def log_weightingfilter(stop_freq=20000.0, branches=5, input=sumpf.Signal(), amplify=True): ip_prp = sumpf.modules.ChannelDataProperties() ip_prp.SetSignal(input) frequencies = [ stop_freq, ] * branches filter_spec = [] for i, freq in enumerate(frequencies): alpha_filter = sumpf.modules.WeightingFilterGenerator( weighting=sumpf.modules.WeightingFilterGenerator.A, resolution=ip_prp.GetResolution(), length=ip_prp.GetSpectrumLength()) alpha_filter.SetMaximumFrequency(frequency=freq) spec = alpha_filter.GetSpectrum() if amplify is True: amp = 1.0 / (i + 1) spec = sumpf.modules.AmplifySpectrum(input=spec, factor=amp).GetOutput() kernel = sumpf.modules.InverseFourierTransform(spec).GetSignal() kernel = sumpf.Signal(channels=kernel.GetChannels(), samplingrate=input.GetSamplingRate(), labels=kernel.GetLabels()) filter_spec.append(kernel) # filter_spec = [i for i in reversed(filter_spec)] return filter_spec
def test_merge_signals_manually(): """Tests the merging behavior with manually generated signals.""" signal1 = sumpf.Signal(channels=numpy.array([(1.1, 1.2, 1.3)]), sampling_rate=1.0, offset=1, labels=("s1c1",)) signal2 = sumpf.Signal(channels=numpy.array([(2.1, 2.2, 2.3, 2.4), (3.1, 3.2, 3.3, 3.4)]), sampling_rate=2.0, offset=-4, labels=("s2c1", "s2c2")) signal12 = sumpf.Signal(channels=numpy.array([(0.0, 0.0, 0.0, 0.0, 0.0, 1.1, 1.2, 1.3), (2.1, 2.2, 2.3, 2.4, 0.0, 0.0, 0.0, 0.0), (3.1, 3.2, 3.3, 3.4, 0.0, 0.0, 0.0, 0.0)]), sampling_rate=1.0, offset=-4, labels=("s1c1", "s2c1", "s2c2")) signal21 = sumpf.Signal(channels=numpy.array([(2.1, 2.2, 2.3, 2.4, 0.0, 0.0, 0.0, 0.0), (3.1, 3.2, 3.3, 3.4, 0.0, 0.0, 0.0, 0.0), (0.0, 0.0, 0.0, 0.0, 0.0, 1.1, 1.2, 1.3)]), sampling_rate=2.0, offset=-4, labels=("s2c1", "s2c2", "s1c1")) signal21c = sumpf.Signal(channels=numpy.array([(2.1, 2.2, 2.3, 2.4, 0.0, 0.0, 0.0, 0.0), (0.0, 0.0, 0.0, 0.0, 0.0, 1.1, 1.2, 1.3), (3.1, 3.2, 3.3, 3.4, 0.0, 0.0, 0.0, 0.0)]), sampling_rate=2.0, offset=-4, labels=("s2c1", "s1c1", "s2c2")) FIRST_CHANNELS_FIRST = sumpf.Merge.modes.FIRST_CHANNELS_FIRST assert sumpf.Merge([signal1, signal2]).output() == signal12 assert sumpf.Merge([signal2, signal1]).output() == signal21 assert sumpf.Merge([signal1, signal2], mode=FIRST_CHANNELS_FIRST).output() == signal12 assert sumpf.Merge([signal2, signal1], mode=FIRST_CHANNELS_FIRST).output() == signal21c
def GetHarmonicImpulseResponse(self): """ Get the harmonic impuse response. :return: the harmonic impulse response """ # stable sweep_rate = self.__sweep_generator.GetSweepExcitationRate() harmonic_start_time = self.__sweep_duration - (math.log(self.__harmonic_order) * sweep_rate) harmonic_start_sample = sumpf.modules.DurationToLength(duration=harmonic_start_time, samplingrate=self.__impulse_response.GetSamplingRate(), even_length=False).GetLength() harmonic_stop_sample = len(self.__impulse_response) if self.__harmonic_order > 2: harmonic_stop_time = self.__sweep_duration - (math.log(self.__harmonic_order - 1) * sweep_rate) harmonic_stop_sample = sumpf.modules.DurationToLength(duration=harmonic_stop_time, samplingrate=self.__impulse_response.GetSamplingRate(), even_length=False).GetLength() # prepare the labels labels = [] affix = " (%s harmonic)" % sumpf.helper.counting_number(self.__harmonic_order) for l in self.__impulse_response.GetLabels(): if l is None: labels.append("Impulse Response" + affix) else: labels.append(l + affix) # crop to the impulse response of the wanted harmonic cropped = self.__impulse_response[harmonic_start_sample:harmonic_stop_sample] harmonic = sumpf.Signal(channels=cropped.GetChannels(), samplingrate=cropped.GetSamplingRate(), labels=tuple(labels)) if len(harmonic) % 2 != 0: harmonic = sumpf.Signal(channels=tuple([c + (0.0,) for c in harmonic.GetChannels()]), samplingrate=harmonic.GetSamplingRate(), labels=harmonic.GetLabels()) return harmonic
def _concatenate_signals(signals): """A simple but inefficient implementation, that concatenates signals by adding them.""" # test for the corner cases of zero or one signal if not signals: raise RuntimeError("Nothing to concatenate") if len(signals) == 1: return signals[0] # add the signals sum_ = signals[0] index = signals[0].length() + signals[0].offset() for s in signals[1:]: # fill missing channels with zeros if len(s) < len(sum_): new_channels = numpy.zeros(shape=(len(sum_), s.length())) new_channels[0:len(s)] = s.channels() s = sumpf.Signal(channels=new_channels, offset=s.offset()) elif len(sum_) < len(s): new_channels = numpy.zeros(shape=(len(s), sum_.length())) new_channels[0:len(sum_)] = sum_.channels() sum_ = sumpf.Signal(channels=new_channels, offset=sum_.offset()) sum_ += s.shift(index) index += s.length() + s.offset() # return a signal with the correct labels return sumpf.Signal(channels=sum_.channels(), sampling_rate=signals[0].sampling_rate(), offset=sum_.offset(), labels=tuple( tuple(f"Concatenation {i}" for i in range(1, len(sum_) + 1))))
def test_manually_generated_signals(): """Tests the concatenation behavior with manually generated signals.""" signal1 = sumpf.Signal(channels=numpy.array([(1.1, 1.2, 1.3)]), sampling_rate=1.0, offset=1, labels=("s1c1", )) signal2 = sumpf.Signal(channels=numpy.array([(2.1, 2.2, 2.3, 2.4), (3.1, 3.2, 3.3, 3.4)]), sampling_rate=2.0, offset=-4, labels=("s2c1", "s2c2")) signal12 = sumpf.Signal(channels=numpy.array([(2.1, 3.3, 3.5, 3.7), (3.1, 3.2, 3.3, 3.4)]), sampling_rate=1.0, offset=0, labels=("Concatenation 1", "Concatenation 2")) signal21 = sumpf.Signal(channels=numpy.array([ (2.1, 2.2, 2.3, 2.4, 0.0, 1.1, 1.2, 1.3), (3.1, 3.2, 3.3, 3.4, 0.0, 0.0, 0.0, 0.0) ]), sampling_rate=2.0, offset=-4, labels=("Concatenation 1", "Concatenation 2")) assert tests.compare_signals_approx( _concatenate_signals([signal1, signal2]), signal12) assert tests.compare_signals_approx( _concatenate_signals([signal2, signal1]), signal21) assert tests.compare_signals_approx( sumpf.Concatenate([signal1, signal2]).output(), signal12) assert tests.compare_signals_approx( sumpf.Concatenate([signal2, signal1]).output(), signal21)
def from_rows(time_column, data_rows, labels): """Deserializes a signal from tabular data. :param time_column: a vector with time values, that correspond to the rows in the data_rows matrix with the same index. :param data_rows: a matrix, where the rows contain a sample for each channel of the signal. :param labels: the labels for the channels or an empty tuple. :returns: the deserialized signal """ if len(data_rows) and len(data_rows[0]): # pylint: disable=len-as-condition; data_rows can be a NumPy array sorted_time_row = sorted(time_column) minimum_time = sorted_time_row[0] maximum_time = sorted_time_row[-1] if len(sorted_time_row) <= 1: if minimum_time == 0.0: sampling_rate = 48000.0 else: sampling_rate = 1.0 / abs(minimum_time) else: sampling_rate = (len(sorted_time_row) - 1) / (maximum_time - minimum_time) offset = int(round(minimum_time * sampling_rate)) if numpy.array_equal(time_column, sorted_time_row): sorted_data_rows = data_rows else: sorted_data_rows = [[e for _, e in sorted(zip(time_column, data_row))] for data_row in data_rows] channels = allocate_array(shape=numpy.shape(sorted_data_rows)) channels[:] = sorted_data_rows if len(labels) < len(channels): labels = tuple(labels) + ("",) * (len(channels) - len(labels)) elif len(labels) > len(channels): labels = labels[0:len(channels)] return sumpf.Signal(channels=channels, sampling_rate=sampling_rate, offset=offset, labels=labels) else: return sumpf.Signal()
def dot_product(signal1=None, signal2=None): if signal1 is None: signal1 = sumpf.Signal() if signal2 is None: signal2 = sumpf.Signal() product = sumpf.modules.MultiplySignals(signal1=signal1, signal2=signal2).GetOutput() energy_allchannels = [] for c in product.GetChannels(): energy_singlechannel = [] for s in c: energy_singlechannel.append(abs(s)**2) energy_allchannels.append(numpy.sum(energy_singlechannel)) return energy_allchannels
def _GetFilterImpuleResponses(self): """ Get the identified filter impulse responses. :return: the filter impulse responses """ branches = max(self._select_branches) input_wgn = self.GetExcitation() output_wgn = self._system_response hermite_filterkernels = [] decorrelated_inputs = self.__get_decorrelated_inputs( input_signal=input_wgn, branches=branches) for branch in range(branches): mode = sumpf.modules.CorrelateSignals.SPECTRUM input_decorrelated = decorrelated_inputs[branch] variance = sumpf.modules.SignalMean( input_decorrelated * input_decorrelated).GetMean()[0] cross_corr = sumpf.modules.CorrelateSignals( signal1=input_decorrelated, signal2=output_wgn, mode=mode).GetOutput() num = sumpf.modules.FourierTransform(cross_corr).GetSpectrum() den = sumpf.modules.FourierTransform( sumpf.modules.CorrelateSignals( signal1=input_decorrelated, signal2=input_decorrelated, mode=mode).GetOutput()).GetSpectrum() linear = sumpf.modules.Divide(value1=num, value2=den).GetResult() kernel = sumpf.modules.InverseFourierTransform(linear).GetSignal() signal = sumpf.Signal(channels=kernel.GetChannels(), samplingrate=input_wgn.GetSamplingRate(), labels=kernel.GetLabels()) hermite_filterkernels.append(signal) return hermite_filterkernels
def test_channels_manual(): """compares the result of an energy decay curve computation to a manually computed result.""" signal = sumpf.Signal(channels=numpy.array([(1.0, 2.0, 3.0), (0.4, 0.5, 0.6)])) edc = sumpf.EnergyDecayCurve(signal).channels() ref = numpy.array([(14.0, 13.0, 9.0), (0.77, 0.61, 0.36)]) assert (edc == ref).all()
def _compare_merge_signals_first_channel_first(signals, merged): """test if the merged signal's channels are ordered in a way that the first channels of all input signals come first""" sampling_rate = signals[0].sampling_rate() signals = list(signals) c = 0 d = 0 while signals: to_remove = [] for s in signals: if d < len(s): signal = sumpf.Signal(channels=s[d].channels(), sampling_rate=sampling_rate, # take the sampling rate from the first signal offset=s[d].offset(), labels=s[d].labels()) # the merged signal has a label for each channel, which could be empty start = signal.offset() - merged.offset() stop = start + signal.length() assert merged[c, start:stop] == signal c += 1 else: to_remove.append(s) for s in to_remove: signals.remove(s) d += 1 assert c == len(merged)
def _sanitize_offsets(data): """makes sure, that the offsets of the signals and spectrograms are not so large, that the merged signal requires excessive amounts of memory.""" first_offset = data[0].offset() r = random.Random() r.seed(first_offset) # the first signal is returned with its original offset result = [data[0]] # the other signal's offset must not differ from the first signal's offset by more than their length for s in data[1:]: if abs(first_offset - s.offset()) < s.length(): result.append(s) else: if isinstance(s, sumpf.Signal): result.append(sumpf.Signal(channels=s.channels(), sampling_rate=s.sampling_rate(), offset=random.randint(first_offset - s.length(), first_offset + s.length()), labels=s.labels())) else: # s must be a spectrogram result.append(sumpf.Spectrogram(channels=s.channels(), resolution=s.resolution(), sampling_rate=s.sampling_rate(), offset=random.randint(first_offset - s.length(), first_offset + s.length()), labels=s.labels())) return result
def get_nl_harmonics_iden(sweep_generator, response, harmonics): sweep_length = sweep_generator.GetLength() rev = sweep_generator.GetReversedOutput() rev_spec = sumpf.modules.FourierTransform(rev).GetSpectrum() out_spec = sumpf.modules.FourierTransform(response).GetSpectrum() out_spec = out_spec / response.GetSamplingRate() tf = rev_spec * out_spec ir_sweep = sumpf.modules.InverseFourierTransform(tf).GetSignal() ir_sweep_direct = sumpf.modules.CutSignal(signal=ir_sweep, start=0, stop=int(sweep_length / 4)).GetOutput() ir_sweep_direct = nlsp.append_zeros(ir_sweep_direct) ir_sweep_direct = nlsp.relabel(ir_sweep_direct, "Identified Harmonics 1") ir_merger = sumpf.modules.MergeSignals( on_length_conflict=sumpf.modules.MergeSignals.FILL_WITH_ZEROS) ir_merger.AddInput(ir_sweep_direct) for i in range(harmonics - 1): split_harm = nlsp.FindHarmonicImpulseResponse_Novak( impulse_response=ir_sweep, harmonic_order=i + 2, sweep_generator=sweep_generator).GetHarmonicImpulseResponse() split_harm = sumpf.modules.CutSignal( signal=split_harm, stop=len(sweep_generator.GetOutput())).GetOutput() ir_merger.AddInput( sumpf.Signal(channels=split_harm.GetChannels(), samplingrate=ir_sweep.GetSamplingRate(), labels=("Identified Harmonics %r" % (i + 2), ))) tf = sumpf.modules.FourierTransform(ir_merger.GetOutput()).GetSpectrum() return tf
def release_feature1(audio, threshold): thr = pow(10, -threshold / 20) signal = np.reshape(audio, [1, audio.size]) signal = sumpf.Signal(signal, 44100.0) obj = SignalEnvelope(signal) a = obj.GetEnvelope() b = np.array(a.GetChannels()) b = np.reshape(b, b.size) y_top = peakutils.indexes(b, thres=thr, min_dist=100) y_bottom = peakutils.indexes(thr - b, thres=0, min_dist=100) top_label = np.array([y_top, np.zeros(y_top.size)]) bottom_label = np.array([y_bottom, np.ones(y_bottom.size)]) labels = np.concatenate((top_label, bottom_label), axis=1) sorted_labels = np.array(sorted(np.transpose(labels), key=itemgetter(0)), dtype='int') slop = [] for i in range(sorted_labels.size / 4, sorted_labels.size / 2): j = i - 1 if sorted_labels[i, 1] == 0 and sorted_labels[j, 1] == 1: k = sorted_labels[i, 0] - sorted_labels[j, 0] slop.append((b[sorted_labels[i, 0]] - b[sorted_labels[j, 0]]) / k) else: i += 1 j += 1 release_feature_AVR = np.mean(slop) release_feature_VAR = np.var(slop) return release_feature_AVR, release_feature_VAR
def getnl_ir(sweep_generator,output_sweep,branches=5): sweep_length = sweep_generator.GetLength() sweep_start_freq = sweep_generator.GetStartFrequency() sweep_stop_freq = sweep_generator.GetStopFrequency() ip_signal = sweep_generator.GetOutput() # output_sweep = nlsp.append_zeros(output_sweep) rev = sweep_generator.GetReversedOutput() rev_spec = sumpf.modules.FourierTransform(rev).GetSpectrum() out_spec = sumpf.modules.FourierTransform(output_sweep).GetSpectrum() out_spec = out_spec / output_sweep.GetSamplingRate() tf = rev_spec * out_spec ir_sweep = sumpf.modules.InverseFourierTransform(tf).GetSignal() # nlsp.common.plots.plot(ir_sweep) ir_sweep_direct = sumpf.modules.CutSignal(signal=ir_sweep,start=0,stop=int(sweep_length/4)).GetOutput() ir_sweep_direct = nlsp.append_zeros(ir_sweep_direct) ir_merger = sumpf.modules.MergeSignals(on_length_conflict=sumpf.modules.MergeSignals.FILL_WITH_ZEROS) ir_merger.AddInput(ir_sweep_direct) for i in range(branches-1): split_harm = nlsp.FindHarmonicImpulseResponse_Novak(impulse_response=ir_sweep, harmonic_order=i+2, sweep_generator=sweep_generator).GetHarmonicImpulseResponse() split_harm = sumpf.modules.CutSignal(signal=split_harm,stop=len(sweep_generator.GetOutput())).GetOutput() ir_merger.AddInput(sumpf.Signal(channels=split_harm.GetChannels(), samplingrate=ir_sweep.GetSamplingRate(), labels=split_harm.GetLabels())) ir_merger = ir_merger.GetOutput() # nlsp.common.plots.plot(ir_merger) return ir_sweep
def _sanitize_offsets(data): """makes sure, that the offsets of the signals and spectrograms are not so large, that the concatenation requires excessive amounts of memory.""" r = random.Random() r.seed(data[0].offset()) # the first data set is returned with its original offset result = [data[0]] # the other data sets offset must not exceed their length, so the concatenation is at maximum twice as long as the original data sets combined for s in data[1:]: if abs(s.offset()) < s.length(): result.append(s) else: if isinstance(s, sumpf.Signal): result.append( sumpf.Signal(channels=s.channels(), sampling_rate=s.sampling_rate(), offset=random.randint(-s.length(), s.length()), labels=s.labels())) else: result.append( sumpf.Spectrogram(channels=s.channels(), resolution=s.resolution(), sampling_rate=s.sampling_rate(), offset=random.randint( -s.length(), s.length()), labels=s.labels())) return result
def func(channel): signal = sumpf.Signal(channels=(channel, ), samplingrate=48000, labels=("nl", )) clipped = nlsp.sumpf.SoftClipSignal(signal=signal, thresholds=thresholds) return numpy.asarray(clipped.GetOutput().GetChannels()[0])
def miso_identification(input_generator, output_wgn, branches): """ MISO approach of system identification. :param input_generator: the input generator or the input signal :param output_wgn: the response of the nonlinear system :param branches: the number of branches :return: the filter kernels and the nonlinear function of a HGM """ if hasattr(input_generator,"GetOutput"): input_wgn = input_generator.GetOutput() else: input_wgn = input_generator l = [] L = [] signal_matrix, k_matrix, mu_matrix = wgn_hgm_decorrelate(input_wgn,branches) for branch in range(1,branches+1): input_decorrelated = signal_matrix[branch-1] cross_corr = sumpf.modules.CorrelateSignals(signal1=input_decorrelated,signal2=output_wgn,mode=sumpf.modules.CorrelateSignals.SPECTRUM).GetOutput() num = sumpf.modules.FourierTransform(cross_corr).GetSpectrum() den = sumpf.modules.FourierTransform(sumpf.modules.CorrelateSignals(signal1=input_decorrelated, signal2=input_decorrelated,mode=sumpf.modules.CorrelateSignals.SPECTRUM).GetOutput()).GetSpectrum() linear = sumpf.modules.DivideSpectrums(spectrum1=num, spectrum2=den).GetOutput() kernel = sumpf.modules.InverseFourierTransform(linear).GetSignal() signal = sumpf.Signal(channels=kernel.GetChannels(),samplingrate=input_wgn.GetSamplingRate(),labels=kernel.GetLabels()) l.append(signal) L.append(sumpf.modules.FourierTransform(signal).GetSpectrum()) G = [] for row in range(0,branches): A = sumpf.modules.ConstantSpectrumGenerator(value=0.0,resolution=L[0].GetResolution(),length=len(L[0])).GetSpectrum() for column in range(0,branches): temp = sumpf.modules.AmplifySpectrum(input=L[column],factor=k_matrix[row][column]).GetOutput() A = A + temp G.append(sumpf.modules.InverseFourierTransform(A + mu_matrix[row]).GetSignal()) nl_func = nlsp.nl_branches(nlsp.function_factory.power_series,branches) return G,nl_func
def test_output_ports(): """Tests if the output ports of the :class:`~sumpf.Jack` instances are created from the labels of their input signal. """ with _create_client() as client: xruns = _XRunHandler() jack = sumpf.Jack("CUT") # Client Under Test jack.xruns.connect(xruns.xrun) # check the output port for the empty default input signal assert ["CUT:output_1"] == [ p.name for p in client.get_ports(is_output=True) if p.name.startswith("CUT:") ] # check adding and renaming output ports jack.input( sumpf.MergeSignals([sumpf.BetaNoise(), sumpf.SquareWave()]).output()) assert ["CUT:Beta noise", "CUT:Square wave"] == [p.name for p in client.get_ports(is_output=True) if p.name.startswith("CUT:")] # pylint: disable=line-too-long # check removing and renaming output ports jack.input(sumpf.ExponentialSweep()) assert ["CUT:Sweep"] == [ p.name for p in client.get_ports(is_output=True) if p.name.startswith("CUT:") ] # check generating port names from a signal with crooked labels jack.input( sumpf.Signal(channels=numpy.eye(3), labels=(None, "output_1")) ) # one label None, one label already exists as port name and one label is missing assert ["CUT:output_1", "CUT:output_2", "CUT:output_3"] == [p.name for p in client.get_ports(is_output=True) if p.name.startswith("CUT:")] # pylint: disable=line-too-long assert xruns.xruns == []
def GetReversedOutput(self, numberofsamples=None): """ Get the reversed output sine sweep signal. :param numberofsamples: number of samples of the reversed sine sweep signal """ numpy.seterr(all='ignore') if numberofsamples is None: length = self.GetLength() else: length = numberofsamples sampling_rate = self.GetOutput().GetSamplingRate() sweep_parameter = self.GetSweepExcitationRate() # fft_len = int(2**numpy.ceil(numpy.log2(length))) fft_len = int(length) interval = numpy.linspace(0, sampling_rate / 2.0, num=fft_len / 2 + 1.0) inverse_sweep = 2 * numpy.sqrt(interval / sweep_parameter) * numpy.exp( 1j * (2 * numpy.pi * sweep_parameter * interval * (self.GetStartFrequency() / interval + numpy.log( interval / self.GetStartFrequency()) - 1) + numpy.pi / 4)) inverse_sweep[0] = 0j rev_sweep = numpy.fft.irfft(inverse_sweep) rev_sweep = sumpf.Signal(channels=(rev_sweep, ), samplingrate=sampling_rate, labels=("Reversed Sweep signal", )) rev_sweep = sumpf.modules.Multiply( value1=rev_sweep, value2=1.0 / self.GetAmplitudeRange()).GetResult() numpy.seterr(all='warn') return rev_sweep
def GetOutput(self): """ Get the output sine sweep signal. :return: the output sine sweep signal """ t = numpy.arange(0, self.GetLength() / self.__sampling_rate, 1 / self.__sampling_rate) s = numpy.sin(2 * numpy.pi * self.__start_frequency * self.GetSweepExcitationRate() * (numpy.exp(t / self.GetSweepExcitationRate()) - 1)) if self.__fade_in > 0: s[0:self.__fade_in] = s[0:self.__fade_in] * ((-numpy.cos( numpy.arange(self.__fade_in) / self.__fade_in * numpy.pi) + 1) / 2) if self.__fade_out > 0: s[-self.__fade_out:] = s[-self.__fade_out:] * ((numpy.cos( numpy.arange(self.__fade_out) / self.__fade_out * numpy.pi) + 1) / 2) ip_signal = sumpf.Signal(channels=(s, ), samplingrate=self.__sampling_rate, labels=("Sweep signal", )) if len(ip_signal) % 2 != 0: ip_signal = sumpf.modules.CutSignal(ip_signal, start=0, stop=-1).GetOutput() ip_signal = self.GetAmplitudeRange() * ip_signal return ip_signal
def get_window(window, overlap, symmetric=True, sampling_rate=48000.0): """Convenience method for defining a window function * if window is an integer, a window function with that length will be generated. * if overlap is zero, the generated window will be a rectangular window. * otherwise, a Hann window will be generated. * if window is a :func:`numpy.array`, it will be wrapped in a :class:`~sumpf.Signal`. * if window is iterable, it will be converted to a :func:`numpy.array` and then wrapped in a :class:`~sumpf.Signal`. * otherwise, it will be returned as it is. :param window: an integer window length or a window signal :param overlap: the overlap in the application of the window function as an integer or a float :param symmetric: True, if the window's last sample shall be the same as its first sample. False, if the window's last sample shall be the same as its second sample. The latter is often beneficial in segmentation applications, as it makes it easier to meet the "constant overlap add"-constraint. :param sampling_rate: optional, specifies the sampling rate if a window is generated :returns: a :class:`~sumpf.Signal` instance """ if isinstance(window, int): if overlap == 0: return sumpf.RectangularWindow(sampling_rate=sampling_rate, length=window, symmetric=symmetric) else: return sumpf.HannWindow(sampling_rate=sampling_rate, length=window, symmetric=symmetric) elif isinstance(window, numpy.ndarray): if len(window.shape) == 1: return sumpf.Signal(channels=numpy.array([window]), sampling_rate=sampling_rate, labels=("Window", )) elif len(window.shape) == 2: return sumpf.Signal(channels=window, sampling_rate=sampling_rate, labels=("Window", ) * len(window)) else: raise ValueError( f"Array of shape {window.shape} cannot be wrapped in a Signal") elif isinstance(window, collections.abc.Iterable): return get_window(window=numpy.array(window), overlap=overlap, sampling_rate=sampling_rate) else: return window
def GetOutput(self): new_channels = [] for c in self.__signal.GetChannels(): self.__dummy = c new_channels.append(tuple(self.__nonlin_func((c)))) return sumpf.Signal(channels=new_channels, samplingrate=self.__signal.GetSamplingRate(), labels=self.__signal.GetLabels())
def _GetFilterImpuleResponses(self): """ Get the identified filter impulse responses. :return: the filter impulse responses """ branches = max(self._select_branches) sweep_length = self.__excitation_generator.GetLength() rev = self.__excitation_generator.GetReversedOutput() rev_spec = sumpf.modules.FourierTransform(rev).GetSpectrum() out_spec = sumpf.modules.FourierTransform(self._system_response).GetSpectrum() out_spec = out_spec / self._system_response.GetSamplingRate() tf = rev_spec * out_spec ir_sweep = sumpf.modules.InverseFourierTransform(tf).GetSignal() ir_sweep_direct = sumpf.modules.CutSignal(signal=ir_sweep, start=0, stop=int(sweep_length / 4)).GetOutput() ir_merger = sumpf.modules.MergeSignals(on_length_conflict=sumpf.modules.MergeSignals.FILL_WITH_ZEROS) ir_merger.AddInput(ir_sweep_direct) for i in range(branches - 1): split_harm = nlsp.common.FindHarmonicImpulseResponse_NovakSweep(impulse_response=ir_sweep, harmonic_order=i + 2, sweep_generator=self.__excitation_generator).GetHarmonicImpulseResponse() split_harm = sumpf.modules.CutSignal(signal=split_harm, stop=len(self.__excitation_generator.GetOutput())).GetOutput() ir_merger.AddInput(sumpf.Signal(channels=split_harm.GetChannels(), samplingrate=ir_sweep.GetSamplingRate(), labels=split_harm.GetLabels())) ir_merger = ir_merger.GetOutput() n = len(ir_merger.GetChannels()) // branches items = range(len(ir_merger.GetChannels())) clubbed = [a for a in zip(*[iter(items)] * n)] ir_harmonics = [] for clubb in clubbed: ir_harmonics.append(sumpf.modules.SplitSignal(data=ir_merger, channels=clubb).GetOutput()) filter_kernels = [] for branch in self._select_branches: if self._filter_length is not None: filter_kernels.append( nlsp.common.helper_functions_private.change_length_signal(signal=ir_harmonics[branch - 1], length=self._filter_length)) else: filter_kernels.append(ir_harmonics[branch - 1]) filters = [] for filt in filter_kernels: filters.append(sumpf.Signal(channels=filt.GetChannels(), samplingrate=ir_sweep.GetSamplingRate(), labels=filt.GetLabels())) return filter_kernels
def absolute(inputfreqspectrum): channels = [] for c in inputfreqspectrum.GetChannels(): channel = [] for s in c: channel.append(abs(s)) channels.append(tuple(channel)) return sumpf.Signal(channels=tuple(channels), labels=inputfreqspectrum.GetLabels())
def __init__(self, input_signal=None, nonlinear_functions=(nlsp.function_factory.power_series(1),), filter_irs=None, max_harmonics=None, filterfunction=sumpf.modules.FilterGenerator.BUTTERWORTH(order=20), attenuation=0.0001): """ :param signal: the input signal :param nonlinear_functions: the tuple of nonlinear functions eg. (nlsp.function_factory.power_series(1),...) :param filter_irs: the tuple of filter impulse responses eg. (IR1,...) :param max_harmonics: the tuple of maximum harmonics eg. (1,...) :param filterfunction: the type of filter used for lowpass operation eg. sumpf.modules.FilterGenerator.BUTTERWORTH(order=20) :param attenuation: the attenuation required at the cutoff frequency eg. 0.001 :return: """ if input_signal is None: self.__signal = sumpf.Signal() else: self.__signal = input_signal self.inputstage = sumpf.modules.AmplifySignal(input=self.__signal) self.__nlfunctions = nonlinear_functions if filter_irs is None: self.__filter_irs = (sumpf.modules.ImpulseGenerator(length=len(input_signal)).GetSignal(),) else: self.__filter_irs = filter_irs self.__filterfunction = filterfunction self.__attenuation = attenuation if len(self.__nlfunctions) == len(self.__filter_irs): self.__branches = len(self.__nlfunctions) else: print "the given arguments dont have same length" if max_harmonics is None: self.__max_harmonics = range(1,self.__branches+1) else: self.__max_harmonics = max_harmonics self.hmodels = [] self.__sums = [None] * self.__branches for nl,ir,mh in zip(self.__nlfunctions,self.__filter_irs,self.__max_harmonics): h = nlsp.AliasingCompensatedHM_lowpass(input_signal=self.inputstage.GetOutput(), nonlin_func=nl, max_harm=mh, filter_impulseresponse=ir, filterfunction=self.__filterfunction, attenuation=attenuation) self.hmodels.append(h) for i in reversed(range(len(self.hmodels)-1)): self.__a = sumpf.modules.AddSignals() # print "connecting hammerstein model %i to adder %i" % (i, i) sumpf.connect(self.hmodels[i].GetOutput, self.__a.SetInput1) if i == len(self.hmodels)-2: # print "connecting hammerstein model %i to adder %i" % (i+1, i) sumpf.connect(self.hmodels[i+1].GetOutput, self.__a.SetInput2) else: # print "connecting adder %i to adder %i" % (i+1, i) sumpf.connect(self.__sums[i+1].GetOutput, self.__a.SetInput2) self.__sums[i] = self.__a self.GetOutput = self.__sums[0].GetOutput
def __init__(self, input_signal=None, desired_output=None, filter_length=None, initialcoefficients=None, step_size=None, leakage=None, iteration_cycle=None): """ :param input_signal: the input signal :type input_signal: sumpf.Signal() :param desired_output: the desired output signal :type desired_output: sumpf.Signal() :param filter_length: the filter length :type filter_length: int :param initialcoefficients: the initial coefficients :type initialcoefficients: sumpf.Signal() :param step_size: the step size :type step_size: float :param leakage: the leakage value :type leakage: Eg, 0-no leakage, <1-leaky filter design, >2-error :param iteration_cycle: the iteration cycles, multiple iteration cycles results in over adaptation :type iteration_cycle: int """ if input_signal is None: self._input_signal = sumpf.Signal() else: self._input_signal = input_signal if desired_output is None: self._desired_output = sumpf.Signal() else: self._desired_output = desired_output if filter_length is None: self._filter_length = 2 ** 10 else: self._filter_length = filter_length self._initial_coeff = initialcoefficients if leakage is None: self._leakage = 0 else: self._leakage = leakage if iteration_cycle is None: self._iteration_cycle = 1 else: self._iteration_cycle = iteration_cycle if step_size is None: self._step_size = 0.1 else: self._step_size = step_size
def __init__(self, input_signal1=None, input_signal2=None): """ :param input_signal1: the first input signal :param input_signal2: the second input signal """ # Get the input parameters if input_signal1 is None: self.__input_signal1 = sumpf.Signal() else: self.__input_signal1 = input_signal1 if input_signal2 is None: self.__input_signal2 = sumpf.Signal() else: self.__input_signal2 = input_signal2 self.__output_signal1 = self.__input_signal1 self.__output_signal2 = self.__input_signal2 self._changelength()
def inverse_fourier_transform(self): """Computes the channel-wise inverse Fourier transform of this spectrum. :returns: a :class:`~sumpf.Signal` instance """ if self._length == 0: return sumpf.Signal(channels=numpy.empty(shape=(len(self), 0)), sampling_rate=0.0, offset=0, labels=self._labels) length = max(1, (self._length - 1) * 2) sampling_rate = self.__resolution * length channels = sumpf_internal.allocate_array(shape=(len(self._channels), length)) channels[:, :] = numpy.fft.irfft(self._channels, n=length) return sumpf.Signal(channels=channels, sampling_rate=sampling_rate, offset=0, labels=self._labels)
def GetOutput(self): t = numpy.arange(0,self.GetLength()/self.__sampling_rate,1/self.__sampling_rate) s = numpy.sin(2*numpy.pi*self.__start_frequency*self.GetSweepParameter()*(numpy.exp(t/self.GetSweepParameter())-1)) if self.__fade_in > 0: s[0:self.__fade_in] = s[0:self.__fade_in] * ((-numpy.cos(numpy.arange(self.__fade_in)/self.__fade_in*math.pi)+1) / 2) if self.__fade_out > 0: s[-self.__fade_out:] = s[-self.__fade_out:] * ((numpy.cos(numpy.arange(self.__fade_out)/self.__fade_out*numpy.pi)+1) / 2) signal = sumpf.Signal(channels=(s,),samplingrate=self.__sampling_rate,labels=("Sweep signal",)) if len(signal) % 2 != 0: signal = sumpf.modules.CutSignal(signal,start=0,stop=-1).GetOutput() return signal
def from_dict(dictionary): """Deserializes a signal from a dictionary.""" if "channels" in dictionary: channels = allocate_array(shape=numpy.shape(dictionary["channels"])) channels[:, :] = dictionary["channels"] else: channels = numpy.empty(shape=(1, 0)) return sumpf.Signal(channels=channels, sampling_rate=dictionary.get("sampling_rate", 48000.0), offset=dictionary.get("offset", 0), labels=dictionary.get("labels", ()))