def test_codec_signal(): fs = 1000 peak = LowShelf(fs, 30, 1, 10, count=2).get_transfer_function().get_magnitude() avg = LowShelf(fs, 30, 1, 10).get_transfer_function().get_magnitude() median = LowShelf(fs, 30, 1, 10).get_transfer_function().get_magnitude() filt = CompleteFilter() filt.save(HighShelf(fs, 60, 1, 5, count=2)) data = SingleChannelSignalData('test', fs, xy_data=[avg, peak, median], filter=filt, duration_seconds=123456, start_seconds=123, offset=4.2) output = json.dumps(signaldata_to_json(data)) assert output is not None decoded = signaldata_from_json(json.loads(output), None) assert decoded is not None assert isinstance(decoded, SingleChannelSignalData) assert decoded.name == data.name assert decoded.fs == data.fs assert decoded.filter is not None assert type(decoded.filter) is type(data.filter) assert decoded.filter.id != -1 assert decoded.filter.description == data.filter.description assert decoded.filter.filters == data.filter.filters assert decoded.current_unfiltered is not None assert len(decoded.current_unfiltered) == 3 assert decoded.current_unfiltered == data.current_unfiltered assert decoded.duration_hhmmss == data.duration_hhmmss assert decoded.start_hhmmss == data.start_hhmmss assert decoded.end_hhmmss == data.end_hhmmss assert decoded.offset == data.offset
def optimise_filters(filters, fs, to_save): ''' Attempts to optimise the no of filters required. :param filters: the filters to optimise. :param fs: the sigma fs. :param to_save: how many filters we want to save. :return: the optimised filters. ''' unstackable = sorted( [f for f in filters if isinstance(f, Shelf) and f.count > 1], key=lambda f: f.count, reverse=True) unstackable = sorted(unstackable, key=lambda f: f.gain * f.count, reverse=True) weights = [abs(w.gain * w.count) for w in unstackable] total_weight = sum(weights) allocated = [] for idx, weight in enumerate(weights): weight = float(weight) p = weight / total_weight max_amount = unstackable[idx].count - 1 distributed_amount = min(round(p * (to_save - sum(allocated))), max_amount) total_weight -= weight allocated.append(distributed_amount) new_filts = [f for f in filters if not isinstance(f, Shelf) or f.count < 2] for idx, s in enumerate(unstackable): reduce_by = allocated[idx] if reduce_by > 0: total_gain = s.gain * s.count new_count = s.count - reduce_by if new_count > 0: new_gain = total_gain / new_count tmp_shelf = LowShelf(fs, s.freq, s.q, new_gain, count=new_count) average_s = (tmp_shelf.q_to_s() + s.q_to_s()) / 2 new_shelf = LowShelf(fs, s.freq, s_to_q(average_s, new_gain), new_gain, count=new_count) logger.info(f"Replacing {s} with {new_shelf}") new_filts.append(new_shelf) else: raise ValueError( f"Attempted to reduce shelf count to 0 from {s.count}") else: new_filts.append(s) return new_filts
def test_codec_StackedLowShelf(): filter = LowShelf(48000, 20, 1.5, 2.5, count=5) output = json.dumps(filter.to_json()) assert output == '{"_type": "LowShelf", "fs": 48000, "fc": 20.0, "q": 1.5, "gain": 2.5, "count": 5}' decoded = filter_from_json(json.loads(output)) assert decoded is not None assert isinstance(decoded, LowShelf) assert filter.fs == decoded.fs assert filter.q == decoded.q assert filter.gain == decoded.gain assert filter.freq == decoded.freq assert filter.count == decoded.count assert decoded.get_transfer_function() is not None
def create_shaping_filter(self): ''' Creates a filter of the specified type. :return: the filter. ''' filt = None if self.filterType.currentText() == 'Low Shelf': filt = LowShelf(self.__signal.fs, self.freq.value(), self.filterQ.value(), self.filterGain.value(), self.filterCount.value()) elif self.filterType.currentText() == 'High Shelf': filt = HighShelf(self.__signal.fs, self.freq.value(), self.filterQ.value(), self.filterGain.value(), self.filterCount.value()) elif self.filterType.currentText() == 'PEQ': filt = PeakingEQ(self.__signal.fs, self.freq.value(), self.filterQ.value(), self.filterGain.value()) elif self.filterType.currentText() == 'Gain': filt = Gain(self.__signal.fs, self.filterGain.value()) elif self.filterType.currentText() == 'Variable Q LPF': filt = SecondOrder_LowPass(self.__signal.fs, self.freq.value(), self.filterQ.value()) elif self.filterType.currentText() == 'Variable Q HPF': filt = SecondOrder_HighPass(self.__signal.fs, self.freq.value(), self.filterQ.value()) if filt is None: raise ValueError( f"Unknown filter type {self.filterType.currentText()}") else: filt.id = self.__selected_id return filt
def xml_to_filt(file, fs=1000, unroll=False): ''' Extracts a set of filters from the provided minidsp file ''' from model.iir import PeakingEQ, LowShelf, HighShelf filts = __extract_filters(file) output = [] for filt_tup, count in filts.items(): filt_dict = dict(filt_tup) if filt_dict['type'] == 'SL': for i in range(0, count if unroll is True else 1): filt = LowShelf(fs, float(filt_dict['freq']), float(filt_dict['q']), float(filt_dict['boost']), count=1 if unroll is True else count) output.append(filt) elif filt_dict['type'] == 'SH': for i in range(0, count if unroll is True else 1): filt = HighShelf(fs, float(filt_dict['freq']), float(filt_dict['q']), float(filt_dict['boost']), count=1 if unroll is True else count) output.append(filt) elif filt_dict['type'] == 'PK': for i in range(0, count): filt = PeakingEQ(fs, float(filt_dict['freq']), float(filt_dict['q']), float(filt_dict['boost'])) output.append(filt) else: logger.info(f"Ignoring unknown filter type {filt_dict}") return output
def __make_default_filter(self): ''' Creates a new filter using the default preferences. ''' return LowShelf(self.__signal.fs, self.__preferences.get(FILTERS_DEFAULT_FREQ), self.__preferences.get(FILTERS_DEFAULT_Q), 0.0, f_id=uuid4())
def test_codec_CompleteFilter(): filter = CompleteFilter(filters=[PeakingEQ(1000, 50, 3.2, -5), LowShelf(1000, 25, 1, 3.2, count=3), ComplexHighPass(FilterType.BUTTERWORTH, 6, 1000, 12)], description='Hello from me') output = json.dumps(filter.to_json()) expected = '{"_type": "CompleteFilter", "description": "Hello from me", "fs": 1000, "filters": [' \ '{"_type": "ComplexHighPass", "filter_type": "BW", "order": 6, "fs": 1000, "fc": 12.0}, ' \ '{"_type": "LowShelf", "fs": 1000, "fc": 25.0, "q": 1.0, "gain": 3.2, "count": 3}, ' \ '{"_type": "PeakingEQ", "fs": 1000, "fc": 50.0, "q": 3.2, "gain": -5.0}' \ ']}' assert output == expected decoded = filter_from_json(json.loads(output)) assert decoded is not None assert isinstance(decoded, CompleteFilter) assert decoded.description == 'Hello from me' assert decoded.filters is not None assert len(decoded.filters) == len(filter.filters) assert decoded.getTransferFunction() is not None assert isinstance(decoded.filters[0], filter.filters[0].__class__) assert filter.filters[0].fs == decoded.filters[0].fs assert filter.filters[0].type == decoded.filters[0].type assert filter.filters[0].order == decoded.filters[0].order assert filter.filters[0].freq == decoded.filters[0].freq assert isinstance(decoded.filters[1], filter.filters[1].__class__) assert filter.filters[1].fs == decoded.filters[1].fs assert filter.filters[1].q == decoded.filters[1].q assert filter.filters[1].gain == decoded.filters[1].gain assert filter.filters[1].freq == decoded.filters[1].freq assert filter.filters[1].count == decoded.filters[1].count assert isinstance(decoded.filters[2], filter.filters[2].__class__) assert filter.filters[2].fs == decoded.filters[2].fs assert filter.filters[2].q == decoded.filters[2].q assert filter.filters[2].gain == decoded.filters[2].gain assert filter.filters[2].freq == decoded.filters[2].freq
def __convert_to_filter(filter_params, id): ft = int(filter_params['FilterType']) if SyncHTP1Dialog.__has_filter_type(filter_params) else 0 if ft == 0: return PeakingEQ(HTP1_FS, filter_params['Fc'], filter_params['Q'], filter_params['gaindB'], f_id=id) elif ft == 1: return LowShelf(HTP1_FS, filter_params['Fc'], filter_params['Q'], filter_params['gaindB'], f_id=id) elif ft == 2: return HighShelf(HTP1_FS, filter_params['Fc'], filter_params['Q'], filter_params['gaindB'], f_id=id)
def filter_from_json(o): ''' Converts a dict (parsed from json) to a filter. :param o: the dict. :return: the filter. ''' from model.iir import Passthrough, PeakingEQ, LowShelf, HighShelf, FirstOrder_LowPass, \ FirstOrder_HighPass, SecondOrder_LowPass, SecondOrder_HighPass, AllPass, CompleteFilter, ComplexLowPass, \ FilterType, ComplexHighPass filt = None if '_type' not in o: raise ValueError(f"{o} is not a filter") if o['_type'] == Passthrough.__name__: if 'fs' in o: filt = Passthrough(fs=int(o['fs'])) else: filt = Passthrough() elif o['_type'] == Gain.__name__: filt = Gain(o['fs'], o['gain']) elif o['_type'] == PeakingEQ.__name__: filt = PeakingEQ(o['fs'], o['fc'], o['q'], o['gain']) elif o['_type'] == LowShelf.__name__: filt = LowShelf(o['fs'], o['fc'], o['q'], o['gain'], o['count']) elif o['_type'] == HighShelf.__name__: filt = HighShelf(o['fs'], o['fc'], o['q'], o['gain'], o['count']) elif o['_type'] == FirstOrder_LowPass.__name__: filt = FirstOrder_LowPass(o['fs'], o['fc'], o['q']) elif o['_type'] == FirstOrder_HighPass.__name__: filt = FirstOrder_HighPass(o['fs'], o['fc'], o['q']) elif o['_type'] == SecondOrder_LowPass.__name__: filt = SecondOrder_LowPass(o['fs'], o['fc'], o['q']) elif o['_type'] == SecondOrder_HighPass.__name__: filt = SecondOrder_HighPass(o['fs'], o['fc'], o['q']) elif o['_type'] == AllPass.__name__: filt = AllPass(o['fs'], o['fc'], o['q']) elif o['_type'] == CompleteFilter.__name__: kwargs = {} if 'fs' in o: kwargs['fs'] = o['fs'] filt = CompleteFilter( filters=[filter_from_json(x) for x in o['filters']], description=o['description'], **kwargs) elif o['_type'] == ComplexLowPass.__name__: filt = ComplexLowPass(FilterType(o['filter_type']), o['order'], o['fs'], o['fc']) elif o['_type'] == ComplexHighPass.__name__: filt = ComplexHighPass(FilterType(o['filter_type']), o['order'], o['fs'], o['fc']) if filt is None: raise ValueError(f"{o._type} is an unknown filter type") else: if filt.id == -1: filt.id = uuid4() return filt