class BandPassExample(object): def __init__(self): self.su = SignalUtil() def getSignal(self, a, t, f0): x = 0.1 * np.sin(2 * np.pi * 1.2 * np.sqrt(t)) x += 0.01 * np.cos(2 * np.pi * 312 * t + 0.1) x += a * np.cos(2 * np.pi * f0 * t + .11) x += 0.03 * np.cos(2 * np.pi * 2000 * t) return x def getEEGSignal(self): scriptPath = os.path.dirname(os.path.abspath(__file__)) return EEGTableFileUtil().readFile(scriptPath + "/../../examples/example_1024.csv") def plotBBF(self, fs, lowcut, highcut): # Plot the frequency response for a few different orders. plt.figure(1) plt.clf() for order in [2, 4, 8]: b, a = self.su.butterBandpass(lowcut, highcut, fs, order=order) w, h = freqz(b, a, worN=2000) plt.doPlot((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order) plt.doPlot([0, 0.5 * fs], [np.sqrt(0.5), np.sqrt(0.5)], '--', label='sqrt(0.5)') plt.xlabel('Frequency (Hz)') plt.ylabel('Gain') plt.grid(True) plt.legend(loc='best') def getDuration(self, data): time = data.getColumn("Timestamp") duration = time[len(time) - 1] - time[0] return duration def plotEEGSignal(self): # Filter a noisy signal. data = self.getEEGSignal() fs = data.getSamplingRate(); x = data.getColumn("F3") x = SignalUtil().normalize(x) duration = self.getDuration(data) t = np.linspace(0, duration, len(x), endpoint=False) plt.figure(2) plt.clf() plt.doPlot(t, x, label='normalized signal') for label, (lowcut, highcut) in EEGUtil().channel_ranges.iteritems(): if label == "alpha": y = self.su.butterBandpassFilter(x, lowcut, highcut, fs, order=6) plt.doPlot(t, y, label='%s (%d - %dHz)' % (label, lowcut, highcut)) plt.xlabel('time (seconds)') plt.grid(True) plt.axis('tight') plt.legend(loc='upper left') def plotSoundSignal(self): # Filter a noisy signal. path = "../../examples/" fs, s1 = wavfile.read(path + '12000hz.wav') if len(s1.shape) == 2: s1 = s1[:,0] n = float(len(s1)) t = arange(0, n, 1) t = t / fs t = t * 1000 #scale to milliseconds plt.figure(2) plt.clf() plt.doPlot(t, s1, label='sound signal') y = self.su.butterBandpassFilter(s1, 11000, 13000, fs, order=6) #wavfile.write(path + '12000hz_cut.wav', fs, y) plt.doPlot(t, y, label='%s (%d - %dHz)' % ("12000Hz", 11000, 13000)) plt.xlabel('time (seconds)') plt.grid(True) plt.axis('tight') plt.legend(loc='upper left') def plotSignal(self, fs, lowcut, highcut): # Filter a noisy signal. T = 0.05 nsamples = T * fs t = np.linspace(0, T, nsamples, endpoint=False) a = 0.02 f0 = 600.0 # frequency x = self.getSignal(a, t, f0) plt.figure(2) plt.clf() plt.doPlot(t, x, label='Noisy signal') y = self.butterBandpassFilter(x, lowcut, highcut, fs, order=6) plt.doPlot(t, y, label='Filtered signal (%g Hz)' % f0) plt.xlabel('time (seconds)') plt.hlines([-a, a], 0, T, linestyles='--') plt.grid(True) plt.axis('tight') plt.legend(loc='upper left') def main(self): # Sample rate and desired cutoff frequencies (in Hz). fs = 5000.0 lowcut = 500.0 highcut = 1250.0 self.plotBBF(fs, lowcut, highcut) #self.plotSignal(fs, lowcut, highcut) self.plotEEGSignal() #self.plotSoundSignal() plt.show()
class TestFrequencyFilter(unittest.TestCase): def setUp(self): self.util = SignalUtil() self._setSignalParams() def _setSignalParams(self, offset=0, length=-1): self.samplingRate, self.data= self._readSoundFile(offset=offset, length=length) self.n = len(self.data) self.nUniquePts = ceil((self.n+1)/2.0) self.freqArray = np.arange(0, self.nUniquePts, 1.0) * (self.samplingRate / self.n) def test_butterBandpass(self): samplingRate = 32 i = samplingRate / 4 b, a = self.util.butterBandpass(i-1, i+1, samplingRate) _, h = freqz(b, a, worN=samplingRate*4) h = abs(h) self.assertEqual(np.argmax(h), len(h)/2) self.assertAlmostEqual(max(h), 1, delta=0.1) self.assertAlmostEqual(h[0], 0, delta=0.01) self.assertAlmostEqual(h[len(h)-1], 0, delta=0.01) def test_butterBandpass_egde(self): # no signal allowed b, a = self.util.butterBandpass(5, 5, 16) _, h = freqz(b, a, worN=32) self.assertEquals(np.count_nonzero(abs(h)), 0) # everything gets through (except 0) b, a = self.util.butterBandpass(0, 8, 16) _, h = freqz(b, a, worN=16) self.assertAlmostEqual(sum(abs(h)), len(h)-1, delta = 1) b, a = self.util.butterBandpass(0.5, 8, 16) _, h = freqz(b, a, worN=16) self.assertAlmostEqual(sum(abs(h)), len(h)-1, delta = 1) b, a = self.util.butterBandpass(-1, 9, 16) _, h = freqz(b, a, worN=16) self.assertAlmostEqual(sum(abs(h)), len(h)-1, delta = 1) def test_butterBandpassFilter(self): x = [1, -1, 1, -1] _ = self.util.butterBandpassFilter(x, 1, 2, 10) def _readSoundFile(self, fileName='12000hz.wav', offset=0, length=-1): samplingRate, data = wavfile.read(PATH + fileName) if len(data.shape) == 2: data = data[:,0] if(length > -1): data = data[offset:offset+length] data = self.util.normalize(data) return samplingRate, data def _getMaxFrequency(self, data, freqArray): fft = FFTUtil().fft(data) return freqArray[np.argmax(fft)] def test_butterBandpassFilter_original(self): freqMax = self._getMaxFrequency(self.data, self.freqArray) self.assertAlmostEqual(freqMax, 12000.0, delta= 1000) def test_butterBandpassFilter_filterNoCut(self): cut = self.util.butterBandpassFilter(self.data, 1000, self.samplingRate/2-1000, self.samplingRate) freqMax = self._getMaxFrequency(cut, self.freqArray) self.assertAlmostEqual(freqMax, 12000.0, delta= 1000) def test_butterBandpassFilter_filterAroundMax(self): cut = self.util.butterBandpassFilter(self.data, 11000, 13000, self.samplingRate) freqMax = self._getMaxFrequency(cut, self.freqArray) self.assertAlmostEqual(freqMax, 12000.0, delta= 1000) def test_butterBandpassFilter_filterAboveMax(self): cut = self.util.butterBandpassFilter(self.data, 0, 2000, self.samplingRate) freqMax = self._getMaxFrequency(cut, self.freqArray) self.assertNotEqual(freqMax, 12000.0) self.assertAlmostEqual(freqMax, 1000.0, delta= 1000) def test_butterBandpassFilter_filterBeyondMax(self): cut = self.util.butterBandpassFilter(self.data, self.samplingRate/2-2000, self.samplingRate/2, self.samplingRate) freqMax = self._getMaxFrequency(cut, self.freqArray) self.assertNotEqual(freqMax, 12000.0) self.assertAlmostEqual(freqMax, self.samplingRate/2-1000, delta= 1000) def test_butterBandpassFilter_short(self): self._setSignalParams(length=4) freqMax = self._getMaxFrequency(self.data, self.freqArray) self.assertAlmostEqual(freqMax, 12000.0, delta= 1000) cut = self.util.butterBandpassFilter(self.data, 1000, self.samplingRate/2-1000, self.samplingRate) freqMax = self._getMaxFrequency(cut, self.freqArray) self.assertAlmostEqual(freqMax, 12000.0, delta= 1000) def test_butterBandpassFilter_originalAndShort(self): cutOrig = self.util.butterBandpassFilter(self.data, 1000, self.samplingRate/2-1000, self.samplingRate) freqMaxOrig = self._getMaxFrequency(self.data, self.freqArray) self._setSignalParams(length=4) cutShort = self.util.butterBandpassFilter(self.data, 1000, self.samplingRate/2-1000, self.samplingRate) freqMaxShort = self._getMaxFrequency(self.data, self.freqArray) self.assertAlmostEqual(freqMaxShort, freqMaxOrig, delta=1000) for i in range(len(cutShort)): self.assertAlmostEqual(cutOrig[i], cutShort[i], delta=0.02)