def test_spectrum_plot(self): """ Creates a spectrum plot. """ # setup fft fft = sumpf.modules.FourierTransform() sumpf.connect(self.mrg.GetOutput, fft.SetSignal) # setup plot plt = sumpf.modules.SpectrumPlotWindow() sumpf.connect(fft.GetSpectrum, plt.SetSpectrum) # modify plot before showing plt.HideMagnitude() # show window plt.Show() # modify while showing plt.SetXInterval(None) self.assertRaises(RuntimeError, plt.HidePhase) # Attempting to hiding the last shown plot should raise an error plt.ShowGroupDelay() plt.SetMargin(0.4) plt.LinearMagnitude() plt.HidePhase() plt.LogarithmicGroupDelay() plt.ShowContinuousPhase() plt.SetXInterval((10, 22050)) # close Window plt.Close() # collect garbage gc.collect() self.assertEqual(gc.garbage, []) # The plot should not leave any dead objects behind
def test_object_deletion(self): """ Checks that Connectors do not inhibit clean object deletion. """ # deletion without explicit garbage collection gc.collect() rel = sumpf.modules.RelabelSignal() rel.SetSignal(sumpf.Signal()) del rel self.assertEqual(gc.collect(), 0) # sumpf.collect_garbage sumpf.connect(self.obj1.GetValue, self.obj2.SetValue) sumpf.connect(self.obj2.GetText, self.obj1.SetText) sumpf.disconnect_all(self.obj1) gc.collect() current_instance_count = ExampleClass.instance_count sumpf.destroy_connectors(self.obj1) del self.obj1 gc.collect() if ExampleClass.instance_count != current_instance_count - 1: for o in gc.garbage: if isinstance(o, ExampleClass): collected = sumpf.collect_garbage() self.assertIsInstance(collected, int) # sumpf.collect_garbage shall return the integer number of collected items self.assertEqual(gc.garbage, []) # garbage collection should have removed all garbage return self.fail("The object has neither been deleted, nor has it been marked as garbage")
def test_windowed_sine(self): """ Emulates an impulse response by fading out a sine wave with a window function. """ lng = 100 # setup a processing chain that generates example data sin = sumpf.modules.SineWaveGenerator(length=lng) win = sumpf.modules.WindowGenerator(fall_interval=(0, lng // 2), length=lng) mul = sumpf.modules.Multiply() rms = sumpf.modules.RootMeanSquare(integration_time=sumpf.modules.RootMeanSquare.FULL) edc = sumpf.modules.EnergyDecayCurveFromImpulseResponse() dif = sumpf.modules.DifferentiateSignal() sumpf.connect(sin.GetSignal, mul.SetValue1) sumpf.connect(win.GetSignal, mul.SetValue2) sumpf.connect(mul.GetResult, rms.SetInput) sumpf.connect(mul.GetResult, edc.SetImpulseResponse) sumpf.connect(edc.GetEnergyDecayCurve, dif.SetInput) # get the generated example data out = edc.GetEnergyDecayCurve().GetChannels()[0] der = dif.GetOutput().GetChannels()[0] egy = rms.GetOutput().GetChannels()[0][0] ** 2 * lng # do the testing self.assertEqual(max(out[lng // 2:]), 0.0) # all samples after the window should be 0.0 self.assertLessEqual(max(der), 0.0) # the energy decay curve has to be falling monotonely self.assertAlmostEqual(out[0], egy) # the first sample of the energy decay curve should be the whole energy of the impulse response
def test_message(self): tester1 = ProgressTester(progress=(1, 0, "Test"), testcase=self, count_inputs=False) tester2 = ProgressTester(progress=(1, 1, "ProgressTester.NonCachingOutput has just finished"), testcase=self, count_inputs=False) sumpf.connect(tester1.NonCachingOutput, tester2.Input) progress_indicator = sumpf.progressindicators.ProgressIndicator_Outputs(method=tester1.Input, message="Test") tester1.SetProgressIndicator(progress_indicator) tester2.SetProgressIndicator(progress_indicator) tester1.Input(1337)
def setUp(self): frq = 10.0 lng = 4800 self.gen1 = sumpf.modules.SineWaveGenerator(frequency=frq, phase=1.6, samplingrate=4800.0, length=lng) self.gen2 = sumpf.modules.SineWaveGenerator(frequency=frq / 4, phase=0.8, samplingrate=4800.0, length=lng) self.mrg = sumpf.modules.MergeSignals() sumpf.connect(self.gen1.GetSignal, self.mrg.AddInput) sumpf.connect(self.gen2.GetSignal, self.mrg.AddInput)
def __init__(self): self.__input = sumpf.modules.PassThroughSignal() fft = sumpf.modules.FourierTransform() sumpf.connect(self.__input.GetSignal, fft.SetSignal) self.__inversion = sumpf.modules.RegularizedSpectrumInversion() sumpf.connect(fft.GetSpectrum, self.__inversion.SetSpectrum) self.SetSignal = self.__input.SetSignal self.GetInversion = self.__inversion.GetOutput
def test_setting_to_different_connectors(self): for m in ["Input", "Trigger", "MultiInput"]: tester1 = ProgressTester(progress=(3, 0, None), testcase=self) tester2 = ProgressTester(progress=(3, 2, None), testcase=self) sumpf.connect(tester1.CachingOutput, tester2.Input) progress_indicator = sumpf.progressindicators.ProgressIndicator_All(method=getattr(tester1, m)) tester1.SetProgressIndicator(progress_indicator) tester2.SetProgressIndicator(progress_indicator) getattr(tester1, m)(1337)
def test_compare_with_inversion(self): """ Creates a Signal, transforms it, inverses the transformation and tests, if it resembles the original Signal. """ ifft = sumpf.modules.InverseFourierTransform() sumpf.connect(self.fft.GetSpectrum, ifft.SetSpectrum) insignal = self.gen.GetSignal() outsignal = ifft.GetSignal() common.compare_signals_almost_equal(testcase=self, signal1=insignal, signal2=outsignal)
def setUp(self): self.frequency = 1000.0 self.samplingrate = 4800.0 self.length = self.samplingrate self.gen = sumpf.modules.SineWaveGenerator(frequency=self.frequency, phase=0.0, samplingrate=self.samplingrate, length=self.length) self.fft = sumpf.modules.FourierTransform() sumpf.connect(self.gen.GetSignal, self.fft.SetSignal)
def test_double_conjugate(self): """ Tests the conjugation of a conjugation is the original Spectrum. """ spectrum = sumpf.Spectrum(channels=((0.0 + 1.0j, 1.0 - 0.0j), (1 + 2j, 3 - 4j)), resolution=66.6, labels=("two", "channels")) cnj1 = sumpf.modules.ConjugateSpectrum() cnj2 = sumpf.modules.ConjugateSpectrum() sumpf.connect(cnj1.GetOutput, cnj2.SetInput) cnj1.SetInput(spectrum) self.assertEqual(cnj2.GetOutput(), spectrum)
def test_group_delay(self): """ Tests if the method for calculating the group delay works as expected """ gen = sumpf.modules.ImpulseGenerator(delay=0.03, samplingrate=400, length=400) fft = sumpf.modules.FourierTransform() sumpf.connect(gen.GetSignal, fft.SetSignal) spk = fft.GetSpectrum() self.assertAlmostEqual(min(spk.GetGroupDelay()[0]), max(spk.GetGroupDelay()[0])) # the group delay should be constant self.assertAlmostEqual(min(spk.GetGroupDelay()[0]), 0.03) # the group delay should be the same as the delay for the impulse
def ShowRecent(self, show=True): if show: if not self.__showrecent: self.__progress_indicator.AddMethod(self.__merge_utf.AddInput) sumpf.connect(self.__relabel.GetOutput, self.__merge_utf.AddInput) self.__showrecent = True else: if self.__showrecent and self.__kept_ids != []: self.__progress_indicator.AddMethod(self.__merge_utf.AddInput) sumpf.disconnect(self.__relabel.GetOutput, self.__merge_utf.AddInput) self.__showrecent = False
def GetNLOutput(self): """ Gets the output of the nonlinear block of the Hammerstein model. The output of the nonlinear block is downsampled to the original sampling rate. :return: the output of the nonlinear block of the Hammerstein model """ sumpf.connect(self._nonlin_function.GetOutput, self._downnloutput.SetInput) sumpf.connect(self._prp.GetSamplingRate, self._downnloutput.SetSamplingRate) return self._downnloutput.GetOutput()
def test_connections(self): """ tests if calculating the average through connections is possible. """ gen = ConnectionTester() avg = sumpf.modules.AverageSignals() sumpf.connect(gen.GetSignal, avg.AddInput) sumpf.connect(avg.TriggerDataCreation, gen.Start) avg.SetNumber(10) avg.Start() output = avg.GetOutput() self.assertEqual(output.GetSamplingRate(), 42) self.assertEqual(output.GetChannels(), ((4.5, 9.0, 13.5),))
def test_make_invalid_connections(self): """ Tries to make and brake some invalid connections and tests if the mistakes are correctly detected. """ self.assertRaises(TypeError, sumpf.connect, *(self.obj1.GetText, self.obj2.SetValue2)) # connecting should fail if the types of the connectors are different self.assertRaises(TypeError, sumpf.connect, *(self.obj1.GetValue, self.obj2.GetValue)) # connecting should fail if both connectors are outputs self.assertRaises(TypeError, sumpf.connect, *(self.obj1.SetValue, self.obj2.SetValue)) # connecting should fail if both connectors are inputs self.assertRaises(ValueError, sumpf.connect, *(self.obj1.GetValue, self.obj1.SetValue)) # connecting should fail if the output is connected to an input that updates the output automatically, because that would cause an infinite loop sumpf.connect(self.obj1.GetValue, self.obj1.SetValueNoUpdate) self.assertRaises(ValueError, sumpf.connect, *(self.obj1.GetValue, self.obj1.SetValueNoUpdate)) # connecting should fail if the connection already exists self.assertRaises(ValueError, sumpf.connect, *(self.obj1.GetValue2, self.obj1.SetValueNoUpdate)) # connecting should fail if input is already connected self.assertRaises(ValueError, sumpf.disconnect, *(self.obj1.GetValue, self.obj2.SetValue)) # disconnecting should fail if connection does not exist sumpf.disconnect(self.obj1.GetValue, self.obj1.SetValueNoUpdate) self.assertRaises(ValueError, sumpf.disconnect, *(self.obj1.GetValue, self.obj1.SetValueNoUpdate)) # disconnecting should fail if connection does not exist. Even if it has existed before
def test_setter(self): """ Tests if the setter methods raise no errors and notify the GetSignal-connector correctly. """ rec = SignalReceiver() sumpf.connect(self.gen.GetSignal, rec.SetSignal) self.assertTrue(rec.HasReceived()) # checks the notification on initial connection rec.Reset() self.gen.SetSamplingRate(44100) self.assertTrue(rec.HasReceived()) # checks the notification after SetSamplingRate rec.Reset() self.gen.SetLength(20) self.assertTrue(rec.HasReceived()) # checks the notification after SetLength rec.Reset()
def test_setter(self): """ Tests if the setter methods raise no errors and notify the GetSpectrum-connector correctly. """ rec = SpectrumReceiver() sumpf.connect(self.gen.GetSpectrum, rec.SetSpectrum) self.assertTrue(rec.HasReceived()) # Checks the notification on initial connection rec.Reset() self.gen.SetResolution(2400) self.assertTrue(rec.HasReceived()) # Checks the notification after SetResolution rec.Reset() self.gen.SetLength(20) self.assertTrue(rec.HasReceived()) # Checks the notification after SetLength rec.Reset() self.gen.SetMaximumFrequency(20000) self.assertTrue(rec.HasReceived()) # Checks the notification after SetDuration
def test_function(self): """ Runs a simple use case for the progress dialog. """ tester1 = ProgressTester() tester2 = ProgressTester() tester3 = ProgressTester() tester4 = ProgressTester() tester5 = ProgressTester() sumpf.connect(tester1.Output, tester2.Input) sumpf.connect(tester2.Output, tester3.Input) sumpf.connect(tester3.Output, tester4.Input) sumpf.connect(tester4.Output, tester5.Input) indicator = sumpf.progressindicators.ProgressIndicator_All(method=tester1.Input, message="Test") dialog = sumpf.gui.ProgressDialog(message="Not Seen", title="Testing the progress dialog") sumpf.connect(indicator.GetProgressAsTuple, dialog.SetProgress) tester1.Input(0.1)
def test_signal_plot_and_threads(self): """ Creates two signals, plots them and modifies them and the plots. """ # setup plots plt1 = sumpf.modules.SignalPlotWindow() plt2 = sumpf.modules.SignalPlotWindow() sumpf.connect(self.mrg.GetOutput, plt1.SetSignal) sumpf.connect(self.gen1.GetSignal, plt2.SetSignal) # show window plt1.Show() plt2.Show() # wait until windows are initialized while plt1._window is None or plt1._panel is None: time.sleep(0.01) while plt2._window is None or plt2._panel is None: time.sleep(0.01) # change data self.gen1.SetFrequency(5.0) # change plots plt1.HideLegend() plt2.HideGrid() plt1.LogarithmicY() plt2.LogarithmicX() plt1.SetCursors([0.15]) plt1.HideCursors() plt2.HideCursors() plt2.ShowCursors() plt1.ShowCursors() # close windows plt1.Close() plt2.Close() # show window 2 again plt2.Show() # wait until frame is initialized while plt2._window is None: time.sleep(0.01) # close Window plt2.Close() # join windows plt1.Join() plt2.Join() # collect garbage gc.collect() self.assertEqual(gc.garbage, []) # The plot should not leave any dead objects behind
def test_function(self): """ Tests the generator's output. """ resolution = 1.0 length = 6 gen = sumpf.modules.DelayFilterGenerator(delay=0.0, resolution=resolution, length=length) ifft = sumpf.modules.InverseFourierTransform() sumpf.connect(gen.GetSpectrum, ifft.SetSpectrum) for d in range(1, 10): delay = d * 0.1 gen.SetDelay(delay) for i in range(length): self.assertAlmostEqual(gen.GetSpectrum().GetMagnitude()[0][i], 1.0) impulse_response = ifft.GetSignal() channel = impulse_response.GetChannels()[0] max_index = channel.index(max(channel)) index = int(round((delay * impulse_response.GetSamplingRate()))) self.assertEqual(max_index, index)
def test_interactively(self): # setup a SpectrumPlotPanel in a TestQuestionnaire questionnaire = common.TestQuestionnaire(title="Testing SpectrumPlotPanel class") plot = sumpf.modules.SpectrumPlotPanel(parent=questionnaire) questionnaire.SetMainElement(plot) sumpf.connect(self.fft.GetSpectrum, plot.SetSpectrum) questionnaire.Show() # run the tests try: questionnaire.AssertYes(question="Does the plot show the magnitude and phase of two spectrums? (both spectrums plotted together with one plot each for magnitude and phase)", testcase=self) self.properties.SetSamplingRate(4000.0) questionnaire.AssertYes(question="Does the x-axis go to 2kHz now?", testcase=self) plot.HideLegend() questionnaire.AssertYes(question="Has the legend been hidden correctly? (the respective checkbox in the toolbar should be unchecked as well)", testcase=self) plot.HideGrid() questionnaire.AssertYes(question="Has the grid behind all plots been hidden?", testcase=self) plot.SetCursors([100.0, 1400.0]) questionnaire.AssertYes(question="Are there two cursors (vertical lines) in the plot now?", testcase=self) self.copy.SetChannelCount(1) questionnaire.AssertYes(question="Has the green curve disappeared? (the cursors should still be visible)", testcase=self) plot.HidePhase() questionnaire.AssertYes(question="Has the plot for the phase been hidden?", testcase=self) self.copy.SetChannelCount(5) plot.SetLayout(sumpf.modules.SpectrumPlotPanel.LAYOUT_HORIZONTALLY_TILED) plot.ShowContinuousPhase() plot.ShowGroupDelay() questionnaire.AssertYes(question="Does the plot now show five groups of plots in three columns with three plots each and one line per plot?", testcase=self) plot.MovePlotsTogether() questionnaire.AssertYes(question="Please pan or zoom one plot. Do the other plots move accordingly?", testcase=self) self.copy.SetChannelCount(1) plot.LinearX() plot.LinearMagnitude() plot.HideContinuousPhase() plot.LogarithmicGroupDelay() questionnaire.AssertYes(question="Is there now one group of plots with a linear x-axis scale, linearly scaled magnitude and logarithmically scaled group delay?", testcase=self) plot.ShowMajorGrid() plot.SetXInterval((300.0, 3500.0)) questionnaire.AssertYes(question="Does the x axis now span from 300Hz to 3.5kHz?", testcase=self) plot.SetMargin(0.03) questionnaire.AssertYes(question="Has the size of the plots been increased slightly?", testcase=self) finally: questionnaire.Close()
def test_set_multiple_values(self): """ Tests the set_multiple_values function. Most assertions will be don in the SetMultipleValuesTestClass class. """ # test with single Inputs testobject = SetMultipleValuesTestClass(testcase=self) sumpf.connect(testobject.GetState, self.obj1.SetValue) testobject.Start() sumpf.set_multiple_values(pairs=[(testobject.SetValue1, 37.9), (testobject.SetValue2, "Broccoli"), (testobject.TriggerValue3,)]) self.assertEqual(testobject.GetValue1(), 37.9) self.assertEqual(testobject.GetValue2(), "Broccoli") self.assertEqual(testobject.GetValue3(), True) # test with a MultiInput sumpf.set_multiple_values(pairs=[(testobject.AddValue4, 1), (testobject.AddValue4, 2), (testobject.AddValue4, 3)]) self.assertEqual(testobject.GetValue4().GetData(), [1, 2, 3])
def test_deactivate_output(self): """ Tests if deactivating and reactivating outputs works. """ self.obj1.SetValue(0) self.obj2.SetValue(1) sumpf.deactivate_output(self.obj1.GetValue) sumpf.connect(self.obj1.GetValue, self.obj2.SetValue) self.assertEqual(self.obj2.GetValue(), 1) # A deactivated output shall not be passed while creating a connection sumpf.activate_output(self.obj1.GetValue) sumpf.connect(self.obj1.GetText, self.obj2.SetText) self.obj1.ComputeValueAndText(2) sumpf.deactivate_output(self.obj1) sumpf.deactivate_output(self.obj1) # Deactivating already deactivated outputs should not fail self.obj1.ComputeValueAndText(3) self.assertEqual(self.obj2.GetValue(), 2) # No value should be passed through deactivated outputs sumpf.activate_output(self.obj1.GetValue) self.assertEqual(self.obj2.GetValue(), 3) # Value should have been passed through reactivated output self.assertEqual(self.obj2.GetText(), "2") # Text output should have remained deactivated sumpf.activate_output(self.obj1) self.assertEqual(self.obj2.GetText(), "3") # Text should have been passed while globally enabling outputs
def test_replacing_multi_input(self): """ Testing every aspect of a MultiInput is more complex, so it is done in separately in this and the next method. This method tests the MultiInput that replace updated data with a proper replacing method. This should maintain the order of the output data. """ id0 = self.obj2.AddItemReplace(0) id1 = self.obj2.AddItemReplace(1) self.assertEqual(self.obj2.GetItems(), [0, 1]) # adding items manually should work self.obj1.SetValue(2) sumpf.connect(self.obj1.GetValue, self.obj2.AddItemReplace) self.assertEqual(self.obj2.GetItems(), [0, 1, 2]) # adding items through connections should work self.obj1.SetValue(3) self.assertEqual(self.obj2.GetItems(), [0, 1, 3]) # a connection should only update its own value sumpf.connect(self.obj1.GetValue2, self.obj2.AddItemReplace) self.assertEqual(self.obj2.GetItems(), [0, 1, 3, 6]) # multiple connections must be possible sumpf.connect(self.obj2.GetItems, self.obj1.Trigger) self.obj1.triggered = False sumpf.disconnect(self.obj1.GetValue, self.obj2.AddItemReplace) self.assertTrue(self.obj1.triggered) # disconnecting should have triggered the Trigger self.assertEqual(self.obj2.GetItems(), [0, 1, 6]) # disconnecting should remove the item from the list self.obj2.RemoveItem(id1) self.assertEqual(self.obj2.GetItems(), [0, 6]) # removing items manually should work as well self.obj2.AddItemReplace(7) self.obj1.SetValue2(2) self.assertEqual(self.obj2.GetItems(), [0, 4, 7]) # the connection should still work, even after many changes
def test_ProgressIndicator_All(self): tester1 = ProgressTester(progress=(6, 0, None), testcase=self) tester2 = ProgressTester(progress=(6, 1, None), testcase=self) # tester1.Input done sumpf.connect(tester1.CachingOutput, tester2.Trigger) tester3 = ProgressTester(progress=(6, 3, None), testcase=self) # tester2.Trigger & tester2.Output done sumpf.connect(tester2.NonCachingOutput, tester3.MultiInput) tester4 = ProgressTester(progress=(6, 5, None), testcase=self) # tester3.MultiInput & tester3.Output done sumpf.connect(tester3.CachingOutput, tester4.InputNoObserver) progress_indicator = sumpf.progressindicators.ProgressIndicator_All(method=tester1.Input) tester1.SetProgressIndicator(progress_indicator) tester2.SetProgressIndicator(progress_indicator) tester3.SetProgressIndicator(progress_indicator) tester4.SetProgressIndicator(progress_indicator) tester1.Input(1337) self.assertEqual(progress_indicator.GetProgressAsTuple(), (6, 6, None)) # tester4.InputNoObserver done self.assertEqual(progress_indicator.GetProgressAsFloat(), 1.0) self.assertEqual(progress_indicator.GetProgressAsPercentage(), 100) tester1.SetProgress((6, 6, None)) tester2.SetProgress((6, 6, None)) tester3.SetProgress((6, 6, None)) tester1.Input(4711) progress_indicator.Destroy() del tester1 del tester2 del tester3 del tester4 gc.collect() self.assertEqual(gc.garbage, [])
def test_full_integration(self): """ Tests the integration time flag FULL. """ samplingrate = 100.0 gen1 = sumpf.modules.SineWaveGenerator(frequency=5, phase=0.3, samplingrate=samplingrate, length=samplingrate) gen2 = sumpf.modules.ImpulseGenerator(delay=0.1, samplingrate=samplingrate, length=samplingrate) merge = sumpf.modules.MergeSignals() sumpf.connect(gen1.GetSignal, merge.AddInput) sumpf.connect(gen2.GetSignal, merge.AddInput) rms = sumpf.modules.RootMeanSquare(integration_time=sumpf.modules.RootMeanSquare.FULL) sumpf.connect(merge.GetOutput, rms.SetInput) result = rms.GetOutput() self.assertEqual( result.GetSamplingRate(), samplingrate ) # the sampling rate has to be taken from the input Signal self.assertEqual(len(result), samplingrate) # the length has to be the same as the input Signal self.assertEqual( result.GetLabels(), merge.GetOutput().GetLabels() ) # the labels have to be copied from the input Signal self.assertAlmostEqual(result.GetChannels()[0][0], 0.5 ** 0.5) # the RMS value has to be calculated correctly self.assertEqual( result.GetChannels()[1][0], (1.0 / samplingrate) ** 0.5 ) # the RMS value has to be calculated correctly self.assertEqual( min(result.GetChannels()[0]), max(result.GetChannels()[0]) ) # all samples of a channel have to have the same value self.assertEqual( min(result.GetChannels()[1]), max(result.GetChannels()[1]) ) # all samples of a channel have to have the same value
def test_ProgressIndicator_OutputsAndNonObservedInputs(self): tester1 = ProgressTester(progress=(3, 0, None), testcase=self, count_inputs=False, count_nonobserved_inputs=True) tester2 = ProgressTester(progress=(3, 0, None), testcase=self, count_inputs=False, count_nonobserved_inputs=True) sumpf.connect(tester1.CachingOutput, tester2.Trigger) tester3 = ProgressTester(progress=(3, 1, None), testcase=self, count_inputs=False, count_nonobserved_inputs=True) # tester2.Output done sumpf.connect(tester2.NonCachingOutput, tester3.MultiInput) tester4 = ProgressTester(progress=(3, 2, None), testcase=self, count_inputs=False, count_nonobserved_inputs=True) # tester3.Output done sumpf.connect(tester3.CachingOutput, tester4.InputNoObserver) progress_indicator = sumpf.progressindicators.ProgressIndicator_OutputsAndNonObservedInputs(method=tester1.Input) tester1.SetProgressIndicator(progress_indicator) tester2.SetProgressIndicator(progress_indicator) tester3.SetProgressIndicator(progress_indicator) tester4.SetProgressIndicator(progress_indicator) tester1.Input(1337) self.assertEqual(progress_indicator.GetProgressAsTuple(), (3, 3, None)) # tester4.InputNoObserver done self.assertEqual(progress_indicator.GetProgressAsFloat(), 1.0) self.assertEqual(progress_indicator.GetProgressAsPercentage(), 100) tester1.SetProgress((3, 3, None)) tester2.SetProgress((3, 3, None)) tester3.SetProgress((3, 3, None)) tester1.Input(4711) progress_indicator.Destroy() del tester1 del tester2 del tester3 del tester4 gc.collect() self.assertEqual(gc.garbage, [])
def test_order(self): """ Tests if connections are updated in the correct order. """ sumpf.connect(self.obj1.GetValue, self.obj2.SetValue) sumpf.connect(self.obj1.GetValue, self.obj2.SetValue2) sumpf.connect(self.obj1.GetValue, self.obj2.SetValueNoUpdate) self.obj2.order = [] self.obj1.SetValue(1) self.assertEqual(self.obj2.order, ["SetValue", "SetValue2", "SetValueNoUpdate"]) # All items should appear in the correct order sumpf.disconnect(self.obj1.GetValue, self.obj2.SetValue2) sumpf.connect(self.obj1.GetValue, self.obj2.SetValue2) self.obj2.order = [] self.obj1.SetValue(2) self.assertEqual(self.obj2.order, ["SetValue", "SetValueNoUpdate", "SetValue2"]) # All items should appear in the correct order
def test_set_multiple_values(self): """ Tests the set_multiple_values function when a progress_indicator is given. Most assertions will be don in the SetMultipleValuesTestClass and ProgressTester classes. """ # test with single Inputs testobject = SetMultipleValuesTestClass(testcase=self) progress_tester = ProgressTester(progress=(5, 4, "SetMultipleValuesTestClass.GetState has just finished"), testcase=self, count_inputs=False) sumpf.connect(testobject.GetState, progress_tester.Input) testobject.Start() progress_indicator = sumpf.progressindicators.ProgressIndicator_All(message="smv") testobject.SetProgressIndicator(progress_indicator) progress_tester.SetProgressIndicator(progress_indicator) sumpf.set_multiple_values(pairs=[(testobject.SetValue1, 37.9), (testobject.SetValue2, "Broccoli"), (testobject.TriggerValue3,)], progress_indicator=progress_indicator) # test with a MultiInput sumpf.set_multiple_values(pairs=[(testobject.AddValue4, 1), (testobject.AddValue4, 2), (testobject.AddValue4, 3)], progress_indicator=progress_indicator)
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, nonlinear_functions=(nlsp.function_factory.power_series(1), ), filter_irs=None, max_harmonics=None): """ :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,...) """ 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 if len(self.__nlfunctions) == len(self.__filter_irs): self.__branches = len(self.__nlfunctions) else: print "the given arguments dont have same length" self.hmodels = [] self.__sums = [None] * self.__branches for nl, ir in zip(self.__nlfunctions, self.__filter_irs): h = nlsp.HammersteinModel(input_signal=self.inputstage.GetOutput(), nonlin_func=nl, filter_impulseresponse=ir) 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 test_connections(self): """ Tests if the connections work """ tester1 = ConnectionTester() tester2 = ConnectionTester() sumpf.connect(self.merger.GetOutput, tester1.Trigger) sumpf.connect(tester1.GetSpectrum, self.merger.AddInput) self.assertTrue(tester1.triggered) # connecting to input should work and it should trigger the output self.assertEqual(len(self.merger.GetOutput().GetChannels()), 2) # after adding one connection there should be the two channels from result of the connected output in the output spectrum tester1.SetSamplingRate(22050) self.assertEqual(self.merger.GetOutput().GetResolution(), 1.0 / 22050) # changing the resolution of the only spectrum in the merger should be possible tester1.SetSamplingRate(48000) sumpf.connect(tester2.GetSpectrum, self.merger.AddInput) self.assertEqual(len(self.merger.GetOutput().GetChannels()), 4) # after adding a second connection there should be four channels in the output spectrum tester1.ChangeChannels() self.assertEqual(self.merger.GetOutput().GetChannels()[0:2], tester1.GetSpectrum().GetChannels()) # the order of the channels should remain, even if the output of tester1 has changed tester1.triggered = False sumpf.disconnect(tester1.GetSpectrum, self.merger.AddInput) self.assertTrue(tester1.triggered) # disconnecting from input should should trigger the output as well self.assertEqual(len(self.merger.GetOutput().GetChannels()), 2) # after removing one connection there should be one channel left in the output spectrum
def test_derivative(self): """ Compares the derivative of the integral with the original Signal. """ noise = sumpf.modules.NoiseGenerator( distribution=sumpf.modules.NoiseGenerator.RedNoise(), length=900, samplingrate=1000.0 ) noise.Seed(13) cache = ( sumpf.modules.PassThroughSignal() ) # avoid regeneration of the random noise Signal even if caching is turned off sumpf.connect(noise.GetSignal, cache.SetSignal) integral = sumpf.modules.IntegrateSignal() sumpf.connect(cache.GetSignal, integral.SetInput) derivative = sumpf.modules.DifferentiateSignal() sumpf.connect(integral.GetOutput, derivative.SetInput) common.compare_signals_almost_equal( testcase=self, signal1=cache.GetSignal()[1:-1], signal2=derivative.GetOutput()[1:-1], places=12 ) integral.SetOffset(129.874) common.compare_signals_almost_equal( testcase=self, signal1=cache.GetSignal()[1:-1], signal2=derivative.GetOutput()[1:-1], places=10 )
def _Connect(self): sumpf.connect(self._ampsignal.GetOutput,self._nonlin_func.SetInput) sumpf.connect(self._nonlin_func.GetOutput,self._merger.AddInput) sumpf.connect(self._ampfilter.GetOutput,self._merger.AddInput) sumpf.connect(self._merger.GetOutput,self._transform.SetSignal) sumpf.connect(self._transform.GetSpectrum,self._split1ch.SetInput) sumpf.connect(self._transform.GetSpectrum,self._split2ch.SetInput) sumpf.connect(self._split1ch.GetOutput,self._multiply.SetInput1) sumpf.connect(self._split2ch.GetOutput,self._multiply.SetInput2) sumpf.connect(self._multiply.GetOutput,self._itransform.SetSpectrum)
def _ConnectHM(self): """ Connect the components of the Hammerstein Model. """ if self._downsampling_position == 1: sumpf.connect(self.__passsignal.GetSignal, self.__signalaliascomp.SetPreprocessingInput) sumpf.connect(self.__nonlin_function.GetMaximumHarmonics, self.__signalaliascomp.SetMaximumHarmonics) sumpf.connect(self.__signalaliascomp.GetPreprocessingOutput, self.__nonlin_function.SetInput) sumpf.connect(self.__nonlin_function.GetOutput, self.__signalaliascomp.SetPostprocessingInput) sumpf.connect(self.__signalaliascomp.GetPostprocessingOutput, self.__prop_signal.SetSignal) sumpf.connect(self.__signalaliascomp.GetPostprocessingOutput, self.__change_length.SetFirstInput) sumpf.connect(self.__prop_signal.GetSamplingRate, self.__resampler.SetSamplingRate) sumpf.connect(self.__passfilter.GetSignal, self.__resampler.SetInput) sumpf.connect(self.__resampler.GetOutput, self.__change_length.SetSecondInput) sumpf.connect(self.__change_length.GetSecondOutput, self.__transform_filter.SetSignal) sumpf.connect(self.__change_length.GetFirstOutput, self.__transform_signal.SetSignal) sumpf.connect(self.__transform_signal.GetSpectrum, self.__multiplier.SetValue1) sumpf.connect(self.__transform_filter.GetSpectrum, self.__multiplier.SetValue2) sumpf.connect(self.__multiplier.GetResult, self.__itransform.SetSpectrum) sumpf.connect(self.__itransform.GetSignal, self.__passoutput.SetSignal) elif self._downsampling_position == 2: sumpf.connect(self.__passsignal.GetSignal, self.__signalaliascomp.SetPreprocessingInput) sumpf.connect(self.__nonlin_function.GetMaximumHarmonics, self.__signalaliascomp.SetMaximumHarmonics) sumpf.connect(self.__signalaliascomp.GetPreprocessingOutput, self.__nonlin_function.SetInput) sumpf.connect(self.__signalaliascomp._GetAttenuation, self.__attenuator.SetValue1) sumpf.connect(self.__nonlin_function.GetOutput, self.__attenuator.SetValue2) sumpf.connect(self.__attenuator.GetResult, self.__prop_signal.SetSignal) sumpf.connect(self.__attenuator.GetResult, self.__change_length.SetFirstInput) sumpf.connect(self.__prop_signal.GetSamplingRate, self.__resampler.SetSamplingRate) sumpf.connect(self.__passfilter.GetSignal, self.__resampler.SetInput) sumpf.connect(self.__resampler.GetOutput, self.__change_length.SetSecondInput) sumpf.connect(self.__change_length.GetFirstOutput, self.__transform_signal.SetSignal) sumpf.connect(self.__change_length.GetSecondOutput, self.__transform_filter.SetSignal) sumpf.connect(self.__transform_signal.GetSpectrum, self.__multiplier.SetValue1) sumpf.connect(self.__transform_filter.GetSpectrum, self.__multiplier.SetValue2) sumpf.connect(self.__multiplier.GetResult, self.__itransform.SetSpectrum) sumpf.connect(self.__itransform.GetSignal, self.__signalaliascomp.SetPostprocessingInput) sumpf.connect(self.__signalaliascomp.GetPostprocessingOutput, self.__passoutput.SetSignal)
def _Connect(self): sumpf.connect(self._ampsignal.GetOutput, self._prp.SetSignal) sumpf.connect(self._prp.GetResolution, self._lpfilter.SetResolution) sumpf.connect(self._prp.GetSpectrumLength, self._lpfilter.SetLength) sumpf.connect(self._GetCutoffFrequency, self._lpfilter.SetFrequency) sumpf.connect(self._lpfilter.GetSpectrum, self._lpmultiply.SetInput1) sumpf.connect(self._ampsignal.GetOutput, self._lptransform.SetSignal) sumpf.connect(self._lptransform.GetSpectrum, self._lpmultiply.SetInput2) sumpf.connect(self._lpmultiply.GetOutput, self._lpitransform.SetSpectrum) sumpf.connect(self._lpitransform.GetSignal, self._nonlin_function.SetInput) sumpf.connect(self._nonlin_function.GetOutput, self._merger.AddInput) sumpf.connect(self._ampfilter.GetOutput, self._merger.AddInput) sumpf.connect(self._merger.GetOutput, self._transform.SetSignal) sumpf.connect(self._transform.GetSpectrum, self._split1ch.SetInput) sumpf.connect(self._transform.GetSpectrum, self._split2ch.SetInput) sumpf.connect(self._split1ch.GetOutput, self._multiply.SetInput1) sumpf.connect(self._split2ch.GetOutput, self._multiply.SetInput2) sumpf.connect(self._multiply.GetOutput, self._itransform.SetSpectrum)
def __init__(self, input_signal=None, nonlinear_functions=(nlsp.function_factory.power_series(1), ), filter_irs=None, max_harmonics=None, resampling_algorithm=sumpf.modules.ResampleSignal.SPECTRUM): """ :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 resampling_algorithm: the algorithm which can be used to downsample and upsample the signal eg. sumpf.modules.ResampleSignal.SPECTRUM """ 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(self.__signal)).GetSignal(), ) * len( self.__nlfunctions) else: self.__filter_irs = filter_irs self.__resampling_algorithm = resampling_algorithm 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_upsampling( input_signal=self.inputstage.GetOutput(), nonlin_func=nl, max_harm=mh, filter_impulseresponse=ir, resampling_algorithm=self.__resampling_algorithm) 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 if len(self.hmodels) == 1: self.__sums[0] = self.hmodels[0] self.GetOutput = self.__sums[0].GetOutput
def _Connect(self): sumpf.connect(self._ampsignal.GetOutput, self._prp.SetSignal) sumpf.connect(self._GetSamplingRateSignal, self._upsignal.SetSamplingRate) sumpf.connect(self._GetSamplingRateFilter, self._upfilter.SetSamplingRate) sumpf.connect(self._Getattenuation, self._attenuator.SetAmplificationFactor) sumpf.connect(self._ampsignal.GetOutput, self._upsignal.SetInput) sumpf.connect(self._ampfilter.GetOutput, self._upfilter.SetInput) sumpf.connect(self._upsignal.GetOutput, self._nonlin_function.SetInput) sumpf.connect(self._nonlin_function.GetOutput, self._attenuator.SetInput) sumpf.connect(self._GetSamplingRateFilter, self._downoutput2.SetSamplingRate) sumpf.connect(self._attenuator.GetOutput, self._downoutput2.SetInput) sumpf.connect(self._downoutput2.GetOutput, self._merger.AddInput) sumpf.connect(self._upfilter.GetOutput, self._merger.AddInput) sumpf.connect(self._merger.GetOutput, self._transform.SetSignal) sumpf.connect(self._transform.GetSpectrum, self._split1ch.SetInput) sumpf.connect(self._transform.GetSpectrum, self._split2ch.SetInput) sumpf.connect(self._split1ch.GetOutput, self._multiply.SetInput1) sumpf.connect(self._split2ch.GetOutput, self._multiply.SetInput2) sumpf.connect(self._multiply.GetOutput, self._itransform.SetSpectrum) sumpf.connect(self._itransform.GetSignal, self._downoutput.SetInput) sumpf.connect(self._prp.GetSamplingRate, self._downoutput.SetSamplingRate)
def __init__(self, input_signal=None, nonlinear_functions=None, filter_impulseresponses=None, aliasing_compensation=None, downsampling_position=AFTERNONLINEARBLOCK): """ :param input_signal: the input signal :param nonlinear_functions: the nonlinear functions Eg, [nonlinear_function1, nonlinear_function2, ...] :param filter_impulseresponse: the filter impulse responses Eg, [impulse_response1, impulse_response2, ...] :param aliasing_compensation: the aliasin compensation technique Eg, nlsp.aliasing_compensation.FullUpsamplingAliasingCompensation() :param downsampling_position: the downsampling position Eg, AFTER_NONLINEAR_BLOCK or AFTER_LINEAR_BLOCK """ # interpret the input parameters if input_signal is None: self.__input_signal = sumpf.Signal() else: self.__input_signal = input_signal if nonlinear_functions is None: self.__nonlinear_functions = (nlsp.nonlinear_functions.Power(degree=1),) else: self.__nonlinear_functions = nonlinear_functions if filter_impulseresponses is None: self.__filter_irs = (sumpf.modules.ImpulseGenerator(samplingrate=self.__input_signal.GetSamplingRate(), length=2 ** 10).GetSignal(),) * len( self.__nonlinear_functions) else: self.__filter_irs = filter_impulseresponses self._downsampling_position = downsampling_position # check if the filter ir length and the nonlinear functions length is same if len(self.__nonlinear_functions) == len(self.__filter_irs): self.__branches = len(self.__nonlinear_functions) else: print "the given arguments dont have same length" self.__passsignal = sumpf.modules.PassThroughSignal(signal=self.__input_signal) # create multiple aliasing compensation instances which is similar to the aliasing compensation parameter received if aliasing_compensation is None: self.__aliasingcompensation = nlsp.aliasing_compensation.NoAliasingCompensation() else: self.__aliasingcompensation = aliasing_compensation aliasing_comp = [] while len(aliasing_comp) != self.__branches: classname = self.__aliasingcompensation.__class__() aliasing_comp.append(classname) self.__aliasingcompensations = aliasing_comp self.__hmodels = [] for i, (nl, ir, alias) in enumerate( zip(self.__nonlinear_functions, self.__filter_irs, self.__aliasingcompensations)): h = HammersteinModel(input_signal=self.__passsignal.GetSignal(), nonlinear_function=nl, filter_impulseresponse=ir, aliasing_compensation=alias, downsampling_position=self._downsampling_position) self.__hmodels.append(h) self.__sums = [None] * self.__branches for i in reversed(range(len(self.__hmodels) - 1)): self.__a = sumpf.modules.Add() # print "connecting hammerstein model %i to adder %i" % (i, i) sumpf.connect(self.__hmodels[i].GetOutput, self.__a.SetValue1) 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.SetValue2) else: # print "connecting adder %i to adder %i" % (i+1, i) sumpf.connect(self.__sums[i + 1].GetResult, self.__a.SetValue2) self.__sums[i] = self.__a if len(self.__hmodels) == 1: self.__sums[0] = self.__hmodels[0] self.GetOutput = self.__sums[0].GetOutput else: self.GetOutput = self.__sums[0].GetResult
# Get the properties of the recorded excitation and response length = 2**Signal samplingrate = 48000 prp = sumpf.modules.ChannelDataProperties(signal_length=length, samplingrate=samplingrate) sweep_start_frequency, sweep_stop_frequency, sweep_duration = head_specific.get_sweep_properties( sumpf.modules.SilenceGenerator(length=length, samplingrate=samplingrate).GetSignal()) print "Input sweep prop: startfreq-%f, stopfreq-%f, duration-%f" % ( sweep_start_frequency, sweep_stop_frequency, sweep_duration) load = sumpf.modules.SignalFile(filename=common.get_filename( Speaker, "Sweep%i" % Signal, 1), format=sumpf.modules.SignalFile.WAV_FLOAT) split_excitation = sumpf.modules.SplitSignal(channels=[0]) sumpf.connect(load.GetSignal, split_excitation.SetInput) split_response = sumpf.modules.SplitSignal(channels=[1]) # Model for extracting the harmonics of the recorded signal sumpf.connect(load.GetSignal, split_response.SetInput) fft_excitation = sumpf.modules.FourierTransform() sumpf.connect(split_excitation.GetOutput, fft_excitation.SetSignal) fft_response = sumpf.modules.FourierTransform() sumpf.connect(split_response.GetOutput, fft_response.SetSignal) inversion = sumpf.modules.RegularizedSpectrumInversion( start_frequency=max(sweep_start_frequency * 4.0, 20.0), stop_frequency=sweep_stop_frequency / 4.0, transition_length=100, epsilon_max=0.1) sumpf.connect(fft_excitation.GetSpectrum, inversion.SetSpectrum) tf_measured = sumpf.modules.MultiplySpectrums()