Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: FFT decreasing BW modifiying sampling frecuency?

  1. #1
    Member javiernicola's Avatar
    Join Date
    Apr 2018
    Location
    Madrid
    Posts
    20

    FFT decreasing BW modifiying sampling frecuency?

    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?
    Click image for larger version. 

Name:	a.jpg 
Views:	66 
Size:	57.0 KB 
ID:	13652
    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];
                     }
          }
    }

  2. #2
    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.

  3. #3
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    682
    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/...ode-=-Zoom-FFT

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

    https://github.com/DD4WH/Teensy-Conv...lution_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

  4. #4
    Member javiernicola's Avatar
    Join Date
    Apr 2018
    Location
    Madrid
    Posts
    20

    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
    Click image for larger version. 

Name:	Sin título.png 
Views:	54 
Size:	26.2 KB 
ID:	13663
    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

  5. #5
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    682
    Hi Javier,

    congratulations!

    Maybe it is better to not use a modification of the original Audio lib files? (but depends on your goals)

    The thread I meant is this one and it describes a simple way of changing sample rate for either the audio board, but also the ADC/DAC without having to change the audio lib files.

    https://forum.pjrc.com/threads/38753...nk+sample+rate

    Frank DD4WH

  6. #6
    Member javiernicola's Avatar
    Join Date
    Apr 2018
    Location
    Madrid
    Posts
    20
    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

  7. #7
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    682
    Im not using the audio board(shield)
    Yes, you said so.

    As far as I know, the proposed solution by Frank B also works without an audio shield (but I may be wrong):

    https://forum.pjrc.com/threads/38753...l=1#post121253

  8. #8
    Member javiernicola's Avatar
    Join Date
    Apr 2018
    Location
    Madrid
    Posts
    20
    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.

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,061
    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.

  10. #10
    Member javiernicola's Avatar
    Join Date
    Apr 2018
    Location
    Madrid
    Posts
    20
    Quote Originally Posted by PaulStoffregen View Post
    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)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •