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

Thread: set min/max frequency with AudioAnalyzeFFT1024?

  1. #1
    Junior Member
    Join Date
    Nov 2012
    Location
    SJ, CA
    Posts
    7

    set min/max frequency with AudioAnalyzeFFT1024?

    Is there a way to set the min and max frequency that the audio board will read with using AudioAnalyzeFFT1024?

    i believe it by default "listens" to something like 0 Hz up to 3000 Hz (just a random guess) or something like that. Id like to make a visualizer that only uses frequencies between 60 and 1200 Hz.

    Thanks,

    Greg

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,785
    You don't have to read all the frequency bins. Just read the ones you want and ignore the rest.

    If you're asking about the internal design within the library, consider these 2 things.

    1: Fast Fourier Transform always computes all the frequency bins. They're not computed in a sequential manner where you could just stop early. The "fast" nature of FFT is a tricky algorithm which essentially divides the range in half, then in half again, and again and again as it computes everything. So by doing less work, you can choose to have 128 or 256 bins instead of 512, but by nature of how the FFT algorithm works, you always get a power-of-2 number of frequency bins and they are always linearly distributed across the entire frequency range (from DC to half the sample rate).

    2: Even Teensy 3.2 is plenty fast enough to compute 1024 point FFT (resulting in 512 frequency bins) with 50% overlaps, keeping up with 44.1 kHz sample rate and leaving plenty of CPU time left over for your code to actually do something with the data.

    So it isn't feasible for the library to compute only part of the frequency range, but you can simple read only the frequency range you want and ignore the rest. Easy stuff.

  3. #3
    Senior Member
    Join Date
    Jul 2020
    Posts
    734
    Quote Originally Posted by mohawkpiper View Post
    i believe it by default "listens" to something like 0 Hz up to 3000 Hz (just a random guess) or something like that.
    no idea where you got that from. FFTs always generate entire spectra.

    Id like to make a visualizer that only uses frequencies between 60 and 1200 Hz.
    What frequency resolution do you want? The audio lib 1024-point FFT at 44100 samples/second has a bin size of 43Hz (44100/1024).
    For greater resolution you'll need something more sophisticated, like low-pass filtering, resampling to a lower sample rate and a
    bespoke FFT of the result.

    Filtering down to 1.5kHz bandwidth, then decimating the sample-rate by 8 would give 5.5kSPS, allowing an FFT bin-size
    of about 5Hz if 1024-point FFT is employed.

    If there's enough memory you could also just use a larger FFT (although the built-in FFT libraries are somewhat limited
    IIRC for ARM processors). 8192-point FFT direct on 44.1kSPS would give 5Hz bins, at the expense of more work and much
    more RAM.

  4. #4
    Junior Member
    Join Date
    Nov 2012
    Location
    SJ, CA
    Posts
    7
    Quote Originally Posted by MarkT View Post
    no idea where you got that from. FFTs always generate entire spectra.
    it was just a random guess based off im reading from a guitar pickup. a guitar's frequencies range roughly 80Hz to 1200Hz. If i pluck the highest note, on my LED strip, the LEDs display up to just below halfway along the strip. Thanks for educating me though.

    Quote Originally Posted by MarkT View Post
    What frequency resolution do you want?
    I have a strip of 66 LEDs, and each LED is mapped to a band. I am using the brightness of each LED to show the volume of the band (so just 1 led per band on a strip, as opposed to how ppl do it often with a grid). so i guess i was looking for roughly 17Hz per bin (if thats 80->1200Hz).

    Quote Originally Posted by PaulStoffregen;
    You don't have to read all the frequency bins. Just read the ones you want and ignore the rest.
    I think this is what I'm doing currently. (but after these replies and looking through it again maybe not a good way, my current way works... it's just not as pretty as id like it.)

    I guess I just figured all those frequencies i wasn't using were extra wasted computations so why not just grab only the frequencies i wanted. But it sounds like its fastest to get em all the way its already doing it.

    I think i've just had a rough time understanding what bins are entirely. But after looking at these replies i think im getting a feel for it.

    I am using the logarithmic function for FFT bin selection for any given number of bands link found in the SpectrumAnalyzerBasic sketch... and i think i got bands and bins confused... originally thinking i had 66 bins (one for each of the 66 leds on my strip) but i in fact have 512 bins (always 512 with FFT1024) but 66 bands (not bins), each band using a range of those bins.

    currently im remapping my bands to get what i want, so i took bands 0-66 and remapped bands 2-18 to fill 0-66, but it looks like i should remap the bins that the bands use.

    aight ill play with this a bit... ill report back if this was helpful or if im still lost :P

    thanks a ton, i feel like this is all pretty helpful

  5. #5
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,504
    There are FFT samples that show bins grouping and plotting - maybe in the audio tutorial IIRC But there is also a text display version to SerMon of the bin levels.

    There are some good years old threads on FFT.

  6. #6
    Junior Member
    Join Date
    Nov 2012
    Location
    SJ, CA
    Posts
    7
    Thanks for all this. I got it looking nicer than it was. I am pretty happy with it.

    Although a bin size smaller than 43Hz would be nice (even just half) i don't understand this here...

    Quote Originally Posted by MarkT View Post
    Filtering down to 1.5kHz bandwidth, then decimating the sample-rate by 8 would give 5.5kSPS, allowing an FFT bin-size
    of about 5Hz if 1024-point FFT is employed.
    and i tried editing the libraries to do this | for a 2048 point FFT
    v
    Quote Originally Posted by MarkT View Post
    If there's enough memory you could also just use a larger FFT (although the built-in FFT libraries are somewhat limited
    IIRC for ARM processors). 8192-point FFT direct on 44.1kSPS would give 5Hz bins, at the expense of more work and much
    more RAM.
    but i just froze up the teensy so I guess since im happy enough with it ill just leave it be.

    Here is what I been working on btw... it's been a lot of fun...


    I even found the note frequency function and added this into it later...


    I really got the tuner dialed in after the video. its more accurate than the clip on.

    I couldn't have done it without the help of the forums (i haven't really said much til now but I been looking around a lot) and Paul's teensy (and audio board, but the first video is pre-audio board.)

    I really have just one issue to work out still...
    the LED's produce some kind of interference (some sort of humming or buzzing) through the pickups.

    Anybody have any ideas how to get rid of that?

    it isn't necessarily in the circuit, i can use an led strip from an entirely different circuit and put it close to the pickup and the pickup will grab the noise.

    I found that steel works pretty well in shielding it... but it's been difficult to say the least in building a steel barrier around the leds inside the guitar.

    G

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,546
    If the audio is suitably bandwidth-limited, you could lower the sampling rate, for example to 8kHz, and get much higher resolution from the FFT - a bit less than 8Hz per bin. The highest frequency would then be 4kHz. At 8Hz per bin you might have to average some of the bins together since there would be 150 bins up to 1200Hz.
    The setI2SFreq function is used to change the sampling frequency. Here's my current version which has a fix to allow 8kHz sampling rate on T4.x - it will also work on T3.6
    Just use SetI2SFreq(8000) in the setup function.

    setI2SFreq.cpp
    Code:
    #include <Arduino.h>
    #include <Audio.h>
    #include "setI2SFreq.h"
    
    unsigned int sample_rate_real;
    
    #ifdef __IMXRT1062__
    // For set_audioClock on T4.x
    #include <utility/imxrt_hw.h>
    // Teensy 4.0, 4.1
    int setI2SFreq(int freq) {
    int n1;
      // PLL between 27*24 = 648MHz und 54*24=1296MHz
    //>>> Fudge to handle 8kHz - El Supremo
      if(freq > 8000) {
        n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
      } else {
        n1 = 8;
      }
      
      int n2 = 1 + (24000000 * 27) / (freq * 256 * n1);
    //>>> El Supremo - make sure n2 fits into 6 bits
      if(n2 > 63) {
        // n2 must fit into a 6-bit field
        Serial.printf("ERROR: n2 exceeds 63 - %d\n",n2);
        return 0;
      }
    
      double C = ((double)freq * 256 * n1 * n2) / 24000000;
    //  Serial.printf("%6d : n1 = %d, n2 = %d, C = %12.6f ",freq,n1,n2,C);
      int c0 = C;
      int c2 = 10000;
      int c1 = C * c2 - (c0 * c2);
    //  Serial.printf("c0 = %d, c1 = %d, c2 = %d\n",c0,c1,c2);
      set_audioClock(c0, c1, c2, true);
      CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
                   | CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07
                   | CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f
    
    //START//Added afterwards to make the SAI2 function at the desired frequency as well.
    
      CCM_CS2CDR = (CCM_CS2CDR & ~(CCM_CS2CDR_SAI2_CLK_PRED_MASK | CCM_CS2CDR_SAI2_CLK_PODF_MASK))
                   | CCM_CS2CDR_SAI2_CLK_PRED(n1 - 1) // &0x07
                   | CCM_CS2CDR_SAI2_CLK_PODF(n2 - 1); // &0x3f)
    //END//Added afterwards to make the SAI2 function at the desired frequency as well.
      // For compatibility with my T3.6 version
      return freq;
    }
    #else
    // Assume it is T3.6
    int setI2SFreq(int freq)
    {
      typedef struct {
        uint8_t mult;
        uint16_t div;
      } tmclk;
    
      const int numfreqs = 14;
      const int samplefreqs[numfreqs] = { 8000, 11025, 16000, 22050, 32000, 44100, (int)44117.64706 , 48000, 88200, (int)44117.64706 * 2, 96000, 176400, (int)44117.64706 * 4, 192000};
    
    #if (F_PLL==16000000)
      const tmclk clkArr[numfreqs] = {{16, 125}, {148, 839}, {32, 125}, {145, 411}, {64, 125}, {151, 214}, {12, 17}, {96, 125}, {151, 107}, {24, 17}, {192, 125}, {127, 45}, {48, 17}, {255, 83} };
    #elif (F_PLL==72000000)
      const tmclk clkArr[numfreqs] = {{32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {128, 1125}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375}, {249, 397}, {32, 51}, {185, 271} };
    #elif (F_PLL==96000000)
      const tmclk clkArr[numfreqs] = {{8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {32, 375}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125}, {151, 321}, {8, 17}, {64, 125} };
    #elif (F_PLL==120000000)
      const tmclk clkArr[numfreqs] = {{32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {128, 1875}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625}, {178, 473}, {32, 85}, {145, 354} };
    #elif (F_PLL==144000000)
      const tmclk clkArr[numfreqs] = {{16, 1125}, {49, 2500}, {32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {4, 51}, {32, 375}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375} };
    #elif (F_PLL==168000000)
      const tmclk clkArr[numfreqs] = {{32, 2625}, {21, 1250}, {64, 2625}, {21, 625}, {128, 2625}, {42, 625}, {8, 119}, {64, 875}, {84, 625}, {16, 119}, {128, 875}, {168, 625}, {32, 119}, {189, 646} };
    #elif (F_PLL==180000000)
      const tmclk clkArr[numfreqs] = {{46, 4043}, {49, 3125}, {73, 3208}, {98, 3125}, {183, 4021}, {196, 3125}, {16, 255}, {128, 1875}, {107, 853}, {32, 255}, {219, 1604}, {214, 853}, {64, 255}, {219, 802} };
    #elif (F_PLL==192000000)
      const tmclk clkArr[numfreqs] = {{4, 375}, {37, 2517}, {8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {1, 17}, {8, 125}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125} };
    #elif (F_PLL==216000000)
      const tmclk clkArr[numfreqs] = {{32, 3375}, {49, 3750}, {64, 3375}, {49, 1875}, {128, 3375}, {98, 1875}, {8, 153}, {64, 1125}, {196, 1875}, {16, 153}, {128, 1125}, {226, 1081}, {32, 153}, {147, 646} };
    #elif (F_PLL==240000000)
      const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
    #endif
    
      for (int f = 0; f < numfreqs; f++) {
        if ( freq == samplefreqs[f] ) {
          while (I2S0_MCR & I2S_MCR_DUF) ;
          I2S0_MDR = I2S_MDR_FRACT((clkArr[f].mult - 1)) | I2S_MDR_DIVIDE((clkArr[f].div - 1));
          return round(((float)F_PLL / 256.0) * clkArr[f].mult / clkArr[f].div); //return real freq
        }
      }
      return 0;
    }
    #endif
    
    void set_sample_rate(int sr)
    {
      switch(sr) {
      case SAMPLE_RATE_8K:
        sample_rate_real = 8000;
        break;
      case SAMPLE_RATE_11K:
        sample_rate_real = 11025;
        break;
      case SAMPLE_RATE_16K:
        sample_rate_real = 16000;
        break;
      case SAMPLE_RATE_22K:
        sample_rate_real = 22050;
        break;
      case SAMPLE_RATE_32K:
        sample_rate_real = 32000;
        break;
      case SAMPLE_RATE_44K:
        sample_rate_real = 44100;
        break;
      case SAMPLE_RATE_48K:
        sample_rate_real = 48000;
        break;
      case SAMPLE_RATE_88K:
        sample_rate_real = 88200;
        break;
      case SAMPLE_RATE_96K:
        sample_rate_real = 96000;
        break;
      case SAMPLE_RATE_176K:
        sample_rate_real = 176400;
        break;
      case SAMPLE_RATE_192K:
        sample_rate_real = 192000;
        break;
      }
      AudioNoInterrupts();
      sample_rate_real = setI2SFreq(sample_rate_real);
      if(sample_rate_real == 0) {
        Serial.printf("ERROR: failed to set sampling frequency\n");
        while(1);
      }
      delay(200); // this delay seems to be very essential !
    
      AudioInterrupts();
      delay(20);
    
    } // END function set_sample_rate
    and setI2SFreq.h
    Code:
    #ifndef SETI2SFREQ_H
    #define SETI2SFREQ_H
    
    
    #define SAMPLE_RATE_MIN               0
    #define SAMPLE_RATE_8K                0
    #define SAMPLE_RATE_11K               1
    #define SAMPLE_RATE_16K               2
    #define SAMPLE_RATE_22K               3
    #define SAMPLE_RATE_32K               4
    #define SAMPLE_RATE_44K               5
    #define SAMPLE_RATE_48K               6
    #define SAMPLE_RATE_88K               7
    #define SAMPLE_RATE_96K               8
    #define SAMPLE_RATE_176K              9
    #define SAMPLE_RATE_192K              10
    #define SAMPLE_RATE_MAX               10
    
    void set_sample_rate(int sr);
    int setI2SFreq(int freq);
    
    // Set by set_sample_rate
    extern unsigned int sample_rate_real;
    #endif
    Pete

Posting Permissions

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