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)
Пример #3
0
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)
Пример #4
0
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)
Пример #5
0
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)
Пример #7
0
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)
Пример #8
0
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')
Пример #9
0
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)
Пример #10
0
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' )