FFT on Teesy 4?

pwd847

Active member
Is it possible to do an FFT on the Teensy 4? I was reading that the audio library wiring doesn't work to connect ADC(A0) to the fft1024_1.
 
Yes, it should. Not sure what was at hand when reading about the issues and how it affects desired use?
 
Capture.PNG

I get this when I try to compile this:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputAnalog         adc1;           //xy=193,57
AudioAnalyzeFFT1024      fft1024_1;      //xy=461,75
AudioConnection          patchCord1(adc1, fft1024_1);
// GUItool: end automatically generated code

void setup(){
  
}

void loop(){
  
}

I'm not using the audio board. Am I doing something wrong?
 
Perhaps look at the Audio Tutorial FFT examples on the PJRC site. It seems that is missing some things.
 
I just watched the relevant portion of the audio tutorial again, and scoured the prjc site for more info on the FFT direct from the ADC, and I don't see anything wrong with my code. The error makes it look like something can't be found in the .h file.
 
Put an Audio board Rev D onto a T_4.0 - and seeing streaming FFT data going by on USB display.

Using :: ...\hardware\teensy\avr\libraries\Audio\examples\Tutorial\Part_3_02_Fourier_Transform\Part_3_02_Fourier_Transform.ino

That isn't feeding from ADC data - but FFT on T_4.0 works - in this sample using the PJRC audio board as the auto driver for output. The Tutorial focuses on the Audio board - not sure if that is in use - assumed not as it is not in the posted code?
Info on ADC usage is showing examples: pjrc.com/teensy/gui/?info=AudioInputAnalog
Code:
Examples
File > Examples > Audio > HardwareTesting > PassThroughMono 
File > Examples > Audio > Analysis > PeakMeterMono 
File > Examples > Audio > Analysis > DialTone_7segment 
File > Examples > OctoWS2811 > SpectrumAnalyzer 
Notes
analogRead() must not be used, because AudioInputAnalog is regularly accessing the ADC hardware. If both access the hardware at the same moment, analogRead() can end up waiting forever, which effectively crashes your program. 
A different pin may be used, but adding it as an parameter to the AudioInputAnalog object definition. 
For example, to use pin A3: 
[B]AudioInputAnalog adc1(A3);[/B]
> that shows 'AudioInputAnalog adc1(A3);' differs from the above where no pin is given - so "Audio input needs to connect to pin 16 (A2). The signal range is 0 to 1.2V." - according to that GUI Tool text.

A provided example close to post #3 looks to be :: ...\hardware\teensy\avr\libraries\Audio\examples\Analysis\PeakMeterMono\PeakMeterMono.ino
> Perhaps seeing that work with these notes will help as it does not use the PJRC Audio Board. After seeing the 'Peak' work it should easily evolve into FFT usage from one of the other examples.

And as indicated in the following there is no "AudioMemory( ## )" from :: ...\hardware\teensy\avr\libraries\Audio\examples\Analysis\SpectrumAnalyzerBasic\SpectrumAnalyzerBasic.ino
Code:
void setup() {
  [B]// Audio requires memory to work.[/B]
  AudioMemory(12);

To run the above sketch "Part_3_02_Fourier_Transform.ino" these lines needed to be added - a SD card on the audio board with PJRC file "SDTEST1.WAV" present:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>


///////////////////////////////////
// copy the Design Tool code here
///////////////////////////////////
// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;     //xy=90,44
AudioPlayMemory          playMem1;       //xy=94,113
AudioSynthWaveform       waveform1;      //xy=104,170
AudioMixer4              mixer1;         //xy=290,91
AudioAnalyzeFFT1024      fft1024_1;      //xy=461,132
AudioOutputI2S           i2s1;           //xy=465,58
AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord2(playSdWav1, 1, mixer1, 1);
AudioConnection          patchCord3(playMem1, 0, mixer1, 2);
AudioConnection          patchCord4(waveform1, 0, mixer1, 3);
AudioConnection          patchCord5(mixer1, 0, i2s1, 0);
AudioConnection          patchCord6(mixer1, 0, i2s1, 1);
AudioConnection          patchCord7(mixer1, fft1024_1);
AudioControlSGTL5000     sgtl5000_1;     //xy=352,195
// GUItool: end automatically generated code
 
I just watched the relevant portion of the audio tutorial again, and scoured the prjc site for more info on the FFT direct from the ADC, and I don't see anything wrong with my code. The error makes it look like something can't be found in the .h file.

No error details were provided. Cut and paste of text from the console would show what that was.

Perhaps it is the error showing here compiling the suggested : ...\hardware\teensy\avr\libraries\Audio\examples\Analysis\PeakMeterMono\PeakMeterMono.ino

Just posted a question about that on the TD 1.52 B3 thread - as that may in fact be not yet supported - but FFT's are working.
 
See Capture.PNG in #3

Indeed it is there once clicked … I thought that was an audio wave form of some sort ( scope or LA ) proving it wasn't working somehow since the code has no loop() there would be no SerMon output.

Anyhow the answer is - indeed T_4.0 lacks ADC1 support at this time:
No, there were several threads absolut this... as with PWM,
this is still a missing part in the T4 Audiolib.
I would help with this, or add it, if I knew a way to clock it with 44.100kHz
 
"fixed" might be a strong word to use. "experimental" or "alpha" is probably better.

ADC input does work now, but still has many caveats. Among them, it requires another input or output because it does not yet cause the audio library to update.
 
Well the COMPILE error was fixed … and provided the link to notes about the need for RunTime caveats …
 
Here is a program which will run on Teensy 4.0 using 1.52-beta4 and gives you FFT of an audio signal on analog pin A2.

Code:
#include <Audio.h>

// GUItool: begin automatically generated code
AudioInputAnalog         adc1;           //xy=197,73
AudioAnalyzeFFT1024      fft1024_1;      //xy=361,47
AudioOutputI2S           i2s1;           //xy=378,99
AudioConnection          patchCord1(adc1, 0, i2s1, 0);
AudioConnection          patchCord2(adc1, 0, i2s1, 1);
AudioConnection          patchCord3(adc1, fft1024_1);
AudioControlSGTL5000     sgtl5000_1;     //xy=265,161
// GUItool: end automatically generated code

void setup() {
  AudioMemory(30);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("FFT test");
}

void loop() {
  if (fft1024_1.available()) {
    for (int i=0; i < 20; i++) {  // print the first 20 bins
      Serial.print(fft1024_1.read(i), 3);
      Serial.print(" ");
    }
    Serial.println();
  }
}

This will work without the audio shield present, but I2S output (or any other I/O object that causes the library to update) is currently required. Future versions will remove this requirement. Please understand this ADC audio code is very new and still has many minor issues. But at least you can see we're making progress towards ADC input for audio.

One of those many minor issues is the level. A full scale waveform on the ADC pin does not yet map to a full scale signal coming into the audio library. Removal of DC offset also isn't working well yet.
 
Here is a program which will run on Teensy 4.0 using 1.52-beta4 and gives you FFT of an audio signal on analog pin A2.

Code:
#include <Audio.h>

// GUItool: begin automatically generated code
AudioInputAnalog         adc1;           //xy=197,73
AudioAnalyzeFFT1024      fft1024_1;      //xy=361,47
AudioOutputI2S           i2s1;           //xy=378,99
AudioConnection          patchCord1(adc1, 0, i2s1, 0);
AudioConnection          patchCord2(adc1, 0, i2s1, 1);
AudioConnection          patchCord3(adc1, fft1024_1);
AudioControlSGTL5000     sgtl5000_1;     //xy=265,161
// GUItool: end automatically generated code

void setup() {
  AudioMemory(30);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("FFT test");
}

void loop() {
  if (fft1024_1.available()) {
    for (int i=0; i < 20; i++) {  // print the first 20 bins
      Serial.print(fft1024_1.read(i), 3);
      Serial.print(" ");
    }
    Serial.println();
  }
}

This will work without the audio shield present, but I2S output (or any other I/O object that causes the library to update) is currently required. Future versions will remove this requirement. Please understand this ADC audio code is very new and still has many minor issues. But at least you can see we're making progress towards ADC input for audio.

One of those many minor issues is the level. A full scale waveform on the ADC pin does not yet map to a full scale signal coming into the audio library. Removal of DC offset also isn't working well yet.

Paul - this code works on T_4.0 and 4.1 - but as noted elsewhere FAILS on T_3.6 [ using IDE 1.8.12 and TD 1.52 B4 ]::
Code:
"T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SD\\fat_t3.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SD\\file_t3.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SD\\init_t3.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SD\\utility\\NXP_SDHC.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SD\\utility\\Sd2Card.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SD\\utility\\SdFile.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SD\\utility\\SdVolume.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SerialFlash\\SerialFlashChip.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\SerialFlash\\SerialFlashDirectory.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\Wire\\Wire.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\Wire\\WireIMXRT.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\Wire\\WireKinetis.cpp.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino\\libraries\\Wire\\utility\\twi.c.o" "T:\\TEMP\\arduino_build_AnalogFFT.ino/core\\core.a" "-LT:\\TEMP\\arduino_build_AnalogFFT.ino" -larm_cortexM4lf_math -lm
T:\TEMP\arduino_build_AnalogFFT.ino\sketch\AnalogFFT.ino.cpp.o: In function `AudioInputAnalog::AudioInputAnalog(unsigned char)':
T:\arduino-1.8.12\hardware\teensy\avr\libraries\Audio/input_adc.h:38: undefined reference to `AudioInputAnalog::init(unsigned char)'
T:\TEMP\arduino_build_AnalogFFT.ino\sketch\AnalogFFT.ino.cpp.o: In function `AudioStream::AudioStream(unsigned char, audio_block_struct**)':
T:\arduino-1.8.12\hardware\teensy\avr\cores\teensy3/AudioStream.h:138: undefined reference to `vtable for AudioInputAnalog'
collect2.exe: error: ld returned 1 exit status
 
"Audio input needs to connect to pin 16 (A2). The signal range is 0 to 1.2V." - according to that GUI Tool text.


To run the above sketch "Part_3_02_Fourier_Transform.ino" these lines needed to be added - a SD card on the audio board with PJRC file "SDTEST1.WAV" present


Hello dear defragster / dear forum members,


I have a few questions regarding the FFT Example:

Above you said that audio input needs to be connected to pin 16...so does that mean that if I'm connecting a device like e.g. a little Synthesizer to pin 16 the serial monitor / plotter will show me the spectrum of that signal?

Why do i need the file "SDTEST1.WAV" on my SD card? In the "Part_3_02_Fourier_Transform" example there is a sample of a guitar "AudioSampleGuitar.cpp / .h"... I thought the Fourier analysis was taken from that sample rather than the .WAV file? Or am I seeing the spectrum of "SDTEST1.WAV" right now?

So are different data types possible then? What I mean: Can I only get the FFT of an wav2sketch sampled .WAV signal? Or also as an analog signal like a synth coming into pin16? Or could I directly send an .WAV into the code without converting it before? What format(s) is / are needed for the FFT?

Furthermore: Does somebody know on how to find the highest peak in the resulting spectrum? So e.g. if I'm playing an A (440Hz) on my piano, the fundamental of f = 440 Hz should be the loudest in that signal - but how loud is it? Everything coming from the "Part_3_02_Fourier_Transform" - Code is very numerical, I can't really translate those values / LED-pictures to an actual dB-value...any ideas how to transform the values coming out of that "Part_3_02_Fourier_Transform" - Code into some more audio-relatable data like decibel?

Thanks a lot for this thread and your help guys :)


With kind regards,
Mala
 
Hello dear defragster / dear forum members,


I have a few questions regarding the FFT Example:

Above you said that audio input needs to be connected to pin 16...so does that mean that if I'm connecting a device like e.g. a little Synthesizer to pin 16 the serial monitor / plotter will show me the spectrum of that signal?
So long as the signal is in the correct voltage range, 0..Vcc (otherwise you'll risk frying the chip - the suggested interface circuit in the
docs for adc input doesn't seem to feature any protection alas - at the very least its wise to use series resistor and schottky clamps if
the voltage source is from an external piece of equipment)
So are different data types possible then? What I mean: Can I only get the FFT of an wav2sketch sampled .WAV signal? Or also as an analog signal like a synth coming into pin16? Or could I directly send an .WAV into the code without converting it before? What format(s) is / are needed for the FFT?
Any signal you can get into the audio lib system can be processed however you like with any object. Internally its 44.1kSPS and 16 bit signed
throughout.
Furthermore: Does somebody know on how to find the highest peak in the resulting spectrum? So e.g. if I'm playing an A (440Hz) on my piano, the fundamental of f = 440 Hz should be the loudest in that signal - but how loud is it? Everything coming from the "Part_3_02_Fourier_Transform" - Code is very numerical, I can't really translate those values / LED-pictures to an actual dB-value...any ideas how to transform the values coming out of that "Part_3_02_Fourier_Transform" - Code into some more audio-relatable data like decibel?
That's up to your coding I think - scan the fft bins and find the greatest... BTW its not necessarily true that the fundamental has the
highest amplitude in a musical note, though often the case. To pick the dominant tone there are much better algorithms than picking
the highest peak in the FFT, for instance cepstrum analysis is used for speech decoding as its more reliable. For this sort of task
I'd recommend looking around for existing libraries and projects.
Thanks a lot for this thread and your help guys :)


With kind regards,
Mala
 
So long as the signal is in the correct voltage range, 0..Vcc (otherwise you'll risk frying the chip - the suggested interface circuit in the
docs for adc input doesn't seem to feature any protection alas - at the very least its wise to use series resistor and schottky clamps if
the voltage source is from an external piece of equipment)

Thanks for the advice, i will try that out! Did you ever connect a microphone to one of your teensys / audio boards? Would be interested if you got any tips for a good little MIC and what to bear in mind when connecting it :)

That's up to your coding I think - scan the fft bins and find the greatest... BTW its not necessarily true that the fundamental has the
highest amplitude in a musical note, though often the case. To pick the dominant tone there are much better algorithms than picking
the highest peak in the FFT, for instance cepstrum analysis is used for speech decoding as its more reliable. For this sort of task
I'd recommend looking around for existing libraries and projects.

Since you've posted in the thread i've started last week (https://forum.pjrc.com/threads/66288-Voice-Authentication-with-FFT) I can tell you why I'm interested in the FFT algorithm:
I've analyzed the spectrum of my voice inside a DAW. It has a nearly constant fundamental and a very unique overtone series. I actually do not need THE lowest frequency of the signal, it just has to be one of the lowest overtones f. Then I would search for 2f, 3f, 4f and so on. If I could measure the values / loudness of the different frequencies I could actually create my own "voice fingerprint" with that. Taking a second recording I could then evaluate if the person talking into the microphone creates a different spectrum or not.

To realize this approach I'll need to have access to the different peaks of the spectrum and that's the current issue I'm trying to solve.

I've never heard of Cepstrum Analysis, thanks for sharing that with me! I googled it and researched a bit on how the transformation works and it is a really powerful tool if you want to evaluate the periodicity of a signal. However I wouldn't see a benefit in using this transformation in my case, since I think the DFT/FFT approach would be way easier to program.

Thanks for reading this and thanks for any advice / help!


With kind regards,
Mala
 
Voice spectra contain both the signature of the harmonics, related to the waveform from the vocal chords,
and the filtering envelope imposed by the throat/mouth cavity, which doesn't change in frequency with the
note, but can change in character with mouth/tongue/soft-palette position (vowel sounds are principally due to this part).
 
filtering envelope imposed by the throat/mouth cavity, which doesn't change in frequency with the
note, but can change in character with mouth/tongue/soft-palette position (vowel sounds are principally due to this part).

Yes exactly, there isn't really one unique recording of your voice which will always sound the same - there will be filtering-effects due to different recording sessions. I thought of something like a "frequency tolerance" for this issue. Something like this:

If (f0_new >= f0_old + 5 || f0_new <= f0_old - 5)
return 0; // Authentification failed

I know it all looks a bit improvised at this point. But i don't think one wouldn't be able to realize an algorithm like that. But first of all I need to get concrete values for the frequencies and their levels. That's why i was asking here in this thread on how to translate the FFT1024 values.

(I also would still be interested why you'd need the "SDTEST1.WAV" for this example code? Is the spectrum I'm seeing taken of "AudioSampleGuitar" or of "SDTEST1.WAV"?)

With kind regards, Mala
 
You need to install the three buttons to use the complete example code. By default it uses SDTEST1.WAV as the audio input to the FFT. Each of the three buttons selects a different input.
Code:
// Left button starts playing a new song
.
.
// Middle button plays Guitar sample
.
.
// Right button plays a pure sine wave tone


and BTW.
This:
Code:
If (f0_new >= f0_old + 5 || f0_new <= f0_old - 5)
would always be true. It should be this:
Code:
if (f0_new >= f0_old + 5 && f0_new <= f0_old - 5)

Pete
 
You need to install the three buttons to use the complete example code. By default it uses SDTEST1.WAV as the audio input to the FFT. Each of the three buttons selects a different input.

Thanks a lot Pete, I'll try to install the buttons and analyze the FFTs of the other Signals!

and BTW.
This:
Code:
If (f0_new >= f0_old + 5 || f0_new <= f0_old - 5)
would always be true. It should be this:
Code:
if (f0_new >= f0_old + 5 && f0_new <= f0_old - 5)

Pete

I'm not sure about that, because with && the value f0_new would need to be 5Hz higher than f0_old and 5 Hz lower than f0_old at the same time which would then always be false I think?


Code:
If (f0_new >= f0_old + 5 || f0_new <= f0_old - 5)


Assuming f0_old is 200 Hz, then with this or conjunction f0_new would need to be between 195 Hz and 205 Hz (if I'm not overseeing something)

Thanks for your help guys!


With kind regards,
Mala
 
I'm not sure about that
You're absolutely right. I misread it. Sorry.

If you just want to see the spectrum of the guitar sample, There's a variable that is set to 0, 1 or 2 when you push the buttons. It is initially zero. If you initialize it to 1, you'll get the guitar spectrum without needing any extra hardware - although the buttons could just be jumper wires and you ground one of them.

Pete
 
Here is a program which will run on Teensy 4.0 using 1.52-beta4 and gives you FFT of an audio signal on analog pin A2.

Code:
#include <Audio.h>

// GUItool: begin automatically generated code
AudioInputAnalog         adc1;           //xy=197,73
AudioAnalyzeFFT1024      fft1024_1;      //xy=361,47
AudioOutputI2S           i2s1;           //xy=378,99
AudioConnection          patchCord1(adc1, 0, i2s1, 0);
AudioConnection          patchCord2(adc1, 0, i2s1, 1);
AudioConnection          patchCord3(adc1, fft1024_1);
AudioControlSGTL5000     sgtl5000_1;     //xy=265,161
// GUItool: end automatically generated code

void setup() {
  AudioMemory(30);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("FFT test");
}

void loop() {
  if (fft1024_1.available()) {
    for (int i=0; i < 20; i++) {  // print the first 20 bins
      Serial.print(fft1024_1.read(i), 3);
      Serial.print(" ");
    }
    Serial.println();
  }
}

This will work without the audio shield present, but I2S output (or any other I/O object that causes the library to update) is currently required. Future versions will remove this requirement. Please understand this ADC audio code is very new and still has many minor issues. But at least you can see we're making progress towards ADC input for audio.

One of those many minor issues is the level. A full scale waveform on the ADC pin does not yet map to a full scale signal coming into the audio library. Removal of DC offset also isn't working well yet.

Paul some questions on the code:

1) What frequencies could cover the range 0-20 that you propose in the vector?
Code:
for (int i=0; i < 20; i++)

2) If it were zoomed in between 2-135 bins, would it be feasible to cover a frequency spectrum, say between 40 and 6000 Hz?
 
Back
Top