package org.signalml.math.fft;
import static org.junit.Assert.assertEquals;
import static org.signalml.SignalMLAssert.assertArrayEquals;
import org.apache.commons.math.complex.Complex;
import org.junit.Test;
/**
* Applies unit tests to the {@link FourierTransform}.
*
* @author Piotr Szachewicz
*/
public class FourierTransformTest {
@Test
public void testForwardFFT() {
FourierTransform transform = new FourierTransform();
double[] signal = new double[] {1,4,2,-1,7,4,5,2};
Complex[] expectedFFT = new Complex[] {
new Complex(24.00000000,0),
new Complex(-3.87867966, 5.12132034),
new Complex(1.00000000,-7),
new Complex(-8.12132034,-0.87867966),
new Complex(6.00000000, 0),
new Complex(-8.12132034, 0.87867966),
new Complex(1.00000000,7),
new Complex(-3.87867966, -5.12132034)
};
Complex[] actualFFT = transform.forwardFFT(signal);
assertArrayEquals(expectedFFT, actualFFT, new Complex(1e-5, 1e-5));
}
@Test
public void testGetPowerOfTwoSize() {
int actual = FourierTransform.getPowerOfTwoSize(13);
assertEquals(16, actual);
assertEquals(256, FourierTransform.getPowerOfTwoSize(256));
}
@Test
public void testForwardFFTNotPowerOf2() {
FourierTransform transform = new FourierTransform();
double[] signal = new double[] {1, 8, 3, -5, 4};
//these expectedFFT data was obtained from python using the following code:
//from numpy import *
//a = array((1, 8, 3, -5, 4, 0, 0, 0));
//fft.fft(a)
Complex[] expectedFFT = new Complex[] {
new Complex(11.00000000, 0),
new Complex(6.19238816, -5.12132034),
new Complex(2.00000000, -13),
new Complex(-12.19238816, +0.87867966),
new Complex(5.00000000, 0),
new Complex(-12.19238816, -0.87867966),
new Complex(2.00000000, 13),
new Complex(6.19238816, +5.12132034)
};
Complex[] actualFFT = transform.forwardFFT(signal);
assertArrayEquals(expectedFFT, actualFFT, new Complex(1e-5, 1e-5));
}
@Test
public void testInverseFFT() {
FourierTransform transform = new FourierTransform();
double[] signal = new double[] {1,4,2,-1,7,4,5,2};
Complex[] actualFFT = transform.forwardFFT(signal);
double[] signalAfterInverseFFT = transform.inverseFFT(actualFFT);
assertArrayEquals(signal, signalAfterInverseFFT, 1e-5);
}
@Test
public void testPadWithZeroIfNecessary() {
double[] signal = new double[] {1, 2, 3, 4, 5};
double[] paddedSignal = FourierTransform.padWithZeroIfNecessary(signal);
double[] expected = new double[] {1, 2, 3, 4, 5, 0, 0, 0};
assertArrayEquals(expected, paddedSignal, 1e-5);
signal = new double[] {1, 2, 3, 4};
paddedSignal = FourierTransform.padWithZeroIfNecessary(signal);
expected = new double[] {1, 2, 3, 4};
assertArrayEquals(expected, paddedSignal, 1e-5);
}
@Test
public void testGetFrequencies() {
double[] signal = new double[8];
double[] expectedFrequencies = new double[] {0, 18.05, 36.1, 54.15};
double[] actualFrequencies = FourierTransform.getFrequencies(signal, 144.4);
assertArrayEquals(expectedFrequencies, actualFrequencies, 1e-5);
signal = new double[11]; //should be padded to N=16
expectedFrequencies = new double[] {0, 9.025, 18.05, 27.075, 36.1, 45.125, 54.15, 63.175};
actualFrequencies = FourierTransform.getFrequencies(signal, 144.4);
assertArrayEquals(expectedFrequencies, actualFrequencies, 1e-5);
}
@Test
public void testCalculatePowerSpectrum() {
double[] signal = new double[] {
1.2945659058474952, -0.3345509351321665, 5.686547339065295, -8.251057190829304, 6.782008754863941, -9.134070114429775, -12.259336118683912, 13.486409636503414,
1.8258866901508277, 0.4308346756427337, -18.640142221783385, -7.815740922810197, 35.705738662583414, 7.632716335419829, 1.2143921649235434, 0.6845342901367637,
-20.37850112097658, 9.85023416020675, 14.78950345263582, 2.7650244844863296, -6.942829611294604, -16.40622299713456, 3.082133356005155, -7.242053767287787,
-2.197578472736221, 17.385956045818038, 6.162402093861749, 10.838229891253318, -12.724725517976047, -23.84119303031666, -1.5768588095737623, -5.900298186852732,
10.202159448157966, -2.615649371592628, -21.682798991223805, 14.165208986842746, 17.853755293871323, 4.704799142360598, -21.755783846205357, -24.902217334838383,
31.78449300189404, 23.343600178346634, -12.750695801273517, -16.622844135624327, -9.384465577200022, 8.929057623584448, -11.965855209828595, 1.955062908265024,
24.329981556146993, -21.213543509571668, -12.584172736229025, 10.43515216846423, -13.408886913972406, -36.02748448905436, -34.20473261490329, 10.417435036954839,
-10.186784862756335, -57.55700608412204, -35.64481864122739, -42.031481578404325, -53.12914668440834, -100.42137643435781, -153.05710437623753, 14.050410151715724
};
double[] expectedSpectrum = new double[] {
7881.704916587174, 7.673766100809436, 12.187623700910711, 0.8159553743630922,1.4770931373325087, 6.498600593661602, 10.85091081725627, 1.061426422745983,
26.88128120985778, 21.78562336940601, 3.4244437826030345, 32.21854497792773, 22.91863874862273, 55.16914569310824, 83.10465624126286, 16.042215100310283,
31.3136707302396, 38.36589514960133, 18.474755969059, 1.384323391051688, 3.254238160709387, 3.306617793557015, 0.8176794118837908, 0.8308016702724461,
7.60029232776595, 63.8659508925275, 8.439245833668412, 0.0704436056803683,0.1361250292097137, 0.09222877638116617, 0.08975138063516105, 0.08593685429305786
};
double[] expectedFrequencies = new double[] {
0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0,
18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0, 32.0,
34.0, 36.0, 38.0, 40.0, 42.0, 44.0, 46.0, 48.0,
50.0, 52.0, 54.0, 56.0, 58.0, 60.0, 62.0
};
FourierTransform fourierTransform = new FourierTransform(WindowType.HAMMING);
double[] actualSpectrum = fourierTransform.calculatePowerSpectrum(signal);
double[] actualFrequencies = fourierTransform.getFrequencies(signal, 128.0);
assertArrayEquals(expectedSpectrum, actualSpectrum, 1e-5);
assertArrayEquals(expectedFrequencies, actualFrequencies, 1e-5);
}
}