From 217680246794065fa4130a2a20900e06592ceb11 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 19 Nov 2012 01:38:46 -0500 Subject: [PATCH] FFT_tools: add LOG and rework tests to use self.assert...(). Now you don't need to compare expected-vs-actual by hand. The troublesome self.run_sin(sin_freq=1, samp_freq=1024, samples=2048) case is handled by explicitly making a very fuzzy comparison. This gets rid of all the print() statements. --- FFT_tools.py | 75 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/FFT_tools.py b/FFT_tools.py index 51a2fea..abdc75f 100644 --- a/FFT_tools.py +++ b/FFT_tools.py @@ -26,6 +26,7 @@ Main entry functions: * :func:`unitary_avg_power_spectrum` """ +import logging as _logging import unittest as _unittest import numpy as _numpy @@ -33,6 +34,12 @@ import numpy as _numpy __version__ = '0.4' + +LOG = _logging.getLogger('FFT-tools') +LOG.addHandler(_logging.StreamHandler()) +LOG.setLevel(_logging.ERROR) + + # Display time- and freq-space plots of the test transforms if True TEST_PLOTS = False @@ -358,22 +365,21 @@ class TestRFFT (_unittest.TestCase): Xa.append(sum([x * _numpy.exp(-2 * _numpy.pi * i * m * k / n) for x,m in zip(xs, range(n))])) if k < len(Xs): - if (Xs[k] - Xa[k]) / _numpy.abs(Xa[k]) >= 1e-6: - raise ValueError( - ('rfft mismatch on element {}: {} != {}, ' - 'relative error {}').format( - k, Xs[k], Xa[k], - (Xs[k] - Xa[k]) / _numpy.abs(Xa[k]))) + self.assertAlmostEqual( + (Xs[k] - Xa[k]) / _numpy.abs(Xa[k]), 0, 6, + ('rfft mismatch on element {}: {} != {}, ' + 'relative error {}').format( + k, Xs[k], Xa[k], (Xs[k] - Xa[k]) / _numpy.abs(Xa[k]))) # Which should satisfy the discrete form of Parseval's theorem # n-1 n-1 # SUM |x_m|^2 = 1/n SUM |X_k|^2. # m=0 k=0 timeSum = sum([_numpy.abs(x)**2 for x in xs]) freqSum = sum([_numpy.abs(X)**2 for X in Xa]) - if _numpy.abs(freqSum / _numpy.float(n) - timeSum) / timeSum >= 1e-6: - raise ValueError( - "Mismatch on Parseval's, {} != 1/{} * {}".format( - timeSum, n, freqSum)) + self.assertAlmostEqual( + _numpy.abs(freqSum / _numpy.float(n) - timeSum) / timeSum, 0, 6, + "Mismatch on Parseval's, {} != 1/{} * {}".format( + timeSum, n, freqSum)) def test_rfft(self): xs = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1] @@ -394,20 +400,18 @@ class TestUnitaryRFFT (_unittest.TestCase): """ dt = 1.0 / freq df = freqs[1] - freqs[0] - if (df - 1 / (len(xs) * dt)) / df >= 1e-6: - raise ValueError( - 'Mismatch in spacing, {} != 1/({}*{})'.format(df, len(xs), dt)) + self.assertAlmostEqual( + (df - 1 / (len(xs) * dt)) / df, 0, 6, + 'Mismatch in spacing, {} != 1/({}*{})'.format(df, len(xs), dt)) Xa = list(Xs) for k in range(len(Xs) - 1, 1, -1): Xa.append(Xa[k]) - if len(xs) != len(Xa): - raise ValueError( - 'Length mismatch {} != {}'.format(len(xs), len(Xa))) + self.assertEqual(len(xs), len(Xa)) lhs = sum([_numpy.abs(x)**2 for x in xs]) * dt rhs = sum([_numpy.abs(X)**2 for X in Xa]) * df - if _numpy.abs(lhs - rhs) / lhs >= 1e-4: - raise ValueError( - "Mismatch on Parseval's, {} != {}".format(lhs, rhs)) + self.assertAlmostEqual( + _numpy.abs(lhs - rhs) / lhs, 0, 3, + "Mismatch on Parseval's, {} != {}".format(lhs, rhs)) def test_parsevals(self): "Test unitary rfft on Parseval's theorem" @@ -464,8 +468,7 @@ class TestUnitaryRFFT (_unittest.TestCase): expected = _numpy.zeros((len(freq_axis),), dtype=_numpy.float) # normalized sinc(x) = sin(pi x)/(pi x) # so sinc(0.5) = sin(pi/2)/(pi/2) = 2/pi - if _numpy.sinc(0.5) != 2.0 / _numpy.pi: - raise ValueError('abnormal sinc()') + self.assertEqual(_numpy.sinc(0.5), 2.0 / _numpy.pi) for i in range(len(freq_axis)): f = freq_axis[i] expected[i] = 1.0 / _numpy.abs(a) * _numpy.sinc(f / a) @@ -589,13 +592,15 @@ class TestUnitaryPowerSpectrum (_unittest.TestCase): # = 0.5 / df (T = 1/df) expected[i] = 0.5 / df - print('The power should be a peak at {} Hz of {} ({}, {})'.format( + LOG.debug('The power should be a peak at {} Hz of {} ({}, {})'.format( sin_freq, expected[i], freq_axis[imax], power[imax])) Pexp = P = 0 for i in range(len(freq_axis)): Pexp += expected[i] * df P += power[i] * df - print('The total power should be {} ({})'.format(Pexp, P)) + self.assertAlmostEqual( + _numpy.abs((P - Pexp) / Pexp), 0, 1, + 'The total power should be {} ({})'.format(Pexp, P)) if TEST_PLOTS: figure = _pyplot.figure() @@ -645,8 +650,10 @@ class TestUnitaryPowerSpectrum (_unittest.TestCase): expected = _numpy.ones( (len(freq_axis),), dtype=_numpy.float) * expected_amp - print('The power should be flat at y = {} ({})'.format( - expected_amp, power[0])) + self.assertAlmostEqual( + expected_amp, power[0], 4, + 'The power should be flat at y = {} ({})'.format( + expected_amp, power[0])) if TEST_PLOTS: figure = _pyplot.figure() @@ -711,8 +718,10 @@ class TestUnitaryPowerSpectrum (_unittest.TestCase): f = i * df gaus = self.gaussian(area, mean, std, f) expected[i] = 2.0 * gaus**2 * samp_freq / samples - print(('The power should be a half-gaussian, ' - 'with a peak at 0 Hz with amplitude {} ({})').format( + self.assertAlmostEqual( + expected[0], power[0], 3, + ('The power should be a half-gaussian, ' + 'with a peak at 0 Hz with amplitude {} ({})').format( expected[0], power[0])) if TEST_PLOTS: @@ -740,7 +749,7 @@ class TestUnitaryPowerSpectrum (_unittest.TestCase): class TestUnitaryAvgPowerSpectrum (_unittest.TestCase): def run_sin(self, sin_freq=10, samp_freq=512, samples=1024, chunk_size=512, - overlap=True, window=window_hann): + overlap=True, window=window_hann, places=3): """TODO """ x = _numpy.zeros((samples,), dtype=_numpy.float) @@ -758,13 +767,15 @@ class TestUnitaryAvgPowerSpectrum (_unittest.TestCase): # see TestUnitaryPowerSpectrum.run_unitary_power_spectrum_sin() expected[i] = 0.5 / df - print('The power should peak at {} Hz of {} ({}, {})'.format( - sin_freq, expected[i], freq_axis[imax], power[imax])) + LOG.debug('The power should peak at {} Hz of {} ({}, {})'.format( + sin_freq, expected[i], freq_axis[imax], power[imax])) Pexp = P = 0 for i in range(len(freq_axis)): Pexp += expected[i] * df P += power[i] * df - print('The total power should be {} ({})'.format(Pexp, P)) + self.assertAlmostEqual( + Pexp, P, places, + 'The total power should be {} ({})'.format(Pexp, P)) if TEST_PLOTS: figure = _pyplot.figure() @@ -787,7 +798,7 @@ class TestUnitaryAvgPowerSpectrum (_unittest.TestCase): self.run_sin(sin_freq=17, samp_freq=512, samples=1024) self.run_sin(sin_freq=5, samp_freq=1024, samples=2048) # test long wavelenth sin, so be closer to window frequency - self.run_sin(sin_freq=1, samp_freq=1024, samples=2048) + self.run_sin(sin_freq=1, samp_freq=1024, samples=2048, places=0) # finally, with some irrational numbers, to check that I'm not # getting lucky self.run_sin( -- 2.26.2