circuitjs1 icon indicating copy to clipboard operation
circuitjs1 copied to clipboard

FFT does not use a window function

Open mordae opened this issue 1 year ago • 3 comments

Hi, I was taking the fact that the FFT always "jumps around" as a harsh reality of life, but I've just realized it's doing that only because we are not windowing the data. Can we please add a window function to the FFT so that it stabilizes and one can actually read and compare it?

I've tested the triangle window and it retains too much of the original jiggling, cosine window looks pretty good as does Hann window.

Cosine window patch:

diff --git a/src/com/lushprojects/circuitjs1/client/FFT.java b/src/com/lushprojects/circuitjs1/client/FFT>
index e9243a3..84aae03 100644
--- a/src/com/lushprojects/circuitjs1/client/FFT.java
+++ b/src/com/lushprojects/circuitjs1/client/FFT.java
@@ -24,6 +24,7 @@ class FFT {
     private int bits;
     private double[] cosTable;
     private double[] sinTable;
+    private double[] winTable;
 
     FFT(int n) {
       size = n;
@@ -35,6 +36,15 @@ class FFT {
         cosTable[i] = Math.cos(dtheta * i);
         sinTable[i] = Math.sin(dtheta * i);
       }
+
+      /* Scale the sine window up for unity gain. */
+      double gainCompensation = 1.5707963267961471;
+
+      winTable = new double[size];
+      for (int i = 0; i < winTable.length; i++) {
+        double weight = Math.sin(i * Math.PI / winTable.length);
+        winTable[i] = weight * gainCompensation;
+      }
     }
 
     /*
@@ -47,6 +57,11 @@ class FFT {
      * http://cnx.rice.edu/content/m12016/latest/
      */
     void fft(double[] real, double[] imag) {
+        for (int i = 0; i < real.length; i++) {
+          real[i] *= winTable[i];
+          imag[i] *= winTable[i];
+        }
+
         int j = 0;
         int n2 = real.length / 2;
         for (int i=1; i < real.length - 1; i++) {

Although it might be interesting to add window function selection to scope settings. Let me know what you think. I'll draft an actual pull request then, @pfalstad.

mordae avatar Aug 07 '24 12:08 mordae

Interesting, but I guess amplitude should be corrected after windowing see : https://community.sw.siemens.com/s/article/window-correction-factors

cedricp avatar Aug 07 '24 12:08 cedricp

Yeah, you are obviously right. :sweat_smile: I guess multiplying taps with reciprocal of the average original tap gain should do the trick.

mordae avatar Aug 07 '24 20:08 mordae

Love this, thanks! I don't need a pull request.

pfalstad avatar Oct 27 '24 21:10 pfalstad