FFT decreasing BW modifiying sampling frecuency?

Status
Not open for further replies.
Hi , im trying to implement a FFT of the ADC readings with a teensy 3.5.
My intentions are getting the highest resolution possible but just around the low frecuencies from 0Hz to 500Hz.

I want to modify the Sampling frecuency so i get the bandwidth i need but i dont really know how to make those changes.
Should i change the ADC sampling frecuency?
Should i change something in the FFT code?
a.jpg
So far I have succesfully built a regular 23khz bandwidth tft display that listens to A2 analog input and labels the maximum peak frecuency.
Code:
#include <ILI9341_t3.h>
#include <font_Arial.h> // from ILI9341_t3
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
///////////////////////////////tft screen
#define CS_PIN  8
#define TFT_DC  9
#define TFT_CS 10

// MOSI=11, MISO=12, SCK=13

AudioInputAnalog          myadc;           
AudioAnalyzeFFT1024       myfft;      
AudioConnection           patchCord1(myadc, myfft);
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

int SCREEN_WIDTH,SCREEN_HEIGH;
float dataforscreen [320];
float mainPeak[2]={0,0};//frecuecny, value


void setup(){

  Serial.begin(115200);
  Serial.println("FFT example : ");
  AudioMemory(12);
  myfft.windowFunction(AudioWindowHanning1024);
//null
//extern const int16_t AudioWindowHanning1024[];
//extern const int16_t AudioWindowBartlett1024[];
//extern const int16_t AudioWindowBlackman1024[];
//extern const int16_t AudioWindowFlattop1024[];
//extern const int16_t AudioWindowBlackmanHarris1024[];
//extern const int16_t AudioWindowNuttall1024[];
//extern const int16_t AudioWindowBlackmanNuttall1024[];
//extern const int16_t AudioWindowWelch1024[];
//extern const int16_t AudioWindowHamming1024[];
//extern const int16_t AudioWindowCosine1024[];
//extern const int16_t AudioWindowTukey1024[];
 //////////////////////////////////////////screen
  SCREEN_HEIGH= tft.height();
  SCREEN_WIDTH= tft.width();
  Serial.print("SCREEN_HEIGH");Serial.print(SCREEN_HEIGH);Serial.print("    SCREEN_WIDTH");Serial.println(SCREEN_WIDTH);
  Serial.print("AUDIO_SAMPLE_RATE ");Serial.print(AUDIO_SAMPLE_RATE);Serial.print("    AUDIO_BLOCK_SAMPLES ");Serial.println(AUDIO_BLOCK_SAMPLES);
  
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
      tft.setTextColor(ILI9341_WHITE);
      tft.setFont(Arial_20);
  //??ts.setRotation(1);
  while (!Serial && (millis() <= 1000));

}

void loop() {
  
getfftdata();
PrintScreenFFT();
PrintSerialFFT();
//delay(100);
}


void PrintSerialFFT(){
  float n;
  int i;

    if (myfft.available()) {
    // each time new FFT data is available
    // print it all to the Arduino Serial Monitor
    Serial.print("FFT: ");
    for (i=0; i<50; i++) {
      n = myfft.read(i);
      if (n >= 0.01) {
        Serial.print(n);
        Serial.print(" ");
      } else {
        Serial.print("  -  "); // don't print "0.00"
      }
    }
    Serial.println();
    Serial.println(mainPeak[0]);
  }
}

void PrintScreenFFT(){
  int i;
  if (myfft.available()) {
    tft.fillScreen(ILI9341_BLACK);
      for(i=0;i<SCREEN_HEIGH;i++){
        //int n=myfft.output[i]/40;
        int n =dataforscreen[i]*500;
    tft.drawFastVLine(i,SCREEN_WIDTH-n,n,ILI9341_YELLOW);
      }

    tft.setCursor(mainPeak[0],60);
    tft.print((23000/512)*mainPeak[0]);   
    //tft.drawPixel(x, y,ILI9341_RED);
    //tft.fillScreen(ILI9341_BLACK);
    //tft.setTextColor(ILI9341_YELLOW);
    //tft.setFont(Arial_10);
    //tft.setCursor(10,10);
    //tft.print("RAW");
  }
}

void getfftdata(){
  int i;
  mainPeak[0]=0;
  mainPeak[1]=0;
      for(i=0;i<SCREEN_HEIGH;i++){
         dataforscreen[i] = myfft.read(i);
                 if(mainPeak[1]<dataforscreen[i])
                 {
                  mainPeak[0]=i;
                  mainPeak[1]=dataforscreen[i];
                 }
      }
}
 
Increased resolution will require decreased sample rate. I'm also interested in how that is done. Hopefully, someone who has already grappled with this will provide some guidance.
 
Hi,

there are (at least) two possibilities:

* use a lower sample rate --> search for Frank B "changing sample rate" thread for the code to change sample rates. However as far as I remember, lowest sample rate is 8kHz, which gives you a bandwidth of 0-4khz (and a resolution of 4000 / 1024 = 4Hz)
* use ZoomFFT, ie. lowpass filter your input data, downsample it and use the downsampled data as input for the FFT. I have achieved resolution with sub-Hz accuracy by this technique on a Teensy 3.6

--> here you get more info on this implementation of the ZoomFFT

https://github.com/df8oe/UHSDR/wiki/Spectrum-display-Magnify-mode-=-Zoom-FFT

and have a look here for an implementation on a Teensy including source code:

https://github.com/DD4WH/Teensy-ConvolutionSDR/blob/master/Teensy_Convolution_SDR.ino

Implementing the ZoomFFT is much more demanding than changing the sample rate, I would think.

Both have the disadvantage of increasing latency (decreasing time resolution) with increasing frequency resolution.

All the best,

Frank DD4WH
 
I got it!

I just figured it out diving around the audio.h libraries the exact line of code that sets the ADC sampling period.

Arduino/hardware/teensy/avr/libraries/audio/input_adc.cpp
Sin título.png
line 73:
Code:
PDB0_MOD = PDB_PERIOD*40;///////////////////////////////////////////////////////modificado por javi///////////////////
I just multiply the sampling period (PDB_PERIOD)*40 so i get 23khz/40=575hz of bandwidth and 43/40=1,075hz of resolution each bin rechecked with a wave generator

DAAAAMn it feels good, thanks for the help ill look around ZoomFFT for more ideas and inside toughts.

Cheers
 
Im not using the audio board(shield)

Im used to be able in other types of microcontrolers to modify those kind of registers from the arduino IDE but for some reason
arduino IDE doesnt recognice PDB0_MOD
 
Yeah i can see FRANK modifies the same registers with his DAC function
Code:
void setDACFreq(int freq) {
const unsigned config = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT | PDB_SC_PDBIE | PDB_SC_DMAEN;
    PDB0_SC = 0;
    PDB0_IDLY = 1;
    PDB0_MOD = round((float)F_BUS / freq ) - 1;    
    PDB0_SC = config | PDB_SC_LDOK;
    PDB0_SC = config | PDB_SC_SWTRIG;
    PDB0_CH0C1 = 0x0101;    
}

but for some reason when i stick that line inside my setup() it doesnt compile (doesnt recognice those names)
Ill try to work around that because you´re right , modifying the library isn´t a classy move.
 
From a reply I wrote where you asked this same question on an earlier thread.

------------------

Consider the loss of temporal resolution that comes with the increase in spectral resolution. A 1024 point FFT using 500 Hz sample rate will span 2 seconds of input data. If you're analysis is something like astronomy radio telescope signals, this finer resolution is probably worth the loss of timing. But for music, 2 seconds will usually span at least a few different notes and percussive events (beats of the music). Probably not useful for anything other than perhaps instrument tuning (which is much better done with the YIN algorithm than FFT).

This trade-off between temporal versus spectral resolution is a fundamental aspect of the Fourier Transform math. No amount of crafty software or wishful thinking can get around it. You could try other ways than FFT, but for Fourier Transform any increase in resolution for the spectrum comes at a cost of doing the analysis over a longer period of time.
 
From a reply I wrote where you asked this same question on an earlier thread.

------------------

Consider the loss of temporal resolution that comes with the increase in spectral resolution. A 1024 point FFT using 500 Hz sample rate will span 2 seconds of input data. If you're analysis is something like astronomy radio telescope signals, this finer resolution is probably worth the loss of timing. But for music, 2 seconds will usually span at least a few different notes and percussive events (beats of the music). Probably not useful for anything other than perhaps instrument tuning (which is much better done with the YIN algorithm than FFT).

This trade-off between temporal versus spectral resolution is a fundamental aspect of the Fourier Transform math. No amount of crafty software or wishful thinking can get around it. You could try other ways than FFT, but for Fourier Transform any increase in resolution for the spectrum comes at a cost of doing the analysis over a longer period of time.

Thanks Paul, you are right if i lower the sampling frecuency in order to zoom in lower frecuencies everything slows down.
I fixed this by finding the right frecuency that doesnt lag the process heavily and then just picking the lower bins i need.(sacrificing a bit of resolution)
 
Status
Not open for further replies.
Back
Top