Chris@25: !function() { Chris@25: Chris@25: var EPSILON = 1e-4, Chris@25: assert = require('assert'), Chris@25: complex_array_lib = require('../lib/complex_array'), Chris@25: fft_lib = require('../lib/fft'), Chris@25: ComplexArray = complex_array_lib.ComplexArray, Chris@25: isComplexArray = complex_array_lib.isComplexArray, Chris@25: PI = Math.PI, Chris@25: SQRT2 = Math.SQRT2, Chris@25: SQRT1_2 = Math.SQRT1_2, Chris@25: cos = Math.cos, Chris@25: sin = Math.sin, Chris@25: sqrt = Math.sqrt Chris@25: Chris@25: global.assertComplexArraysAlmostEqual = function(first, second) { Chris@25: var message = second + ' != ' + first Chris@25: Chris@25: assert.equal(first.length, second.length, message) Chris@25: Chris@25: first.forEach(function(value, i) { Chris@25: assertApproximatelyEqual(value.real, second.real[i], message) Chris@25: assertApproximatelyEqual(value.imag, second.imag[i], message) Chris@25: }) Chris@25: } Chris@25: Chris@25: global.assertFFTMatches = function(original, expected) { Chris@25: var transformed, copy Chris@25: Chris@25: if (!isComplexArray(expected)) { Chris@25: throw TypeError('expected match should be a ComplexArray') Chris@25: } Chris@25: Chris@25: copy = new ComplexArray(original) Chris@25: transformed = fft_lib.FFT(original) Chris@25: assertComplexArraysAlmostEqual(expected, transformed) Chris@25: assertComplexArraysAlmostEqual(copy, fft_lib.InvFFT(transformed)) Chris@25: } Chris@25: Chris@25: global.assertFFTMatchesDFT = function(input) { Chris@25: input = new ComplexArray(input) Chris@25: Chris@25: assertComplexArraysAlmostEqual(DFT(input), fft_lib.FFT(input)) Chris@25: } Chris@25: Chris@25: global.DFT = function(input) { Chris@25: var n = input.length, Chris@25: amplitude = 1 / sqrt(n), Chris@25: output = new ComplexArray(input), Chris@25: phase = {real: 0, imag: 0}, Chris@25: delta = {real: 0, imag: 0}, Chris@25: i, j, Chris@25: _swap Chris@25: Chris@25: if (!isComplexArray(input)) { Chris@25: input = new ComplexArray(input) Chris@25: } Chris@25: Chris@25: for(i = 0; i < n; i++) { Chris@25: output.real[i] = 0, output.imag[i] = 0 Chris@25: phase.real = 1, phase.imag = 0 Chris@25: delta.real = cos(2*PI*i/n), delta.imag = sin(2*PI*i/n) Chris@25: Chris@25: for(j = 0; j < n; j++) { Chris@25: output.real[i] += phase.real * input.real[j] - phase.imag * input.imag[j] Chris@25: output.imag[i] += phase.real * input.imag[j] + phase.imag * input.real[j] Chris@25: _swap = phase.real Chris@25: phase.real = phase.real * delta.real - phase.imag * delta.imag Chris@25: phase.imag = _swap * delta.imag + phase.imag * delta.real Chris@25: } Chris@25: output.real[i] *= amplitude Chris@25: output.imag[i] *= amplitude Chris@25: } Chris@25: Chris@25: return output Chris@25: } Chris@25: Chris@25: function assertApproximatelyEqual(first, second, message) { Chris@25: var delta = Math.abs(first - second) Chris@25: assert.ok(delta < EPSILON, message) Chris@25: } Chris@25: Chris@25: }()