Audio Library and 4096 point FFT on Teensy 3.6

Status
Not open for further replies.
Thank you so much for your quick response, Frank.

Looks like a good solution. I need time to digest. I shall let you know the result, but it takes time.
BTW, a good starting point could be:

1.) take the AudioGrabber object by DerekR as-it-is for the FFT256 at standard sample rate
2.) modify the AudioGrabber object (include the code for lowpass filtering and downsampling inside the object) and add that to your audio project.
 
It seems that this thread has split into a couple of somewhat disparate conversations:
1) Getting the audio library 4096 FFT to work, which I think has been established?
2) Analyzing/displaying partial frequency regions of an FFT. (See #44)

Let's discuss the latter:
As you are aware, spectral information is normally displayed in "Bode" form where
- Magnitude is displayed on a log/log scale (x is log of frequency - but usually labeled in Hz, y is log of magnitude usually in dB.
- Phase is displayed on log/linear form, where again frequency is in log form, but y (phase is shown on a linear scale in units of degrees or radians)

BUT this doesn't mean you need some sort of special FFT! Engineering/scientific software packages, such as MATLAB, simply compute their displays using a normal linear FFT analysis, then take the necessary logs of the bin frequencies and magnitude and display the data in Bode form. Why can't that be done here?
Note: You can't go down to dc (0 Hz) because log(0) = -infinity, so you need to choose a suitable minimum frequency (bin) for your display.

I note the displays shown in the thread go from 20 Hz to 20 kHz - ie 3 decades of frequency. Since the FFT bin frequencies are n*f_sample/Nfft, to get down to 20 Hz for n = 1 we need Nfft > 44100/20 or >2205 (you could probably get away with 2048, where bin 1 corresponds to 21.5 Hz). Can you use decimation in this case? No - because you need to keep the analysis Nyquist frequency above 20 kHz (the highest in the display). So, unfortunately, you seem to be stuck with a large FFT if you want to duplicate this display...


The computational "cost" of an FFT is roughly proportional to Nfft*log_2(Nfft) so you might expect that the 2048 FFT will take about 46% of the time of a 4096 FFT...

BUT, if you are happy to make 50 Hz your minimum frequency, then a length 1024 FFT will do the trick, bin 1 is now 43 Hz, and you might expect the FFT to be 5 times faster than the 4096 one. Now we're talking :D
 
Thank you so much for your reply, Derek.

1)
I also think that the 4096 FFT has been established. However as I mentioned in my previous post in #37 and #42. I don't understand why it doesn't work in my T3.6. I very much like to make it work and test its performance.
In post #4 by duff, he mentioned about CMSIS v1.1.0. I cannot find any file named CMSIS, is it referring to "core_cm4.h"? The version of this file in my computer is v3.01. I don't know whether it is the cause of the problem, any opinion?

2)
a) "simply compute their displays using a normal linear FFT analysis, then take the necessary logs of the bin frequencies". Agree, it is a matter of the minimum frequency (bin). I want to decrease the min frequency (bin) to around 10 Hz.

b) 2048 FFT will give a min frequency (bin) to around 20 Hz. It is better than 1024 FFT. I would like to try if it can be implemented in simple way. I found a lot of information relating to the 4096 FFT, but less on 2048 FFT. Any example I can follow?

c) According to Frank in #49, he suggested a Zoom FFT plus a 256 FFT working in parallel. It would give a min frequency (bin) even down to around 5 Hz. I am studying his suggestion, but, due to my limited theoretical knowledge, it may take me a long time.

d) My understanding is that to lower the min frequency bin to x Hz, you need at least 1/x seconds. (e.g. a min frequency bin of 10Hz you require a update time of at least 0.1 Second. correct me if I am wrong). If this is correct, I don't know if it applies to zoom FFT as well. If it applies, a 0.2 second update time seems long.

e)I very much hope to get the 4096 FFT work first (which I need assistance). Because it has been established, and I think it will be simpler. If the update time of 0.1 S is too long (to be tested after it is working), I would consider to use 2048 FFT. I shall study the zoom FFT option in parallel.
 
Hi!

I've just made a quick test with the 4096FFT (using the files goldhausen has provided). It seems to work ok with the ILI9341_t3n Library (using frame buffer) I get 22 FPS.
I'm using the Audio Library and have no issues with using the 4096FFT.

In my project I would like to visualize the audio spectrum pre and post filtering (20 Hz ... 20kHz).
As you can see on the picture, my frequency-axis is not linear. I try to get better resolution especially in the lower frequency range (20 Hz ... 320 Hz), therefore the 4096FFT gets handy with a Frequency Bin resolution of ca. 11 Hz.
Although this works, I agree with DD4WH, the "ZoomFFT" would be a much better approach to solve this "low-frequency" problem.

Is there a "ready to use" ZoomFFT library available that works with the audio library?

View attachment 16937

Hi FLEOX,

I understand that you have no issue with using FFT4096. I am also using the files goldhausen has provided. FFT1024 runs with no issue, however, when I changed the FFT1024 to FFt4096, the same sketch can compile and upload but without any printout. I can't find the reason why. The following is what I have done:

1) In order to eliminate any wrong doings, I have reinstalled the Arduino (v 1.8.9) and Teensyduino (v 1.47).
2) Copied the the Analyze_fft4096.cpp and Analyze_fft4096.h file from #24.
3) Replaced the files Audio.h ; data_windows.c and keywords.txt by those in #24.
(By the way, I am still working on the Windows XP system.)

I used the sketch posted in #1 by blacktronics, only change is commented out the line "fft1.averageTogether(8);"

I should be very grateful if you could have a look at what I have done and see what was wrong.

Thank you so much.
 
AudioGrabber object for the FFT256.

A couple of suggestions:
1) In the original post it was mentioned that it was only the lower part of the spectrum that is of interest. You might try a "zoom FFT" approach (google it), and examine only what you want. This would allow you to use a smaller FFT and retain the resolution you want.

2) In order to keep the processing time low within the update time of the Audio library, I often extract the data from the internal data stream and process it in the loop() as a lower priority task. To that end I've written a set of "audioGrabbers" that assemble a given length block of Audio data (say 256 complex data elements, or 512 real data points) and then signal that a block is available. In loop() I check the "new data available" flag and then "grab" the data, and process it. I double-buffer it so that there are no data collisions while grabbing occurs. For example, I use this method for spectral analysis in my SDR (software-defined-radio) work. I currently don't have a 1024 length grabber written, but I'd be happy to throw one together for you...

Derek,
Can you pass me the audioGrabbers object for fft256 please?
 
Sure. Do you want the complex or real? Give me an hour or so... I'll upload them both on the forum under this thread.

Aside: I was getting the grabbers ready to upload as a library to GitHub three days ago when I decided to test them on the T4. And that was a huge mistake - you can read about it on the General Discussion part on the forum in my thread today about "bricking" the T4. Anyway it took 3 days to resolve the problem. It had nothing to do with my code, but was a problem with Teensyduino 1.48beta1. The solution is that if you want to use the grabbers with a T4 you must install Teensyduino 1.48beta2 which was just announced this morning!
 
Thank you Derek,

1) I want complex.
2) Timing is ok for me. I am doing it purely for my own interest, no time frame. Do it in your leisure. I am going for a month's holiday starting next week. I can read the forum via smart phone, but cannot do any testing. Hard luck.
3) I planned to buy T4 after my holiday, I would also like to have a try after I got the T4.


I have been through most of the information suggested by you and Frank, and have drawn up the following concept (Correct me if it is wrong):

a) Audio from standard Audio Library, with sampling frequency of 44.1 Khz. It can be from adc, mic, line-in or waveform generator.

b) Use a standard FFT256 from Audio Library for High frequency components.
- Resolution around (44100/2)/128 = 170 Hz
- update rate = (1/441000)*256 = 5.8 ms

c) Use another standard FFT256 from Audio Library for low frequency, with one out of 32th sampling speed.
- Resolution around (44100/2/32)/128 = 5.4 Hz
- update rate = (1/441000)*32*256 =186 ms

186 ms is a bit long, I would rather sacrify the resolution a bit to around 10 Hz, i.e.
With one out of 16 sampling speed.
- Resolution around (44100/2/16)/128 = 10.8 Hz
- update rate = (1/441000)*16*256 =93 ms ( A bit more acceptable)

However, the location of the lowpass filter is a question. It can be :

Option 1)
The low frequency FFT (LF FFT) takes every 32th sample from the same audio stream as high frequency FFT (HF FFT). The question is where to put the lowpass filter. If I put the lowpass filter before the audio stream, the HF FFT will lost the high frequency components. If we don't insert the lowpass filter, we would have aliasing problem.

Option 2)
The HF FFT takes the sample directly from the audio stream, while the LF FFT takes every 32th sample from the lowpass filtered audio stream. The system would have to sample alternatively, (because we are using one adc only) i.e. .... HF FFT 〉 LF FFT 〉HF FFT 〉 LF FFT 〉.... In this option, the update rate of the high frequency FFT is equal to low frequency FFT that is equal to the sum of the update rates of the HF FFT + LF FFT. This is not acceptable at HF FFT because when waiting for the LF FFT taking sample, data will be lost.

Any idea how to solve the above problem?

The ideal situation will be to make a audio object, with one audio stream input and with two audio stream output, one for the HF FFT and the other for LF FFT. The anti-aliasing filter to be within the object.

Thank you very much for your patience to go through such a long writing.
 
Hi everyone!
I'm sorry for the very late reply to this discussion. I was very busy the last few weeks.

Of course I will post the complete source code of my project. I've made two small code examples how I achieved my results. One of them is just a simple 4096-FFT of a sine wave .
I'm using Arduino 1.8.10 with Teensyduino 1.48 Beta #1
For getting the high display update rate I had to change the F_BUS Speed from 60 MHz to 120 MHz in the kinetis.h file.
Important to know is, that I run the Teensy 3.6 on 240 MHz CPU Speed.

For those of you who are interested in my setup:
In my project (Audio Class-D Amplifier with integrated DSP) the purpose of the Teensy 3.6 is only to visualize the audio spectrum (pre and post the processing).
The actual signal processing of the audio data gets done on a specific Audio-DSP (ADAU1401). Therefor the main clock Source of the System is the DSP not the Teensy.
The Teensy 3.6 gets the audio data via I2S in slave mode (24-Bit, 48 kHz sample rate) and converts it to a 16-Bit audio stream (by taking to 2 most significant Bytes).
The Left Channel of the I2S Stream is representing the Mono-Signal (pre processed), the right channel is used for the Mono-Signal after the DSP processing.

As you know, my goal is to get the best possible display resolution of the FFT for both Mono-Signals (pre and post processing).
I'm as well very interested in the zoom FFT or the very similar "log FFT".

Currently I still have a lot of other things to get done until I can work further on this project.
But I hope that there are some other motivated people to work on this topic!

Best regards
Florian


View attachment FFT-Display_DMA_4096_Demo.zip
View attachment FFT-Display_DMA_4096_Sinewave.zip
 
Thank you very much for you reply, Flexo.
I shall try accordingly, however, I am going for a month's holiday starting next week. I shall let keep you informed of the test result, though it may be at least one month later. Sorry about that.
 
c) Use another standard FFT256 from Audio Library for low frequency, with one out of 32th sampling speed.
- Resolution around (44100/2/32)/128 = 5.4 Hz
- update rate = (1/441000)*32*256 =186 ms

186 ms is a bit long, I would rather sacrify the resolution a bit to around 10 Hz, i.e.
With one out of 16 sampling speed.

Dont worry about the update rate: you can do the following:

for every block of 128samples:
* lowpass @689Hz
* take every 32th sample --> so you get 4 new samples for every new audio block arriving
* perform FFT256 with the 4 new samples and rest of the FFT buffer is filled with the old samples --> so you need a "moving window buffer" which is subsequently filled with the decimated samples
* that gives you resolution of 5.4Hz AND update rate as for the high frequencies

However, the location of the lowpass filter is a question. It can be :

Option 1)
The low frequency FFT (LF FFT) takes every 32th sample from the same audio stream as high frequency FFT (HF FFT). The question is where to put the lowpass filter. If I put the lowpass filter before the audio stream, the HF FFT will lost the high frequency components. If we don't insert the lowpass filter, we would have aliasing problem.

Option 2)
The HF FFT takes the sample directly from the audio stream, while the LF FFT takes every 32th sample from the lowpass filtered audio stream. The system would have to sample alternatively, (because we are using one adc only) i.e. .... HF FFT 〉 LF FFT 〉HF FFT 〉 LF FFT 〉.... In this option, the update rate of the high frequency FFT is equal to low frequency FFT that is equal to the sum of the update rates of the HF FFT + LF FFT. This is not acceptable at HF FFT because when waiting for the LF FFT taking sample, data will be lost.

Any idea how to solve the above problem?

You need two objects: the standard FFT, which analyses the high frequencies, and another object, the ZoomFFT object. Both receive the same audio stream and process it independently from each other. Or, like you proposed:
The ideal situation will be to make a audio object, with one audio stream input and with two audio stream output, one for the HF FFT and the other for LF FFT. The anti-aliasing filter to be within the object.
 
@LoShu -As you requested I have attached a zip file View attachment Grabber256.zip containing two "grabbers":
1 AudioGrabberComplex256
2 AudioGrabberReal256
in separate folders, each with a simple example of their use.

I have several other variants, in buffer lengths and in function, and I'm currently preparing them for upload to GitHub.
Let me know if you have questions.

Derek
 
Hi Frank,

Thanks a lot for your response. I am sorry that I have missed that point that the "moving window buffer" can solve the updating rate problem. I shall go ahead for a trial. I shall come back to you in case I encounter any problem.

By the way, I would still like to clarify one point:

You mentioned:
"
every block of 128 samples:
* lowpass @689Hz
* take every 32th sample --> so you get 4 new samples for every new audio block arriving
* perform FFT256 with the 4 new samples and rest of the FFT buffer is filled with the old samples
"

I think for FFT256, every block should have 256 samples. Shall get 8 new samples for every new audio block arriving for "moving window buffer".

Thanks.
 
Hi Derek,

Thank you very much for the files. I shall study in detail and would come back to you again if I need any clarification.
 
Hi everyone;

Just come back from my holiday.

@ FLEOX

I have changed my system to Arduino 1.8.10 with Teensyduino 1.48 Beta #1 as according to your post #59 on 10-05-2019 test the FFT4096. However, it looks like the board information has not been included because the system cannot recognize any boards for compilation. I have to see how to load it back to the system. I shall be grateful if anybody can tell me how to do it to save my time.
 
Hi LoShu

Ok, it seems that your Arduino IDE is broken or something is corrupt. I would completely uninstall the Arduino IDE and then reinstall firstly the Arduino IDE and secondly the teensyduino (newest = 1.48, no Beta anymore).
Follow the instructions here: https://www.pjrc.com/teensy/td_download.html

After changing all necessary teensy settings it should compile fine:

MCU: Teensy 3.6
USB Type: Serial + Midi + Audio
CPU Speed: 240 MHz (overclock)
Optimize: Faster

Best regards
Florian
 
Hi Florian

I have tried to uninstall and install Arduino 1.8.10 and Teensyduino 1.48 several times. The system is still not working. It cannot even compile the simplest example "blink". Finally I made a hard decision to replace my 20 years old laptop that is still running on window XP.

After installing the Arduino 1.8.10 and Teensyduino 1.48 in the new laptop, the system works ok with the fft1024. It can compile fft4096, but doing nothing. Same result as when running on Arduino 1.8.2 and Teensyduino 1.36.

I then went through the "analyze_fft4096.cpp and analyze_fft4096.h" file pair line by line. I found they are still using "arm_cfft_radix4_q15", which doesn't support fft4096. I have tried several methods modifying them to use "arm_cfft_q15", however, I cannot make them to work.

Can you give me a "analyze_fft4096.cpp and analyze_fft4096.h" file pair which is using "arm_cfft_q15" to save me fooling around?

Thank you again for your assistance.

LoShu
 
Hi LoShu

Ok, that's interesting. In my opinion you don't need to change "arm_cfft_radix4_q15" to "arm_cfft_q15", because "arm_cfft_radix4_q15" does support FFT4096. Have a look here https://www.keil.com/pack/doc/CMSIS/DSP/html/group__ComplexFFT.html

I don't understand why my example (FFT-Display_DMA_4096_Sinewave) is not working on your system. I think your issue has nothing to do with the "analyze_fft4096.c/.h" files, because the exact same code as I uploaded in .zip format does work for me without any changes.
I suspect that something is wrong with your Arduino board options or it is a harware related problem.

Can you please give us more information about your current hardware test setup. Do you have a display connected?
One important thing to notice is that you need some kind of a "audio clock source" for the teensy audio library. Thta's why I hat to implement this line of code in my sketch:
Code:
AudioOutputAnalog dac1;      // ********** !!! Is needed as a clock source !!!

Best regards
Florian
 
Hi Florian,

I am still struggling how to get the fft4096 to work in my system, and have not come to your "FFT-Display_DMA_4096_Sinewave" yet. What I have done is using a simple Arduino Sketch "FFTTest" (attached) to test the performance of the fft. I use a "AudioSynthWaveformSine" to generate a variable frequency sine wave, a potentiometer is connected to adjust the frequency from 0 to 22.1KHz and printout on the IDE monitor.

From gohlhausen in #24, I copied the "analyze_fft4096.cpp and analyze_fft4096.h" to the audio library and replaced "data_windows.c, Audio.h and keywords.txt" in the same audio library.
The sketch works well with fft256 and fft1024. For fft4096, it can compile and load with no problem, but just doesn't work (no print out). I don't quite understand why the 4096 works in your system and not mine.

I am using a brand new laptop computer running on Window 10, newly installed Arduino 1.8.10 and Teensyduino 1.48. No other hardware such as display is connected to the system. The Teensy Board is Teensy 3.6.

I have checked the "arm_cfft_radix4_q15" as per your link and found that it supports up to 1024 points only. (Please refer to the attached file).

It looks like "arm_cfft_q15" is more flexible, because it supports full range of frequency bins. I would be very much interested to get the "arm_cfft_q15" to work. (I have ordered 2 units of Teensy 4.0 for trial later). At the moment, my main target is to get the fft4096 to run in my system, irrespective of "arm_cfft_radix4_q15" or "arm_cfft_q15".

LoShu
Code:
/*-------------------------------------------------------------------------
  This is a simple sketch to test the performance of fft function.
   ----------------------------------------------------------------------- */
   
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
int freq;

AudioControlSGTL5000     codec;
AudioSynthWaveformSine   sine;
AudioAnalyzeFFT256       myFFT;
//AudioAnalyzeFFT1024       myFFT;
//AudioAnalyzeFFT4096       myFFT;
AudioOutputI2S           output;
AudioConnection c2(sine, 0, myFFT, 0 );

void setup() {
  Serial.begin(9600);
  delay(2000);
  
  codec.enable();
  AudioMemory(12);
  codec.volume(0.5);
  sine.amplitude(0.5);

}
//--
void loop() {
  int freq = analogRead(A1) * 21.6; 
  //Use A1(pin 15) to control frequency of the sine.
  //1024 x 21.6 = 22118Hz
  sine.frequency(freq);
  if (myFFT.available()) {
    for (int i = 0; i < 128; i++) {
      if (myFFT.read(i) <= 0.1) {
        Serial.print(" ");
      }
      else {
        Serial.print(i);
        Serial.print("_");
        Serial.print(myFFT.read(i));
        Serial.print(" ");
      }
    }
    Serial.println();
  }
  delay(10);
}[ATTACH=CONFIG]18176._xfImport[/ATTACH]
 
Hi LoShu

Ok I see. I haven't messed around with the Audio library at all. I' just added the "analyze_fft4096.c/h" files directly to my Arduino Sketch (in the same folder, it get's opened in a seperate tab).
Have a look here:
Arduino_MultiTabSketch.PNG

I've made a simple test prgram withou the need of a display connected.
View attachment FFT-Display_DMA_4096_Sinewave_NoDisplay.zip

Please undo all the changes you've made to the Audio library, especially to the Audio.h file.
Let me know if this example is working.

Florian
 
Hi Florian,

By following through your steps, I am very happy to have the FFT4096 running the first time in my computer.
I have to thank once more for your patience in helping me to solve this problem. I planned to do more testing on FFT4096 and shall let you know what I have done and the test result.

At the moment, I have two more issues to tackle:

1.
I have the intention to run two fft4096 together. In order to achieve the speed, I planned to use Teensy 4.0. I have ordered two units of Teensy 4.0 from Sparkfun, am still awaiting for delivery. I understand that Teensy 4.0 does not has a dac. I need to get the clock source elsewhere, do you have any idea?

2.
As I understand, arm_cfft_radix4_q15 will be superseded by arm_cfft_q15. I am very interested to try the "arm_cfft_q15" based FFT4096. If you come across a workable "arm_cfft_q15" based "analyze_fft4096.cpp and analyze_fft4096.h" file pair, please pass a copy to me for my interest.

LoShu
 
@LoShu: if you use a Teensy 4.0, things will become much easier, because the T4 uses a Teensyduino version with the new CMSIS lib built-in.

Have a look at the code here:

https://forum.pjrc.com/threads/5805...-0-on-teensy-4?p=219628&viewfull=1#post219628

It calculates up to a 4096-point complex-to-complex FFT with
Code:
arm_cfft_q15

or up to a 8192-point real-to-complex FFT with
Code:
arm_rfft_q15

The code also compares execution times. And if you are very smart, you can use one single 4096-point complex FFT to calculate the two channels at once ;-). If you are lazy, just use two real-to-complex 4096-point FFTs for your purpose and you can still save a lot of processor cycles.
 
Hi Florian,
I have further tested the fft4096 that you have sent to me, the followings were found:

1. The analyze_fft4096.cpp and data_windows.c is not the same as those from gohlhausen. I think you have modified them to fit the attachment in the local directory. I also found that after attachment of the three files in the local directory, the other ffts such as fft256, 1024 would not work. fft256, 1024 work fine without the attachment.

2. Have tried to run two fft4096 together, use two sinewaves to drive each of the fft4096. the fft2's sinewave is 20Hz higher than the fft1 sinewave. The result is printed out as follow:

Time Stamp fft1( bin_output)
fft2( bin_output)
___________________________________________________________
15:43:08.913 -> 18_0.17 19_0.23
15:43:08.913 -> 20_0.19 21_0.22
15:43:08.913 -> ------------------------------------------- frequency = 237
15:43:08.913 ->
15:43:08.960 -> 18_0.18 19_0.23
15:43:08.960 -> 20_0.20 21_0.21
15:43:08.960 -> ------------------------------------------- frequency FFT1 = 237
15:43:08.960 ->
15:43:09.007 -> 18_0.15 19_0.24 20_0.10
15:43:09.007 -> 20_0.17 21_0.24
15:43:09.007 -> ------------------------------------------- frequency FFT1 = 237
15:43:09.007 ->
15:43:09.054 -> 18_0.12 19_0.24 20_0.13
15:43:09.054 -> 20_0.14 21_0.24
15:43:09.054 -> ------------------------------------------- frequency FFT1 = 216
15:43:09.054 ->
15:43:09.101 ->

The update rate according to the time stamp is 0.047 Sec. But according to the theory should be (1/44,100) * 4096 = 0.0929 Sec. (?). By just watching the ide monitor printout, the updating speed is quite fast.
The frequency should be the (bin number) * (44,100/2/2048).
For bin no. 19, the frequency is 19 * (44,100/2/2048) = 205 Hz. (very close to 237 Hz)

It can also be seen that the fft2's bin no is 2 more than fft1, it indicates that the ffts can give ~10Hz resolution.

I shall wait for my new Teensy 4.0 before I go further with the fft4096. I shall play with the ZoomFFT in the mean time.


LoShu
 
Status
Not open for further replies.
Back
Top