Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 3 of 3

Thread: Audio Library - Possible Error in analyze_fft1024.h - read(binFirst, binLast)

  1. #1

    Audio Library - Possible Error in analyze_fft1024.h - read(binFirst, binLast)

    It appears to me that the fft.read(binFirst, binLast) function does add the energy in binLast to the sum.

    Perhaps I misunderstood how to apply the function but I've read most of the examples using this function and it appears to me that the common understanding of function's usage expects that all of the bins from binFirst to binLast (inclusive) would be summed together.

    Below is a self contained program that demonstrates the problem.

    This program steps a sineWaveGenerator through several of the fft bins.

    The bins are then read using fft.read(binFirst, binLast) and the resulting sum is displayed.

    You can see that every binLast is not included.

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioSynthWaveformSine sineWaveGen;
    AudioAnalyzeFFT1024 fft;
    AudioOutputAnalog dac1;
    AudioConnection patchCord1(sineWaveGen, fft);
    AudioConnection patchCord2(sineWaveGen, dac1);
    // GUItool: end automatically generated code
    
    // An array to hold the 16 frequency bands
    float level[16];
    
    void setup() {
      pinMode(LED_BUILTIN, OUTPUT);
      delay(2000);
      Serial.println("Begin Setup");
      Serial.printf("F_BUS = %d\n", F_BUS);;
      int sampleRate = F_BUS / PDB0_MOD + 1;
      Serial.printf("Sample Rate = %d\n", sampleRate );
      Serial.printf("Bin Size = %d\n", sampleRate / 1024);
      delay(2000);
    
      // Audio requires memory to work.
      AudioMemory(12);
    
      // Configure the window algorithm to use              // - relative bin response to sine wave input -
      //fft.windowFunction(AudioWindowTukey1024);           // 0.04 0.10 0.18 0.63 0.18 0.10 0.03 = 1.26
      //fft.windowFunction(AudioWindowWelch1024);           // 0.02 0.04 0.17 0.56 0.17 0.04 0.02 = 1.02
      //fft.windowFunction(AudioWindowCosine1024);          // 0.02 0.04 0.18 0.53 0.18 0.04 0.02 = 1.01
      fft.windowFunction(AudioWindowHamming1024);           //           0.19 0.45 0.19           = 0.83
      //fft.windowFunction(AudioWindowHanning1024);         //           0.21 0.42 0.21           = 0.84
      //fft.windowFunction(AudioWindowBartlett1024);        //      0.02 0.17 0.42 0.17 0.02      = 0.80
      //fft.windowFunction(AudioWindowBlackman1024);        //      0.03 0.21 0.35 0.21 0.03      = 0.83
      //fft.windowFunction(AudioWindowBlackmanHarris1024);  //      0.06 0.20 0.30 0.20 0.06      = 0.82
      //fft.windowFunction(AudioWindowBlackmanNuttall1024); //      0.06 0.20 0.30 0.20 0.06      = 0.82
      //fft.windowFunction(AudioWindowNuttall1024);         //      0.06 0.20 0.30 0.20 0.06      = 0.82
      //fft.windowFunction(AudioWindowFlattop1024);         // 0.04 0.12 0.17 0.18 0.17 0.12 0.04 = 0.82
    
      // init the generator freq and level
      sineWaveGen.frequency(100.00);
      sineWaveGen.amplitude(1.0);
      Serial.println("End Setup");  
    }
    
    void loop() {
      float n;
      int i, j;
    
      for (j = 1; j < 18; j++) {
        sineWaveGen.frequency(j * 43); // step the generator through the first 17 fft bins
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN)); // Toggle the LED 
        Serial.printf("\n  --  Sinewave Generator set to %d Hz\n", j * 43);
        delay(200); // let the frequency step transits settle out -- send "pure" sine wave to fft
        if (fft.available()) {
          // each time new FFT data is available
          // print it all to the Arduino Serial Monitor
          Serial.print("FFT bin ");
          for (i = 0; i < 511; i++) {
            n = fft.read(i);
            // print only the bins with data for this sine wave binning test
            if (n >= 0.01) {
              Serial.print(i);
              Serial.print(" = ");
              Serial.print(n);
              Serial.print("    ");
            }
          }
          Serial.println();
    
          // bin size = 44,100 Hz / 1024  or 43.08 Hz per bin
          // to keep things simple - only sum the first few fft bins into groups of 3 or 43+43+43 or 129Hz buckets
          level[0] = fft.read(0);     // FFT "0Hz"     -> "DC"
          level[1] = fft.read(1, 3);
          level[2] = fft.read(4, 6);
          level[3] = fft.read(7, 9);
          level[4] = fft.read(10, 12);
          level[5] = fft.read(13, 15);
          level[6] = fft.read(16, 18);
    
          Serial.print(level[0]);
          Serial.print(" ");
          Serial.print(level[1]);
          Serial.print(" ");
          Serial.print(level[2]);
          Serial.print(" ");
          Serial.print(level[3]);
          Serial.print(" ");
          Serial.print(level[4]);
          Serial.print(" ");
          Serial.print(level[5]);
          Serial.print(" ");
          Serial.print(level[6]);
          Serial.println();
          if ((j % 3) == 0) {
            Serial.printf("NOTE - the energy in fft bin %d is NOT in the sum for bucket %d\n", j, j / 3);
          }
        }
      }
    }
    The output from this test program is:

    Code:
      --  Sinewave Generator set to 43 Hz
    FFT bin 0 = 0.05    1 = 0.54    2 = 0.23    
    0.05 0.77 0.00 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 86 Hz
    FFT bin 1 = 0.23    2 = 0.54    3 = 0.23    
    0.00 0.77 0.00 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 129 Hz
    FFT bin 2 = 0.23    3 = 0.54    4 = 0.23    
    0.00 0.23 0.23 0.00 0.00 0.00 0.00
    NOTE - the energy in fft bin 3 is NOT in the sum for bucket 1
    
      --  Sinewave Generator set to 172 Hz
    FFT bin 3 = 0.23    4 = 0.54    5 = 0.23    
    0.00 0.00 0.77 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 215 Hz
    FFT bin 4 = 0.23    5 = 0.54    6 = 0.23    
    0.00 0.00 0.77 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 258 Hz
    FFT bin 5 = 0.24    6 = 0.54    7 = 0.23    
    0.00 0.00 0.24 0.23 0.00 0.00 0.00
    NOTE - the energy in fft bin 6 is NOT in the sum for bucket 2
    
      --  Sinewave Generator set to 301 Hz
    FFT bin 6 = 0.24    7 = 0.54    8 = 0.22    
    0.00 0.00 0.00 0.76 0.00 0.00 0.00
    
      --  Sinewave Generator set to 344 Hz
    FFT bin 7 = 0.24    8 = 0.54    9 = 0.22    
    0.00 0.00 0.00 0.78 0.00 0.00 0.00
    
      --  Sinewave Generator set to 387 Hz
    FFT bin 8 = 0.24    9 = 0.54    10 = 0.22    
    0.00 0.00 0.00 0.24 0.22 0.00 0.00
    NOTE - the energy in fft bin 9 is NOT in the sum for bucket 3
    I believe the error is the comparison operator used in the WHILE statement shown below

    Code:
    // code snippet from analyze_fft1024.h in the audio library
    
    	float read(unsigned int binFirst, unsigned int binLast) {
    		if (binFirst > binLast) {
    			unsigned int tmp = binLast;
    			binLast = binFirst;
    			binFirst = tmp;
    		}
    		if (binFirst > 511) return 0.0;
    		if (binLast > 511) binLast = 511;
    		uint32_t sum = 0;
    		do {
    			sum += output[binFirst++];
    		} while (binFirst < binLast);
    		return (float)sum * (1.0 / 16384.0);
    Last edited by drmartin; 10-31-2015 at 03:56 AM.

  2. #2
    Below is a program version that demonstrates the "correct" bin summing action expected when using fft.read(binFirst, binLast)

    This program was simply "patched" to compensate for the missing binLast .. of course a proper fix would be to correct the underlying library function but this sample program demonstrates what the output of a "correct" bin sum should be.

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioSynthWaveformSine sineWaveGen;
    AudioAnalyzeFFT1024 fft;
    AudioOutputAnalog dac1;
    AudioConnection patchCord1(sineWaveGen, fft);
    AudioConnection patchCord2(sineWaveGen, dac1);
    // GUItool: end automatically generated code
    
    // An array to hold the 16 frequency bands
    float level[16];
    
    void setup() {
      pinMode(LED_BUILTIN, OUTPUT);
      delay(2000);
      Serial.println("Begin Setup - This version Patched to correct missing lastBin");
      Serial.printf("F_BUS = %d\n", F_BUS);;
      int sampleRate = F_BUS / PDB0_MOD + 1;
      Serial.printf("Sample Rate = %d\n", sampleRate );
      Serial.printf("Bin Size = %d\n", sampleRate / 1024);
      delay(2000);
    
      // Audio requires memory to work.
      AudioMemory(12);
    
      // Configure the window algorithm to use              // - relative bin response to sine wave input -
      //fft.windowFunction(AudioWindowTukey1024);           // 0.04 0.10 0.18 0.63 0.18 0.10 0.03 = 1.26
      //fft.windowFunction(AudioWindowWelch1024);           // 0.02 0.04 0.17 0.56 0.17 0.04 0.02 = 1.02
      //fft.windowFunction(AudioWindowCosine1024);          // 0.02 0.04 0.18 0.53 0.18 0.04 0.02 = 1.01
      fft.windowFunction(AudioWindowHamming1024);           //           0.19 0.45 0.19           = 0.83
      //fft.windowFunction(AudioWindowHanning1024);         //           0.21 0.42 0.21           = 0.84
      //fft.windowFunction(AudioWindowBartlett1024);        //      0.02 0.17 0.42 0.17 0.02      = 0.80
      //fft.windowFunction(AudioWindowBlackman1024);        //      0.03 0.21 0.35 0.21 0.03      = 0.83
      //fft.windowFunction(AudioWindowBlackmanHarris1024);  //      0.06 0.20 0.30 0.20 0.06      = 0.82
      //fft.windowFunction(AudioWindowBlackmanNuttall1024); //      0.06 0.20 0.30 0.20 0.06      = 0.82
      //fft.windowFunction(AudioWindowNuttall1024);         //      0.06 0.20 0.30 0.20 0.06      = 0.82
      //fft.windowFunction(AudioWindowFlattop1024);         // 0.04 0.12 0.17 0.18 0.17 0.12 0.04 = 0.82
    
      // init the generator freq and level
      sineWaveGen.frequency(100.00);
      sineWaveGen.amplitude(1.0);
      Serial.println("End Setup");
    }
    
    void loop() {
      float n;
      int i, j;
    
      for (j = 1; j < 18; j++) {
        sineWaveGen.frequency(j * 43); // step the generator through the first 17 fft bins
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN)); // Toggle the LED
        Serial.printf("\n  --  Sinewave Generator set to %d Hz\n", j * 43);
        delay(200); // let the frequency step transits settle out -- send "pure" sine wave to fft
        if (fft.available()) {
          // each time new FFT data is available
          // print it all to the Arduino Serial Monitor
          Serial.print("FFT bin ");
          for (i = 0; i < 511; i++) {
            n = fft.read(i);
            // print only the bins with data for this sine wave binning test
            if (n >= 0.01) {
              Serial.print(i);
              Serial.print(" = ");
              Serial.print(n);
              Serial.print("    ");
            }
          }
          Serial.println();
    
          // bin size = 44,100 Hz / 1024  or 43.08 Hz per bin
          // to keep things simple - only sum the first few fft bins into groups of 3 or 43+43+43 or 129Hz buckets
          level[0] = fft.read(0);     // FFT "0Hz"     -> "DC"
          level[1] = fft.read(1, 3 + 1); // +1 = Patch to compensate for missing lastBin
          level[2] = fft.read(4, 6 + 1); // +1 = Patch to compensate for missing lastBin
          level[3] = fft.read(7, 9 + 1); // +1 = Patch to compensate for missing lastBin
          level[4] = fft.read(10, 12 + 1); // +1 = Patch to compensate for missing lastBin
          level[5] = fft.read(13, 15 + 1); // +1 = Patch to compensate for missing lastBin
          level[6] = fft.read(16, 18 + 1); // +1 = Patch to compensate for missing lastBin
    
          Serial.print(level[0]);
          Serial.print(" ");
          Serial.print(level[1]);
          Serial.print(" ");
          Serial.print(level[2]);
          Serial.print(" ");
          Serial.print(level[3]);
          Serial.print(" ");
          Serial.print(level[4]);
          Serial.print(" ");
          Serial.print(level[5]);
          Serial.print(" ");
          Serial.print(level[6]);
          Serial.println();
        }
      }
    }
    The "correct" program output is

    Code:
    Begin Setup - This version Patched to correct missing lastBin
    F_BUS = 48000000
    Sample Rate = 44159
    Bin Size = 43
    End Setup
    
      --  Sinewave Generator set to 43 Hz
    FFT bin 0 = 0.05    1 = 0.54    2 = 0.23    
    0.05 0.77 0.00 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 86 Hz
    FFT bin 1 = 0.23    2 = 0.54    3 = 0.23    
    0.00 1.00 0.00 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 129 Hz
    FFT bin 2 = 0.23    3 = 0.54    4 = 0.23    
    0.00 0.77 0.23 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 172 Hz
    FFT bin 3 = 0.23    4 = 0.54    5 = 0.23    
    0.00 0.23 0.77 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 215 Hz
    FFT bin 4 = 0.23    5 = 0.54    6 = 0.23    
    0.00 0.00 1.00 0.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 258 Hz
    FFT bin 5 = 0.24    6 = 0.54    7 = 0.23    
    0.00 0.00 0.77 0.23 0.00 0.00 0.00
    
      --  Sinewave Generator set to 301 Hz
    FFT bin 6 = 0.24    7 = 0.54    8 = 0.22    
    0.00 0.00 0.24 0.76 0.00 0.00 0.00
    
      --  Sinewave Generator set to 344 Hz
    FFT bin 7 = 0.24    8 = 0.54    9 = 0.22    
    0.00 0.00 0.00 1.00 0.00 0.00 0.00
    
      --  Sinewave Generator set to 387 Hz
    FFT bin 8 = 0.24    9 = 0.54    10 = 0.22    
    0.00 0.00 0.00 0.78 0.22 0.00 0.00
    
      --  Sinewave Generator set to 430 Hz
    FFT bin 9 = 0.24    10 = 0.54    11 = 0.22    
    0.00 0.00 0.00 0.24 0.76 0.00 0.00
    
      --  Sinewave Generator set to 473 Hz
    FFT bin 10 = 0.24    11 = 0.54    12 = 0.22    
    0.00 0.00 0.00 0.00 1.00 0.00 0.00
    
      --  Sinewave Generator set to 516 Hz
    FFT bin 11 = 0.24    12 = 0.54    13 = 0.22    
    0.00 0.00 0.00 0.00 0.78 0.22 0.00
    
      --  Sinewave Generator set to 559 Hz
    FFT bin 12 = 0.24    13 = 0.54    14 = 0.22    
    0.00 0.00 0.00 0.00 0.24 0.76 0.00
    
      --  Sinewave Generator set to 602 Hz
    FFT bin 13 = 0.24    14 = 0.54    15 = 0.22    
    0.00 0.00 0.00 0.00 0.00 1.00 0.00
    Last edited by drmartin; 10-31-2015 at 03:55 AM.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    26,561
    Thanks!

    I committed a fix for this issue last week, shortly before the 1.26 release.

    https://github.com/PaulStoffregen/Au...d51ac829fa19c6

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •