* :func:`unitary_avg_power_spectrum`
"""
+import logging as _logging
import unittest as _unittest
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
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]
"""
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"
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)
# = 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()
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()
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:
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)
# 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()
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(