/** * Copyright 2004-2006 DFKI GmbH. * All Rights Reserved. Use is subject to license terms. * * This file is part of MARY TTS. * * MARY TTS is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package marytts.util.math; import marytts.signalproc.display.FunctionGraph; import marytts.signalproc.filter.FIRFilter; import marytts.util.data.BufferedDoubleDataSource; import marytts.util.data.DoubleDataSource; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * @author Marc Schröder * */ public class FFTTest { protected int LEN = 1024; protected int ONE = LEN / 10; protected double[] x1; protected double[] x2; protected double[] y; protected FunctionGraph showGraph(double[] array, String title) { FunctionGraph graph = new FunctionGraph(400, 200, 0, 1. / ONE, array); graph.showInJFrame(title, 500, 300, true, false); try { Thread.sleep(1000); } catch (InterruptedException e) { } return graph; } @Before public void setUp() { x1 = new double[ONE]; for (int i = 0; i < ONE; i++) x1[i] = 2 * (1 - (double) i / ONE); x2 = new double[LEN]; for (int i = 0; i < LEN; i++) x2[i] = (double) i / LEN; y = FFT.convolveWithZeroPadding(x1, x2, 1. / ONE); } @Test public void testTransform() { double[] signal = getSampleSignal(1024); double[] real = new double[signal.length]; System.arraycopy(signal, 0, real, 0, signal.length); double[] imag = new double[signal.length]; FFT.transform(real, imag, false); FFT.transform(real, imag, true); double err = MathUtils.sumSquaredError(signal, real); Assert.assertTrue("Error: " + err, err < 1.E-16); } @Test public void testConvolution() { Assert.assertTrue(y.length == x1.length + x2.length); } @Test public void testFIRConvolution() { double[] signal = x2; double[] ir = x1; double[] resultingSignal = new double[signal.length]; double[] reference = new double[signal.length]; int initialTrim = ir.length / 2; int finalTrim = ir.length - initialTrim; // reference is convolution trimmed by the impulse response length: System.arraycopy(y, initialTrim, reference, 0, reference.length); assert reference.length == y.length - initialTrim - finalTrim; int shift = LEN / 2 - ir.length; FIRFilter filter = new FIRFilter(ir, shift); DoubleDataSource filtered = filter.apply(new BufferedDoubleDataSource(signal)); int pos = 0; int iteration = 1; while (filtered.hasMoreData()) { int read = filtered.getData(resultingSignal, pos, shift); pos += read; // showGraph(resultingSignal, "resultingSignal after iteration " + (iteration++)); } for (int i = 0; i < resultingSignal.length; i++) { resultingSignal[i] *= 1. / ONE; } /* * showGraph(resultingSignal, "resultingSignal"); showGraph(y, "y"); showGraph(ir, "impulse response"); showGraph(signal, * "signal"); * * try {Thread.sleep(100000);}catch(Exception e) {} */ double err = MathUtils.sumSquaredError(reference, resultingSignal); Assert.assertTrue("Error: " + err, err < 1.E-20); } public static double[] getSampleSignal(int length) { double[] signal = new double[length]; for (int i = 0; i < length; i++) { signal[i] = Math.round(10000 * Math.sin(2 * Math.PI * i / length)) / 32768.0; } return signal; } public static double[] getSampleSignal(int lengthInSamples, int samplingFrequency, int signalFrequency) { double[] signal = new double[lengthInSamples]; for (int i = 0; i < lengthInSamples; i++) { double factor = MathUtils.TWOPI * signalFrequency / samplingFrequency; signal[i] = Math.round(10000 * Math.sin(factor * i)) / 32768.0; } return signal; } }