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.
The output from this test program is:
I believe the error is the comparison operator used in the WHILE statement shown below
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: