class TestFreqSpectrum(unittest.TestCase): def setUp(self): unittest.TestCase.setUp(self) self.bb = Blackboard() pattern = '/sines' self.offset = 10 self.frequencies = [1,3,5,7] self.amps = [1,2,1,8] self.gen = DataGenerator( self.bb, pattern, frequencies=self.frequencies, amplitudes=self.amps, offset=self.offset, noise=0 ) self.freqspec = FFTAnalyzer( self.bb, pattern, windowsize=256 ) self.bb.set_bufsize( '/sines/fft', 128 ) def test_fft(self): self.gen.start() self.freqspec.start() sleep( 3 ) self.gen.stop() self.freqspec.stop() result = self.bb.get_data('/sines/fft') # Enable when code coverage is guaranteed #self.assertAlmostEqual( result['data'], self.offset, msg="Offset difference too big", delta=.15 ) #for f,amp in zip(self.frequencies,self.amps): # self.assertAlmostEqual( result[f], amp, msg="Power difference too big: freq %f - original %f - measured %f" % (f, amp, result[f]), delta=.15 ) def test_setFreqBands(self): ''' Verify if frequency bands can be set For now only call the function for code coverage ''' test_freq = 10 self.freqspec.setFreqBands(test_freq) def test_setPatterns(self): ''' Verify if patterns can be set For now only call the function for code coverage ''' test_pattern = '/test' self.freqspec.setPatterns(test_pattern) def test_resetBuffers(self): ''' Verify if buffers can be reset For now only call the function for code coverage ''' self.freqspec.resetBuffers() def tearDown(self): unittest.TestCase.tearDown(self)
class TestBlackboard(unittest.TestCase): def setUp(self): self.blackboard = Blackboard() """ Test put functionality """ def test_put(self): # put value in buffer self.blackboard.put_data( test_pattern, test_value ) # buffer should only contain the added value in a list self.assertEquals( self.blackboard.get_data(test_pattern)['data'], [test_value] ) # set buffersize and add a lot of data for pat in self.blackboard.get_patterns(): self.blackboard.set_bufsize( pat, test_buffersize ) for _ in range( 2000 ): self.blackboard.put_data( test_pattern, randint( 0, 256 ) ) # check whether buffer size remains within buffersize self.assertEqual( len( self.blackboard.get_data( test_pattern )['data'] ), test_buffersize ) """ Test get functionality """ def test_get(self): # register buffer, set buffersize and add a bit of data for pat in self.blackboard.get_patterns(): self.blackboard.set_bufferlength( test_buffersize ) for _ in range( number_of_test_samples ): self.blackboard.put_data( test_pattern, randint( 0, 256 ) ) # buffer should contain the number of added samples self.assertEquals( len( self.blackboard.get_data( test_pattern )['data'] ), number_of_test_samples) def tearDown(self): unittest.TestCase.tearDown(self)
class TestBasePlot(unittest.TestCase): def setUp(self): self.bb = Blackboard() self.pattern = "/foo" self._fig, self._ax = plt.subplots(1) def test_init_no_blackboard(self): with self.assertRaises(ValueError): BasePlot("foo", [self.pattern], self._ax) def test_update_ax(self): baseplot = BasePlot(self.bb, [self.pattern], self._ax) with self.assertRaises(NotImplementedError): baseplot._update_ax() def test_process_plot_data(self): baseplot = BasePlot(self.bb, [self.pattern], self._ax) with self.assertRaises(NotImplementedError): baseplot._process_plot_data(None, None, None) def test_process_data(self): offset = 5000 frequencies = [1, 3, 5, 7] amps = [1, 2, 1, 8] baseplot = BasePlot(self.bb, [self.pattern], self._ax) baseplot._process_plot_data = fake_function gen = DataGenerator(self.bb, self.pattern, frequencies=frequencies, amplitudes=amps, offset=offset, noise=0) self.bb.set_bufsize(self.pattern, 128) gen.start() baseplot.start() sleep(10) baseplot.stop() gen.stop def tearDown(self): unittest.TestCase.tearDown(self)
class TestBasePlot(unittest.TestCase): def setUp(self): self.bb = Blackboard() self.pattern = "/foo" self._fig, self._ax = plt.subplots( 1 ) def test_init_no_blackboard(self): with self.assertRaises(ValueError): BasePlot("foo", [self.pattern], self._ax) def test_update_ax(self): baseplot = BasePlot(self.bb, [self.pattern], self._ax) with self.assertRaises(NotImplementedError): baseplot._update_ax() def test_process_plot_data(self): baseplot = BasePlot(self.bb, [self.pattern], self._ax) with self.assertRaises(NotImplementedError): baseplot._process_plot_data(None, None, None) def test_process_data(self): offset = 5000 frequencies = [1,3,5,7] amps = [1,2,1,8] baseplot = BasePlot(self.bb, [self.pattern], self._ax) baseplot._process_plot_data = fake_function gen = DataGenerator( self.bb, self.pattern, frequencies=frequencies, amplitudes=amps, offset=offset, noise=0 ) self.bb.set_bufsize( self.pattern, 128 ) gen.start() baseplot.start() sleep(10) baseplot.stop() gen.stop def tearDown(self): unittest.TestCase.tearDown(self)
class TestBlackboard(unittest.TestCase): def setUp(self): self.blackboard = Blackboard() """ Test put functionality """ def test_put(self): # put value in buffer self.blackboard.put_data(test_pattern, test_value) # buffer should only contain the added value in a list self.assertEquals( self.blackboard.get_data(test_pattern)['data'], [test_value]) # set buffersize and add a lot of data for pat in self.blackboard.get_patterns(): self.blackboard.set_bufsize(pat, test_buffersize) for _ in range(2000): self.blackboard.put_data(test_pattern, randint(0, 256)) # check whether buffer size remains within buffersize self.assertEqual(len(self.blackboard.get_data(test_pattern)['data']), test_buffersize) """ Test get functionality """ def test_get(self): # register buffer, set buffersize and add a bit of data for pat in self.blackboard.get_patterns(): self.blackboard.set_bufferlength(test_buffersize) for _ in range(number_of_test_samples): self.blackboard.put_data(test_pattern, randint(0, 256)) # buffer should contain the number of added samples self.assertEquals(len(self.blackboard.get_data(test_pattern)['data']), number_of_test_samples) def tearDown(self): unittest.TestCase.tearDown(self)
class TestFirPreprocessing(unittest.TestCase): def setUp(self): self.bb = Blackboard() self.input = HDFReader() def create_filters(self): # create preprocessing filters self._processors = [] self.headset = 0 self.channel = 1 notch = 50 lowpass = 80 filter_pattern1 = '/lpf%d' % ( lowpass ) filter_pattern2 = '/notch%d' % ( notch ) self.pat = '/eeg%d/channel_%d' % ( self.headset, self.channel ) lp = IIRLowPassFilter( self.bb, [self.pat], lowpass=lowpass ) self._processors.append( lp ) self.pat_lpf = self.pat + filter_pattern1 nf = IIRNotchFilter( self.bb, [self.pat_lpf], cutoff_freq = notch, cutoff_width=1 ) self._processors.append( nf ) self.pat_notch = self.pat_lpf + filter_pattern2 nf = IIRNotchFilter( self.bb, [self.pat], cutoff_freq = notch, cutoff_width=1 ) self._processors.append( nf ) self.pat_notch1 = self.pat + filter_pattern2 pp = FIRPreprocessing( self.bb, [self.pat] ) self._processors.append( pp ) self.pat_pp = self.pat + '/pp' def test_start(self): self.create_filters() offset = 5000 plot_size = 1000 offset = 5000 last_count = 0 result = [] frequencies = [1,3,5,7] amps = [1,2,1,8] gen = DataGenerator( self.bb, self.pat, frequencies=frequencies, amplitudes=amps, offset=offset, noise=0 ) self.bb.set_bufsize( self.pat_pp, 128 ) gen.start() # Start filters for p in self._processors: p.start() sleep(1) # Start processing data #for d in self.original[:]: # self.bb.put_data( self.pat, d ) # local_count = self.bb.get_count( self.pat ) # dif = local_count - last_count # if dif > 0: # last_count = local_count # local_results = self.bb.get_data( self.pat_pp )['data'] # if local_results: # local_results = local_results[-dif:] # for r in local_results: # result.append(r) # sleep(.00001) sleep(3) # Stop filters for p in self._processors: p.stop() gen.stop() def test_init_firpreprocessing_pattern_no_string(self): with self.assertRaises(TypeError): FIRPreprocessing( self.bb, 2 ) def tearDown(self): unittest.TestCase.tearDown(self)
class TestFirPreprocessing(unittest.TestCase): def setUp(self): self.bb = Blackboard() self.input = HDFReader() def create_filters(self): # create preprocessing filters self._processors = [] self.headset = 0 self.channel = 1 notch = 50 lowpass = 80 filter_pattern1 = '/lpf%d' % (lowpass) filter_pattern2 = '/notch%d' % (notch) self.pat = '/eeg%d/channel_%d' % (self.headset, self.channel) lp = IIRLowPassFilter(self.bb, [self.pat], lowpass=lowpass) self._processors.append(lp) self.pat_lpf = self.pat + filter_pattern1 nf = IIRNotchFilter(self.bb, [self.pat_lpf], cutoff_freq=notch, cutoff_width=1) self._processors.append(nf) self.pat_notch = self.pat_lpf + filter_pattern2 nf = IIRNotchFilter(self.bb, [self.pat], cutoff_freq=notch, cutoff_width=1) self._processors.append(nf) self.pat_notch1 = self.pat + filter_pattern2 pp = FIRPreprocessing(self.bb, [self.pat]) self._processors.append(pp) self.pat_pp = self.pat + '/pp' def test_start(self): self.create_filters() offset = 5000 plot_size = 1000 offset = 5000 last_count = 0 result = [] frequencies = [1, 3, 5, 7] amps = [1, 2, 1, 8] gen = DataGenerator(self.bb, self.pat, frequencies=frequencies, amplitudes=amps, offset=offset, noise=0) self.bb.set_bufsize(self.pat_pp, 128) gen.start() # Start filters for p in self._processors: p.start() sleep(1) # Start processing data #for d in self.original[:]: # self.bb.put_data( self.pat, d ) # local_count = self.bb.get_count( self.pat ) # dif = local_count - last_count # if dif > 0: # last_count = local_count # local_results = self.bb.get_data( self.pat_pp )['data'] # if local_results: # local_results = local_results[-dif:] # for r in local_results: # result.append(r) # sleep(.00001) sleep(3) # Stop filters for p in self._processors: p.stop() gen.stop() def test_init_firpreprocessing_pattern_no_string(self): with self.assertRaises(TypeError): FIRPreprocessing(self.bb, 2) def tearDown(self): unittest.TestCase.tearDown(self)
class TestFIRFilter(unittest.TestCase): def setUp(self): """ Initialize blackboard and a simulation data generator """ unittest.TestCase.setUp(self) self.bb = Blackboard() self.pattern = '/sines' self.offset = 10 self.frequencies = [50, 10] self.amps = [1, 1] self.gen = DataGenerator(self.bb, self.pattern, frequencies=self.frequencies, amplitudes=self.amps, offset=self.offset, noise=0) def test_init_notch(self): """ Compare the generation of notch filter coefficients with the coefficients provided by Imec """ notch_template = FIRPreprocessing.coefBSF256 fir = FIRFilter(self.bb, self.pattern, 129, 256, 50, 'notch') self.assertEqual(len(notch_template), len(fir.get_coefficients()), 'sets should be equal length') self.assertAlmostEqual( sum([ abs(x - y) for x, y in zip(notch_template, fir.get_coefficients()) ]), 0, 5, 'difference should be small') def test_init_lpf(self): """ Compare the generation of low-pass filter coefficients with the coefficients provided by Imec """ lpf_template = FIRPreprocessing.coefLPF256 fir = FIRFilter(self.bb, self.pattern, 33, 256, 75, 'lpf') coef = fir.get_coefficients() self.assertAlmostEqual( sum([abs(x - y) for x, y in zip(lpf_template, coef)]), 0, 2, 'difference should be small') def test_elementwise_lfilter(self): """ Test whether our method of elementwise processing yields the same results as processing a whole signal at once """ fir = FIRFilter(self.bb, self.pattern, 33, 256, 75, 'lpf') a = 1 sig = [randint(0, 1024) for _ in range(256)] result = lfilter(fir.get_coefficients(), a, sig, axis=0) result2 = [] buf = [] for s in sig: buf.append(s) buf = buf[-33:] result2.append(lfilter(fir.get_coefficients(), a, buf)[-1]) self.assertEqual(len(result), len(result2), 'Results should be equal length') self.assertEqual(sum([abs(x - y) for x, y in zip(result, result2)]), 0, 'Results should be equal value') def test_notch50(self): """ TODO Improve test with better timing mechanism or decouple from internal timing mechanism When plotting the results, the filtered signal looks really good though. """ fir = FIRFilter(self.bb, self.pattern, 129, 256, 50, 'notch') self.gen2 = DataGenerator(self.bb, '/sine', frequencies=[10], amplitudes=[1], offset=self.offset, noise=0) self.bb.set_bufsize('/sine', 512) self.bb.set_bufsize('/sines/notch_50', 512) self.gen.start() self.gen2.start() fir.start() time.sleep(3) self.gen.stop() self.gen2.stop() fir.stop() time.sleep(1) off = len(fir.get_coefficients()) target = self.bb.get_data('/sine')['data'][(off - 1) / 2:128 + (off - 1) / 2] result = self.bb.get_data('/sines/notch_50')['data'][:128] #dif = np.average([ abs( x-y ) for x,y in zip(result, target ) ]) #delta = 1 #self.assertAlmostEqual( dif, 0, msg='Difference between target and result should be smaller than %.2f, difference is %f'%(delta,dif), delta=delta) def test_init_pattern_no_string(self): # An TypeError should be raised when a pattern is no string with self.assertRaises(TypeError): FIRFilter(self.bb, 5, 129, 256, 50, 'notch') def test_init_not_implemented_filter(self): # An NotImplementedError should be raised with self.assertRaises(NotImplementedError): FIRFilter(self.bb, self.pattern, 129, 256, 50, 'bsf') def test_init_incompatible_filter(self): # An TyperError should be raised with self.assertRaises(TypeError): FIRFilter(self.bb, self.pattern, 129, 256, 50, 'foo') def test_init_pattern_list(self): # For codecoverage FIRFilter(self.bb, [self.pattern], 129, 256, 50, 'notch')
class TestFreqSpectrum(unittest.TestCase): def setUp(self): unittest.TestCase.setUp(self) self.bb = Blackboard() pattern = '/sines' self.offset = 10 self.frequencies = [1, 3, 5, 7] self.amps = [1, 2, 1, 8] self.gen = DataGenerator(self.bb, pattern, frequencies=self.frequencies, amplitudes=self.amps, offset=self.offset, noise=0) self.freqspec = FFTAnalyzer(self.bb, pattern, windowsize=256) self.bb.set_bufsize('/sines/fft', 128) def test_fft(self): self.gen.start() self.freqspec.start() sleep(3) self.gen.stop() self.freqspec.stop() result = self.bb.get_data('/sines/fft') # Enable when code coverage is guaranteed #self.assertAlmostEqual( result['data'], self.offset, msg="Offset difference too big", delta=.15 ) #for f,amp in zip(self.frequencies,self.amps): # self.assertAlmostEqual( result[f], amp, msg="Power difference too big: freq %f - original %f - measured %f" % (f, amp, result[f]), delta=.15 ) def test_setFreqBands(self): ''' Verify if frequency bands can be set For now only call the function for code coverage ''' test_freq = 10 self.freqspec.setFreqBands(test_freq) def test_setPatterns(self): ''' Verify if patterns can be set For now only call the function for code coverage ''' test_pattern = '/test' self.freqspec.setPatterns(test_pattern) def test_resetBuffers(self): ''' Verify if buffers can be reset For now only call the function for code coverage ''' self.freqspec.resetBuffers() def tearDown(self): unittest.TestCase.tearDown(self)
class TestFIRFilter( unittest.TestCase ): def setUp(self): """ Initialize blackboard and a simulation data generator """ unittest.TestCase.setUp( self ) self.bb = Blackboard() self.pattern = '/sines' self.offset = 10 self.frequencies = [50,10] self.amps = [1,1] self.gen = DataGenerator( self.bb, self.pattern, frequencies=self.frequencies, amplitudes=self.amps, offset=self.offset, noise=0 ) def test_init_notch(self): """ Compare the generation of notch filter coefficients with the coefficients provided by Imec """ notch_template = FIRPreprocessing.coefBSF256 fir = FIRFilter( self.bb, self.pattern, 129, 256, 50, 'notch' ) self.assertEqual( len(notch_template), len(fir.get_coefficients() ), 'sets should be equal length') self.assertAlmostEqual( sum([ abs( x-y ) for x,y in zip(notch_template, fir.get_coefficients() ) ]), 0, 5, 'difference should be small') def test_init_lpf(self): """ Compare the generation of low-pass filter coefficients with the coefficients provided by Imec """ lpf_template = FIRPreprocessing.coefLPF256 fir = FIRFilter( self.bb, self.pattern, 33, 256, 75, 'lpf' ) coef = fir.get_coefficients() self.assertAlmostEqual( sum([ abs( x-y ) for x,y in zip(lpf_template, coef ) ]), 0, 2, 'difference should be small') def test_elementwise_lfilter(self): """ Test whether our method of elementwise processing yields the same results as processing a whole signal at once """ fir = FIRFilter( self.bb, self.pattern, 33, 256, 75, 'lpf' ) a = 1 sig = [ randint(0,1024) for _ in range(256) ] result = lfilter( fir.get_coefficients(), a, sig, axis=0 ) result2 = [] buf = [] for s in sig: buf.append(s) buf = buf[-33:] result2.append(lfilter( fir.get_coefficients(), a, buf )[-1] ) self.assertEqual( len(result), len(result2), 'Results should be equal length') self.assertEqual( sum([ abs( x-y ) for x,y in zip(result, result2 ) ]), 0, 'Results should be equal value') def test_notch50(self): """ TODO Improve test with better timing mechanism or decouple from internal timing mechanism When plotting the results, the filtered signal looks really good though. """ fir = FIRFilter( self.bb, self.pattern, 129, 256, 50, 'notch' ) self.gen2 = DataGenerator( self.bb, '/sine', frequencies=[10], amplitudes=[1], offset=self.offset, noise=0 ) self.bb.set_bufsize('/sine', 512) self.bb.set_bufsize('/sines/notch_50', 512) self.gen.start() self.gen2.start() fir.start() time.sleep( 3 ) self.gen.stop() self.gen2.stop() fir.stop() time.sleep( 1 ) off = len(fir.get_coefficients()) target = self.bb.get_data('/sine')['data'][(off-1)/2:128+(off-1)/2] result = self.bb.get_data('/sines/notch_50')['data'][:128] #dif = np.average([ abs( x-y ) for x,y in zip(result, target ) ]) #delta = 1 #self.assertAlmostEqual( dif, 0, msg='Difference between target and result should be smaller than %.2f, difference is %f'%(delta,dif), delta=delta) def test_init_pattern_no_string(self): # An TypeError should be raised when a pattern is no string with self.assertRaises(TypeError): FIRFilter( self.bb, 5, 129, 256, 50, 'notch' ) def test_init_not_implemented_filter(self): # An NotImplementedError should be raised with self.assertRaises(NotImplementedError): FIRFilter( self.bb, self.pattern, 129, 256, 50, 'bsf' ) def test_init_incompatible_filter(self): # An TyperError should be raised with self.assertRaises(TypeError): FIRFilter( self.bb, self.pattern, 129, 256, 50, 'foo' ) def test_init_pattern_list(self): # For codecoverage FIRFilter( self.bb, [self.pattern] , 129, 256, 50, 'notch' )