@Test public void testRealSTFT() { final int nFft = 128; final int step = 64; final int nSamples = (128 * 3) - 32; final double dt = 1e-3; final double fSine = 25.0; DoubleErrorDataSet sine = new DoubleErrorDataSet("sine", nSamples); for (int i = 0; i < nSamples; i++) { double t = i * dt; double y = i > nFft ? Math.sin(fSine * Math.PI * 2 * t) : 0.0; sine.set(i, t, y); } sine.getAxisDescription(DIM_X).set("Time", "s"); sine.getAxisDescription(DIM_Y).set("Voltage", "V"); final GridDataSet sineSpectrogram = ShortTimeFourierTransform.real(sine, null, nFft, step, Apodization.Hann, Padding.ZERO, false, true); assertArrayEquals(new int[] { nFft / 2, 6 }, sineSpectrogram.getShape()); assertEquals(nFft / 2 * 6, sineSpectrogram.getDataCount()); assertEquals("STFT(" + sine.getName() + ")", sineSpectrogram.getName()); assertEquals(nFft, Integer.valueOf(((DataSetMetaData) sineSpectrogram).getMetaInfo().get("RealSTFT-nFFT"))); assertEquals(step, Integer.valueOf(((DataSetMetaData) sineSpectrogram).getMetaInfo().get("RealSTFT-step"))); assertEquals(0, sineSpectrogram.getAxisDescription(DIM_Y).getMin()); assertEquals(dt * nSamples, sineSpectrogram.getAxisDescription(DIM_Y).getMax(), nFft); assertEquals(sine.getAxisDescription(DIM_X).getName(), sineSpectrogram.getAxisDescription(DIM_Y).getName()); assertEquals(sine.getAxisDescription(DIM_X).getUnit(), sineSpectrogram.getAxisDescription(DIM_Y).getUnit()); assertEquals(0, sineSpectrogram.getAxisDescription(DIM_X).getMin()); assertEquals(0.5 / dt, sineSpectrogram.getAxisDescription(DIM_X).getMax(), 10.0); assertEquals("Frequency", sineSpectrogram.getAxisDescription(DIM_X).getName()); assertEquals("Hz", sineSpectrogram.getAxisDescription(DIM_X).getUnit()); assertEquals(0, sineSpectrogram.getAxisDescription(DIM_Z).getMin()); assertEquals("Magnitude", sineSpectrogram.getAxisDescription(DIM_Z).getName()); assertEquals(sine.getAxisDescription(DIM_Y).getUnit(), sineSpectrogram.getAxisDescription(DIM_Z).getUnit()); assertArrayEquals(new double[] { 0, 1 * step * dt, 2 * step * dt, 3 * step * dt, 4 * step * dt, 5 * step * dt }, sineSpectrogram.getGridValues(DIM_Y), dt); final double[][] zValues = getDataAsNestedArray(sineSpectrogram); final DoubleFFT_1D fastFourierTrafo = new DoubleFFT_1D(nFft); final double[] vals1ref = Arrays.copyOfRange(sine.getValues(DIM_Y), 0, nFft); Apodization.Hann.apodize(vals1ref); fastFourierTrafo.realForward(vals1ref); final double[] vals1refMag = SpectrumTools.computeMagnitudeSpectrum(vals1ref, true); assertArrayEquals(vals1refMag, zValues[0]); final double[] vals2ref = Arrays.copyOfRange(sine.getValues(DIM_Y), 2 * step, 2 * step + nFft); Apodization.Hann.apodize(vals2ref); fastFourierTrafo.realForward(vals2ref); final double[] vals2refMag = SpectrumTools.computeMagnitudeSpectrum(vals2ref, true); assertArrayEquals(vals2refMag, zValues[2]); final double[] vals3ref = new double[nFft]; System.arraycopy(sine.getValues(DIM_Y), 5 * step, vals3ref, 0, nFft - 32 - step); Apodization.Hann.apodize(vals3ref); fastFourierTrafo.realForward(vals3ref); final double[] vals3refMag = SpectrumTools.computeMagnitudeSpectrum(vals3ref, true); assertArrayEquals(vals3refMag, zValues[5]); ShortTimeFourierTransform.real(sine, sineSpectrogram, nFft, step, Apodization.Hamming, Padding.ZOH, false, true); final double[][] zValuesZOH = getDataAsNestedArray(sineSpectrogram); final double[] vals3refZOH = new double[nFft]; System.arraycopy(sine.getValues(DIM_Y), 5 * step, vals3refZOH, 0, nFft - 32 - step); Arrays.fill(vals3refZOH, nFft - 32 - step, nFft, vals3refZOH[nFft - 32 - step - 1]); Apodization.Hamming.apodize(vals3refZOH); fastFourierTrafo.realForward(vals3refZOH); final double[] vals3refMagZOH = SpectrumTools.computeMagnitudeSpectrum(vals3refZOH, true); assertArrayEquals(zValuesZOH[5], vals3refMagZOH); final GridDataSet sineSpectrogramMirror = ShortTimeFourierTransform.real(sine, null, nFft, step, Apodization.Rectangular, Padding.MIRROR, true, false); final double[][] zValuesMirror = getDataAsNestedArray(sineSpectrogramMirror); final double[] vals3refMirror = new double[nFft]; System.arraycopy(sine.getValues(DIM_Y), 5 * step, vals3refMirror, 0, nFft - 32 - step); for (int i = 0; i < vals3refMirror.length - nFft + 32 + step; i++) { vals3refMirror[nFft - 32 - step + i] = sine.getValues(DIM_Y)[5 * step + nFft - 32 - step - i - 1]; } Apodization.Rectangular.apodize(vals2ref); fastFourierTrafo.realForward(vals3refMirror); final double[] vals3refMagMirror = SpectrumTools.computeMagnitudeSpectrum_dB(vals3refMirror, false); assertArrayEquals(zValuesMirror[5], vals3refMagMirror); ShortTimeFourierTransform.real(sine, sineSpectrogram, nFft, 2 * step, Apodization.Rectangular, Padding.MIRROR, true, false); assertArrayEquals(new int[] { nFft / 2, 3 }, sineSpectrogram.getShape()); ShortTimeFourierTransform.real(sine, sineSpectrogram, 2 * nFft, 2 * step, Apodization.Rectangular, Padding.MIRROR, true, false); assertArrayEquals(new int[] { nFft, 3 }, sineSpectrogram.getShape()); ShortTimeFourierTransform.real(new DoubleDataSet("empty"), sineSpectrogram, 2 * nFft, 2 * step, Apodization.Rectangular, Padding.MIRROR, true, false); assertArrayEquals(new int[] { 0, 0 }, sineSpectrogram.getShape()); final GridDataSet emptySpectrogram = ShortTimeFourierTransform.real(new DoubleDataSet("empty"), null, 2 * nFft, 2 * step, Apodization.Rectangular, Padding.MIRROR, true, false); assertArrayEquals(new int[] { 0, 0 }, emptySpectrogram.getShape()); assertThrows(IllegalArgumentException.class, () -> ShortTimeFourierTransform.real(new DataSetBuilder("illegal data set").setDimension(3).setInitalCapacity(3, 5, 7).build(), null, 8, 8, Apodization.Hann, Padding.ZERO, true, false)); }
public static GridDataSet real(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization, final Padding padding, final boolean dbScale, final boolean truncateDCNy) { AssertUtils.notNull("input", input); AssertUtils.gtThanZero("nFFT", nFFT); AssertUtils.gtThanZero("step", step); AssertUtils.notNull("apodization", apodization); AssertUtils.notNull("padding", padding); AssertUtils.gtOrEqual("input.getDimension()", 2, input.getDimension()); if (input.getDataCount() == 0) { if (output instanceof DoubleGridDataSet) { ((DoubleGridDataSet) output).clearData(); ((DoubleGridDataSet) output).clearMetaInfo(); return output; } return new DoubleGridDataSet("STFT(" + input.getName() + ")", false, new double[2][0], new double[0]); } final int nSamples = input.getDataCount(); final double dt = (input.get(DIM_X, nSamples - 1) - input.get(DIM_X, 0)) / nSamples; final double[] yData = input.getValues(DIM_Y); final double[] oldTimeAxis = output == null ? null : output.getValues(DIM_X); final double[] timeAxis = getTimeAxis(dt, nSamples, step, oldTimeAxis); final double[] oldFrequencyAxis = output == null ? null : output.getValues(DIM_Y); final double[] frequencyAxis = getFrequencyAxisReal(dt, nFFT, oldFrequencyAxis); final double[] oldAmplitudeData = output instanceof MultiDimDoubleDataSet ? output.getValues(DIM_Z) : null; final double[] amplitudeData = real(yData, oldAmplitudeData, nFFT, step, apodization, padding, dbScale, truncateDCNy); DoubleGridDataSet result; if (output instanceof DoubleGridDataSet) { result = (DoubleGridDataSet) output; } else { result = new DataSetBuilder("STFT(" + input.getName() + ")").setValues(DIM_X, frequencyAxis).setValues(DIM_Y, timeAxis).setValues(DIM_Z, amplitudeData).build(DoubleGridDataSet.class); } result.lock().writeLockGuard(() -> { if (oldTimeAxis != timeAxis || oldFrequencyAxis != frequencyAxis || oldAmplitudeData != amplitudeData) { result.set(false, new double[][] { frequencyAxis, timeAxis }, amplitudeData); } result.getMetaInfo().put("RealSTFT-nFFT", Integer.toString(nFFT)); result.getMetaInfo().put("RealSTFT-step", Integer.toString(step)); final String timeUnit = input.getAxisDescription(DIM_X).getUnit(); final String freqUnit = timeUnit.equals("s") ? "Hz" : "1/" + timeUnit; result.getAxisDescription(DIM_X).set("Frequency", freqUnit, frequencyAxis[0], frequencyAxis[frequencyAxis.length - 1]); result.getAxisDescription(DIM_Y).set("Time", timeUnit, timeAxis[0], timeAxis[timeAxis.length - 1]); result.getAxisDescription(DIM_Z).set("Magnitude", input.getAxisDescription(DIM_Y).getUnit()); result.recomputeLimits(DIM_Z); }); return result; }
ShortTimeFourierTransform { public static GridDataSet real(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization, final Padding padding, final boolean dbScale, final boolean truncateDCNy) { AssertUtils.notNull("input", input); AssertUtils.gtThanZero("nFFT", nFFT); AssertUtils.gtThanZero("step", step); AssertUtils.notNull("apodization", apodization); AssertUtils.notNull("padding", padding); AssertUtils.gtOrEqual("input.getDimension()", 2, input.getDimension()); if (input.getDataCount() == 0) { if (output instanceof DoubleGridDataSet) { ((DoubleGridDataSet) output).clearData(); ((DoubleGridDataSet) output).clearMetaInfo(); return output; } return new DoubleGridDataSet("STFT(" + input.getName() + ")", false, new double[2][0], new double[0]); } final int nSamples = input.getDataCount(); final double dt = (input.get(DIM_X, nSamples - 1) - input.get(DIM_X, 0)) / nSamples; final double[] yData = input.getValues(DIM_Y); final double[] oldTimeAxis = output == null ? null : output.getValues(DIM_X); final double[] timeAxis = getTimeAxis(dt, nSamples, step, oldTimeAxis); final double[] oldFrequencyAxis = output == null ? null : output.getValues(DIM_Y); final double[] frequencyAxis = getFrequencyAxisReal(dt, nFFT, oldFrequencyAxis); final double[] oldAmplitudeData = output instanceof MultiDimDoubleDataSet ? output.getValues(DIM_Z) : null; final double[] amplitudeData = real(yData, oldAmplitudeData, nFFT, step, apodization, padding, dbScale, truncateDCNy); DoubleGridDataSet result; if (output instanceof DoubleGridDataSet) { result = (DoubleGridDataSet) output; } else { result = new DataSetBuilder("STFT(" + input.getName() + ")").setValues(DIM_X, frequencyAxis).setValues(DIM_Y, timeAxis).setValues(DIM_Z, amplitudeData).build(DoubleGridDataSet.class); } result.lock().writeLockGuard(() -> { if (oldTimeAxis != timeAxis || oldFrequencyAxis != frequencyAxis || oldAmplitudeData != amplitudeData) { result.set(false, new double[][] { frequencyAxis, timeAxis }, amplitudeData); } result.getMetaInfo().put("RealSTFT-nFFT", Integer.toString(nFFT)); result.getMetaInfo().put("RealSTFT-step", Integer.toString(step)); final String timeUnit = input.getAxisDescription(DIM_X).getUnit(); final String freqUnit = timeUnit.equals("s") ? "Hz" : "1/" + timeUnit; result.getAxisDescription(DIM_X).set("Frequency", freqUnit, frequencyAxis[0], frequencyAxis[frequencyAxis.length - 1]); result.getAxisDescription(DIM_Y).set("Time", timeUnit, timeAxis[0], timeAxis[timeAxis.length - 1]); result.getAxisDescription(DIM_Z).set("Magnitude", input.getAxisDescription(DIM_Y).getUnit()); result.recomputeLimits(DIM_Z); }); return result; } }
ShortTimeFourierTransform { public static GridDataSet real(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization, final Padding padding, final boolean dbScale, final boolean truncateDCNy) { AssertUtils.notNull("input", input); AssertUtils.gtThanZero("nFFT", nFFT); AssertUtils.gtThanZero("step", step); AssertUtils.notNull("apodization", apodization); AssertUtils.notNull("padding", padding); AssertUtils.gtOrEqual("input.getDimension()", 2, input.getDimension()); if (input.getDataCount() == 0) { if (output instanceof DoubleGridDataSet) { ((DoubleGridDataSet) output).clearData(); ((DoubleGridDataSet) output).clearMetaInfo(); return output; } return new DoubleGridDataSet("STFT(" + input.getName() + ")", false, new double[2][0], new double[0]); } final int nSamples = input.getDataCount(); final double dt = (input.get(DIM_X, nSamples - 1) - input.get(DIM_X, 0)) / nSamples; final double[] yData = input.getValues(DIM_Y); final double[] oldTimeAxis = output == null ? null : output.getValues(DIM_X); final double[] timeAxis = getTimeAxis(dt, nSamples, step, oldTimeAxis); final double[] oldFrequencyAxis = output == null ? null : output.getValues(DIM_Y); final double[] frequencyAxis = getFrequencyAxisReal(dt, nFFT, oldFrequencyAxis); final double[] oldAmplitudeData = output instanceof MultiDimDoubleDataSet ? output.getValues(DIM_Z) : null; final double[] amplitudeData = real(yData, oldAmplitudeData, nFFT, step, apodization, padding, dbScale, truncateDCNy); DoubleGridDataSet result; if (output instanceof DoubleGridDataSet) { result = (DoubleGridDataSet) output; } else { result = new DataSetBuilder("STFT(" + input.getName() + ")").setValues(DIM_X, frequencyAxis).setValues(DIM_Y, timeAxis).setValues(DIM_Z, amplitudeData).build(DoubleGridDataSet.class); } result.lock().writeLockGuard(() -> { if (oldTimeAxis != timeAxis || oldFrequencyAxis != frequencyAxis || oldAmplitudeData != amplitudeData) { result.set(false, new double[][] { frequencyAxis, timeAxis }, amplitudeData); } result.getMetaInfo().put("RealSTFT-nFFT", Integer.toString(nFFT)); result.getMetaInfo().put("RealSTFT-step", Integer.toString(step)); final String timeUnit = input.getAxisDescription(DIM_X).getUnit(); final String freqUnit = timeUnit.equals("s") ? "Hz" : "1/" + timeUnit; result.getAxisDescription(DIM_X).set("Frequency", freqUnit, frequencyAxis[0], frequencyAxis[frequencyAxis.length - 1]); result.getAxisDescription(DIM_Y).set("Time", timeUnit, timeAxis[0], timeAxis[timeAxis.length - 1]); result.getAxisDescription(DIM_Z).set("Magnitude", input.getAxisDescription(DIM_Y).getUnit()); result.recomputeLimits(DIM_Z); }); return result; }  }
ShortTimeFourierTransform { public static GridDataSet real(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization, final Padding padding, final boolean dbScale, final boolean truncateDCNy) { AssertUtils.notNull("input", input); AssertUtils.gtThanZero("nFFT", nFFT); AssertUtils.gtThanZero("step", step); AssertUtils.notNull("apodization", apodization); AssertUtils.notNull("padding", padding); AssertUtils.gtOrEqual("input.getDimension()", 2, input.getDimension()); if (input.getDataCount() == 0) { if (output instanceof DoubleGridDataSet) { ((DoubleGridDataSet) output).clearData(); ((DoubleGridDataSet) output).clearMetaInfo(); return output; } return new DoubleGridDataSet("STFT(" + input.getName() + ")", false, new double[2][0], new double[0]); } final int nSamples = input.getDataCount(); final double dt = (input.get(DIM_X, nSamples - 1) - input.get(DIM_X, 0)) / nSamples; final double[] yData = input.getValues(DIM_Y); final double[] oldTimeAxis = output == null ? null : output.getValues(DIM_X); final double[] timeAxis = getTimeAxis(dt, nSamples, step, oldTimeAxis); final double[] oldFrequencyAxis = output == null ? null : output.getValues(DIM_Y); final double[] frequencyAxis = getFrequencyAxisReal(dt, nFFT, oldFrequencyAxis); final double[] oldAmplitudeData = output instanceof MultiDimDoubleDataSet ? output.getValues(DIM_Z) : null; final double[] amplitudeData = real(yData, oldAmplitudeData, nFFT, step, apodization, padding, dbScale, truncateDCNy); DoubleGridDataSet result; if (output instanceof DoubleGridDataSet) { result = (DoubleGridDataSet) output; } else { result = new DataSetBuilder("STFT(" + input.getName() + ")").setValues(DIM_X, frequencyAxis).setValues(DIM_Y, timeAxis).setValues(DIM_Z, amplitudeData).build(DoubleGridDataSet.class); } result.lock().writeLockGuard(() -> { if (oldTimeAxis != timeAxis || oldFrequencyAxis != frequencyAxis || oldAmplitudeData != amplitudeData) { result.set(false, new double[][] { frequencyAxis, timeAxis }, amplitudeData); } result.getMetaInfo().put("RealSTFT-nFFT", Integer.toString(nFFT)); result.getMetaInfo().put("RealSTFT-step", Integer.toString(step)); final String timeUnit = input.getAxisDescription(DIM_X).getUnit(); final String freqUnit = timeUnit.equals("s") ? "Hz" : "1/" + timeUnit; result.getAxisDescription(DIM_X).set("Frequency", freqUnit, frequencyAxis[0], frequencyAxis[frequencyAxis.length - 1]); result.getAxisDescription(DIM_Y).set("Time", timeUnit, timeAxis[0], timeAxis[timeAxis.length - 1]); result.getAxisDescription(DIM_Z).set("Magnitude", input.getAxisDescription(DIM_Y).getUnit()); result.recomputeLimits(DIM_Z); }); return result; }  static GridDataSet complex(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] complex(final double[] real, final double[] imag, final double[] output, final int nFFT, final int step,
            final Apodization apodization, final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] complex(final double[] complexInput, final double[] output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] getFrequencyAxisComplex(final double dt, final int nFFT, final double[] output); static double[] getFrequencyAxisReal(final double dt, final int nFFT, final double[] output); static double[] getTimeAxis(final double dt, final int nSamples, final int step, final double[] output); static GridDataSet real(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] real(final double[] input, final double[] output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy); }
ShortTimeFourierTransform { public static GridDataSet real(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization, final Padding padding, final boolean dbScale, final boolean truncateDCNy) { AssertUtils.notNull("input", input); AssertUtils.gtThanZero("nFFT", nFFT); AssertUtils.gtThanZero("step", step); AssertUtils.notNull("apodization", apodization); AssertUtils.notNull("padding", padding); AssertUtils.gtOrEqual("input.getDimension()", 2, input.getDimension()); if (input.getDataCount() == 0) { if (output instanceof DoubleGridDataSet) { ((DoubleGridDataSet) output).clearData(); ((DoubleGridDataSet) output).clearMetaInfo(); return output; } return new DoubleGridDataSet("STFT(" + input.getName() + ")", false, new double[2][0], new double[0]); } final int nSamples = input.getDataCount(); final double dt = (input.get(DIM_X, nSamples - 1) - input.get(DIM_X, 0)) / nSamples; final double[] yData = input.getValues(DIM_Y); final double[] oldTimeAxis = output == null ? null : output.getValues(DIM_X); final double[] timeAxis = getTimeAxis(dt, nSamples, step, oldTimeAxis); final double[] oldFrequencyAxis = output == null ? null : output.getValues(DIM_Y); final double[] frequencyAxis = getFrequencyAxisReal(dt, nFFT, oldFrequencyAxis); final double[] oldAmplitudeData = output instanceof MultiDimDoubleDataSet ? output.getValues(DIM_Z) : null; final double[] amplitudeData = real(yData, oldAmplitudeData, nFFT, step, apodization, padding, dbScale, truncateDCNy); DoubleGridDataSet result; if (output instanceof DoubleGridDataSet) { result = (DoubleGridDataSet) output; } else { result = new DataSetBuilder("STFT(" + input.getName() + ")").setValues(DIM_X, frequencyAxis).setValues(DIM_Y, timeAxis).setValues(DIM_Z, amplitudeData).build(DoubleGridDataSet.class); } result.lock().writeLockGuard(() -> { if (oldTimeAxis != timeAxis || oldFrequencyAxis != frequencyAxis || oldAmplitudeData != amplitudeData) { result.set(false, new double[][] { frequencyAxis, timeAxis }, amplitudeData); } result.getMetaInfo().put("RealSTFT-nFFT", Integer.toString(nFFT)); result.getMetaInfo().put("RealSTFT-step", Integer.toString(step)); final String timeUnit = input.getAxisDescription(DIM_X).getUnit(); final String freqUnit = timeUnit.equals("s") ? "Hz" : "1/" + timeUnit; result.getAxisDescription(DIM_X).set("Frequency", freqUnit, frequencyAxis[0], frequencyAxis[frequencyAxis.length - 1]); result.getAxisDescription(DIM_Y).set("Time", timeUnit, timeAxis[0], timeAxis[timeAxis.length - 1]); result.getAxisDescription(DIM_Z).set("Magnitude", input.getAxisDescription(DIM_Y).getUnit()); result.recomputeLimits(DIM_Z); }); return result; }  static GridDataSet complex(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] complex(final double[] real, final double[] imag, final double[] output, final int nFFT, final int step,
            final Apodization apodization, final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] complex(final double[] complexInput, final double[] output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] getFrequencyAxisComplex(final double dt, final int nFFT, final double[] output); static double[] getFrequencyAxisReal(final double dt, final int nFFT, final double[] output); static double[] getTimeAxis(final double dt, final int nSamples, final int step, final double[] output); static GridDataSet real(final DataSet input, final GridDataSet output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy); static double[] real(final double[] input, final double[] output, final int nFFT, final int step, final Apodization apodization,
            final Padding padding, final boolean dbScale, final boolean truncateDCNy);  }