You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OpenAudio_ArduinoLibrary/examples/TestFFT1024/TestFFT1024.ino

287 lines
9.5 KiB

#if 0
#include "Arduino.h"
#include "AudioStream_F32.h"
#include "arm_math.h"
#include "mathDSP_F32.h"
#if defined(__IMXRT1062__)
#include "arm_const_structs.h"
#endif
#define NFFT 1024
#define NFFT_D2 NFFT/2
#define FFT_PI 3.14159265359f
#define PI2 2.0f*FFT_PI
void setup(void) {
float x[NFFT]; // Real DFT input
float Xre[NFFT], Xim[NFFT]; // DFT of x
float P[NFFT]; // power spectrum of x
float kf, nf;
float fft_buffer[2*NFFT]; // 2 is fo CMSIS FFT
float sinN[NFFT_D2];
float cosN[NFFT_D2];
uint32_t tt;
// Instantiate FFT, T4.x ONLY
arm_cfft_instance_f32 Sfft;
Sfft = arm_cfft_sR_f32_len1024;
// Instantiate FFT, T4.x ONLY
arm_cfft_instance_f32 Sfft_128;
Sfft_128 = arm_cfft_sR_f32_len512;
Serial.begin(300); // Any speed works
delay(1000);
// Factors for using half size complex FFT
for(int n=0; n<NFFT_D2; n++) {
sinN[n] = sinf(FFT_PI*((float)n)/((float)NFFT_D2));
cosN[n] = cosf(FFT_PI*((float)n)/((float)NFFT_D2));
}
// The signal, a sine wave that fits integer number (2 here) of times
Serial.println("The input waveform, NFFT points");
for (int n=0; n<NFFT; n++) {
x[n] = sinf(5.0f*FFT_PI*((float)n)/((float)NFFT_D2));
Serial.println(x[n], 8);
}
Serial.println();
Serial.println("The DFT by full NxN DFT, k, Real, Imag, Power");
// Calculate DFT of x[n] with NFFT point DFT
for (int k=0 ; k<NFFT ; ++k) {
kf = (float)k;
// Real part of X[k]
Xre[k] = 0.0f;
Xim[k] = 0.0f;
for (int n=0 ; n<NFFT ; ++n) {
nf = (float)n;
Xre[k] += x[n] * cos(nf * kf * PI2 / ((float)NFFT));
Xim[k] -= x[n] * sin(nf * kf * PI2 / ((float)NFFT));
}
// Power at kth frequency bin
P[k] = 10.0f*log10f(Xre[k]*Xre[k] + Xim[k]*Xim[k]);
Serial.print(k); Serial.print(",");
Serial.print(Xre[k],8); Serial.print(",");
Serial.print(Xim[k],8); Serial.print(",");
Serial.println(P[k],3);
}
Serial.println("And now the same thing with FFT size NFFT/2");
for (int k = 0; k < NFFT_D2; k++) { // For each output element
kf = (float)k;
float sumreal = 0;
float sumimag = 0;
for (int n = 0; n < NFFT_D2; n++) { // For each input element
nf = (float)n;
float angle = PI2 * nf * kf / ((float)NFFT_D2);
sumreal += x[2*n] * cos(angle) + x[2*n+1] * sin(angle);
sumimag += -x[2*n] * sin(angle) + x[2*n+1] * cos(angle);
}
Xre[k] = sumreal;
Xim[k] = sumimag;
}
// Rearrange the outputs to look like the FFT
for(int k=0; k<NFFT_D2; k++) {
fft_buffer[2*k] = Xre[k];
fft_buffer[2*k+1] = Xim[k];
}
// Now the post FT processing for using half-length transform
Xre[0] = 0.0f;
for(int n=0; n<NFFT; n++)
Xre[0] += x[n]/((float)NFFT); // DC real
Xim[0] = 0.0f; // DC Imag
P[0] = 10.0f*log10f(Xre[0]*Xre[0]);
// And the non-DC values
for(int i=1; i<NFFT_D2; i++) {
float rns = 0.5f*(fft_buffer[2*i] + fft_buffer[NFFT-2*i]);
float ins = 0.5f*(fft_buffer[2*i+1] + fft_buffer[NFFT-2*i+1]);
float rnd = 0.5f*(fft_buffer[2*i] - fft_buffer[NFFT-2*i]);
float ind = 0.5f*(fft_buffer[2*i+1] - fft_buffer[NFFT-2*i+1]);
Xre[i] = rns + cosN[i]*ins - sinN[i]*rnd;
Xim[i] = ind - sinN[i]*ins - cosN[i]*rnd;
P[i] = 10.0f*log10f(Xre[i]*Xre[i] + Xim[i]*Xim[i]);
}
for(int k=0; k<NFFT_D2; k++) {
Serial.print(k); Serial.print(",");
Serial.print(Xre[k],8); Serial.print(",");
Serial.print(Xim[k],8); Serial.print(",");
Serial.println(P[k],3);
}
Serial.println();
// And the same data with the CMSIS FFT
Serial.println("And now the same thing with CMSIS FFT size NFFT, 0.0 input for imag");
// Teensyduino core for T4.x supports arm_cfft_f32
// arm_cfft_f32 (const arm_cfft_instance_f32 *S, float32_t *p1, uint8_t ifftFlag, uint8_t bitReverseFlag)
for(int k=0; k<NFFT; k++) {
fft_buffer[2*k] = x[k];
fft_buffer[2*k+1] = 0.0f;
}
tt = micros();
arm_cfft_f32 (&Sfft, fft_buffer, 0, 1);
Serial.print("NFFT length FFT uSec = ");
Serial.println(micros()-tt);
for (int i=0; i < NFFT; i++) {
float magsq = fft_buffer[2*i]*fft_buffer[2*i] + fft_buffer[2*i+1]*fft_buffer[2*i+1];
Serial.print(i); Serial.print(",");
// Serial.print(Xre[k],8); Serial.print(",");
// Serial.print(Xim[k],8); Serial.print(",");
Serial.println(10.0f*log10f(magsq), 3);
}
// And the same data with the CMSIS FFT of size NFFT/2 and interleaved Trig sorting
// Time: for NFFT=256, this method is 18 uSec, down from 23 uSec using 256 length
// and 0's in the imag inputs. Memory use is about half and accuracy is the same.
Serial.println("And now with CMSIS FFT size NFFT/2, 0.0 input for imag");
// Teensyduino core for T4.x supports arm_cfft_f32
// arm_cfft_f32 (const arm_cfft_instance_f32 *S, float32_t *p1, uint8_t ifftFlag, uint8_t bitReverseFlag)
for(int k=0; k<NFFT; k++) {
fft_buffer[k] = x[k];
}
arm_cfft_f32 (&Sfft_128, fft_buffer, 0, 1);
// Now the post FT processing for using half-length transform
Xre[0] = 0.0f;
for(int n=0; n<NFFT; n++)
Xre[0] += x[n]/((float)NFFT); // DC real
Xim[0] = 0.0f; // DC Imag
P[0] = 10.0f*log10f(Xre[0]*Xre[0]);
// And the non-DC values
for(int i=1; i<NFFT_D2; i++) {
float rns = 0.5f*(fft_buffer[2*i] + fft_buffer[NFFT-2*i]);
float ins = 0.5f*(fft_buffer[2*i+1] + fft_buffer[NFFT-2*i+1]);
float rnd = 0.5f*(fft_buffer[2*i] - fft_buffer[NFFT-2*i]);
float ind = 0.5f*(fft_buffer[2*i+1] - fft_buffer[NFFT-2*i+1]);
Xre[i] = rns + cosN[i]*ins - sinN[i]*rnd;
Xim[i] = ind - sinN[i]*ins - cosN[i]*rnd;
P[i] = 10.0f*log10f(Xre[i]*Xre[i] + Xim[i]*Xim[i]);
}
for(int k=0; k<NFFT_D2; k++) {
Serial.print(k); Serial.print(",");
Serial.print(Xre[k],8); Serial.print(",");
Serial.print(Xim[k],8); Serial.print(",");
Serial.println(P[k],3);
}
Serial.println();
}
void loop(void) {
}
#endif
// *****************************************************************
// *****************************************************************
// TestFFT1024.ino Bob Larkin W7PUA
// Started from PJRC Teensy Examples/Audio/Analysis/FFT
//
// Compute a 1024 point Fast Fourier Transform (spectrum analysis)
// on audio connected to the Left Line-In pin. By changing code,
// a synthetic sine wave can be input instead.
//
// The power output from 512 frequency analysis bins are printed to
// the Arduino Serial Monitor. The format is selectable.
// Output power averaging is an option
//
// T4.0: Uses 11.5% processor and 9 F32 memory blocks, both max.
//
// This example code is in the public domain.
#include <Audio.h>
#include "OpenAudio_ArduinoLibrary.h"
// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
// AudioInputI2S_F32 audioInput; // audio shield: mic or line-in
AudioSynthSineCosine_F32 sinewave;
AudioAnalyzeFFT1024_F32 myFFT;
AudioOutputI2S_F32 audioOutput; // audio shield: headphones & line-out NU
// Connect either the live input or synthesized sine wave
// AudioConnection_F32 patchCord1(audioInput, 0, myFFT, 0);
AudioConnection_F32 patchCord1(sinewave, 0, myFFT, 0);
AudioControlSGTL5000 audioShield;
float xxx[1024];
uint32_t ct = 0;
uint32_t count = 0;
void setup() {
Serial.begin(300); // Any speed works
delay(1000);
AudioMemory_F32(20);
// Enable the audio shield and set the output volume.
audioShield.enable();
audioShield.inputSelect(AUDIO_INPUT_LINEIN);
// Create a synthetic sine wave, for testing
// To use this, edit the connections above
// sinewave.frequency(1033.99f); // Bin 24 T3.x
// sinewave.frequency(1033.59375f); // Bin 24 T4.x at 44100
// sinewave.frequency(1055.0f); // Bin 24.5, demonstrates windowing
// Or some random frequency:
sinewave.frequency(1234.5f);
sinewave.amplitude(1.0f);
// Set windowing function
// myFFT.windowFunction(AudioWindowNone);
// myFFT.windowFunction(AudioWindowHanning1024); // default
// The next Kaiser window needs a dB peak sidelobe number
// myFFT.windowFunction(AudioWindowKaiser1024, 70.0f);
myFFT.windowFunction(AudioWindowBlackmanHarris1024);
// To print the window function:
// float* pw=myFFT.getWindow();
// for(int jj=0; jj<1024; jj++)
// Serial.println(*pw++, 6);
myFFT.setNAverage(1);
myFFT.setOutputType(FFT_DBFS); // FFT_RMS or FFT_POWER or FFT_DBFS
}
void loop() {
if (myFFT.available() /*&& ++ct == 4*/ ) {
// each time new FFT data is available
// print it all to the Arduino Serial Monitor
float* pin = myFFT.getData();
for (int gg=0; gg<512; gg++)
xxx[gg]= *(pin + gg);
for (int i=0; i<512; i++) {
Serial.print(i);
Serial.print(", ");
Serial.println(xxx[i], 8);
}
Serial.println();
}
/*
if(count++<200) {
Serial.print("CPU: Max Percent Usage: ");
Serial.println(AudioProcessorUsageMax());
Serial.print(" Max Float 32 Memory: ");
Serial.println(AudioMemoryUsageMax_F32());
}
*/
}