set min/max frequency with AudioAnalyzeFFT1024?

Status
Not open for further replies.
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
 
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.
 
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.
 
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.

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).

PaulStoffregen; said:
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
 
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.
 
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...

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
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
 
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
 
Status
Not open for further replies.
Back
Top