Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ShortTimeFourierTransform: Amplitude change with zero padding #607

Open
Vado101 opened this issue Aug 24, 2023 · 0 comments
Open

ShortTimeFourierTransform: Amplitude change with zero padding #607

Vado101 opened this issue Aug 24, 2023 · 0 comments

Comments

@Vado101
Copy link

Vado101 commented Aug 24, 2023

Hi! I'm trying make spectrum analyzer using chart-fx library. When I use the real method of the chartfx-math/src/main/java/io/fair_acc/math/spectra/ShortTimeFourierTransform.java class with the FFT size greater than the data length and padding with zeros, then when applying different window functions, the signal amplitude noticeably different.
I tried to implement my real method, where I placed the application of the window function above the code in which the padding with zeros occurs, and also calculated the amplitude compensation. In this case, when applying different window functions, the signal level is approximately the same.
Please tell me if the real method works correctly and if so, why then the amplitude changes with different window functions.

Below is my modified real method

public static double[] real(double[] input, double[] output, int nFFT, int step, Apodization apodization,
                                ShortTimeFourierTransform.Padding padding, boolean dbScale, boolean truncateDCNy) {
      int nT = ceilDiv(input.length, step);
      double[] amplitudeData = output != null && output.length == nFFT / 2 * nT ? output : new double[nFFT / 2 * nT];
      double[] currentMagnitudeData = DoubleArrayCache.getInstance().getArray(nFFT / 2);
      DoubleFFT_1D fastFourierTransform = new DoubleFFT_1D((long)nFFT);
      double[] raw = DoubleArrayCache.getInstance().getArrayExact(nFFT);

      double[] temp = DoubleArrayCache.getInstance().getArrayExact(input.length);
      System.arraycopy(input, 0, temp, 0, temp.length);

      for(int i = 0; i < nT; ++i) {
          int offset = i * step;
          int validLength = temp.length - offset;
          if (validLength >= nFFT) {
              System.arraycopy(temp, offset, raw, 0, nFFT);
              apodization.apodize(raw);
          } else {
              apodization.apodize(temp);
              System.arraycopy(temp, offset, raw, 0, validLength);

              label32:
              switch(padding) {
                  case MIRROR:
                      int j = validLength;

                      while(true) {
                          if (j >= raw.length) {
                              break label32;
                          }

                          raw[j] = temp[temp.length - j + validLength - 1];
                          ++j;
                      }
                  case ZERO:
                      Arrays.fill(raw, validLength, raw.length, 0.0D);
                      break;
                  case ZOH:
                  default:
                      Arrays.fill(raw, validLength, raw.length, temp[temp.length - 1]);
              }
          }

          fastFourierTransform.realForward(raw);
          double k = (double) nFFT / (double) validLength;

          if (dbScale) {
              SpectrumTools.computeMagnitudeSpectrum_dB(raw, 0, nFFT, currentMagnitudeData, 0, truncateDCNy);
              k = Units.conversionLogUnits(k, true);

              // Amplitude compensation
              if (padding == ShortTimeFourierTransform.Padding.ZERO && nFFT > validLength) {
                  for (int j = 0; j < currentMagnitudeData.length; ++j) {
                      currentMagnitudeData[j] += k;
                  }
              }
          } else {
              SpectrumTools.computeMagnitudeSpectrum(raw, 0, nFFT, currentMagnitudeData, 0, truncateDCNy);

              // Amplitude compensation
              if (padding == ShortTimeFourierTransform.Padding.ZERO && nFFT > validLength) {
                  for (int j = 0; j < currentMagnitudeData.length; ++j) {
                      currentMagnitudeData[j] *= k;
                  }
              }
          }

          System.arraycopy(currentMagnitudeData, 0, amplitudeData, i * nFFT / 2, nFFT / 2);
      }

      DoubleArrayCache.getInstance().add(currentMagnitudeData);
      DoubleArrayCache.getInstance().add(raw);

      return amplitudeData;
 }

public static double conversionLogUnits(final double value, final boolean amplitude) {
    if (value == 0.0) {
        return value;
    }

    double temp = Math.log10(value);

    if (amplitude) {
        return 20.0 * temp;
    } else {
        return 10.0 * temp;
    }
}
@wirew0rm wirew0rm changed the title Amplitude change with zero padding ShortTimeRourierTransform: Amplitude change with zero padding Sep 29, 2023
@wirew0rm wirew0rm changed the title ShortTimeRourierTransform: Amplitude change with zero padding ShortTimeFourierTransform: Amplitude change with zero padding Sep 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant