FHT low pass filter

So I am using fht, I found this post

I found out why I am getting aliasing. (bins 2-256 all get activated from anything more than 145hz)
in said post, jremington says I need a low pass filter. I am relatively new to arduino what does he mean by a low pass filter, and how can I do it cost-effectively.

You either need to sample at a much higher rate, or use an anti-aliasing filter before the ADC (a circuit using a few opamps, such as 4th order Butterworth low pass filter as Sallen Key). For instance: https://www.multisim.com/content/gGnfLtUMQBry2iWqsFzLij/4th-order-low-pass-sallen-key-filters/

Its much simpler to sample at a higher rate, like 48kHz, if your hardware can manage it.

i am using an arduino uno, how would I sample at a higher rate?

You change the prescaller register to the A/D.
You can push it to about 35 Ksps ( Samples per second )

Low pass filter

could you please elaborate on what you mean by "prescaller register to the a/d"? How would i change that in the code?

I'm not an expert on this, but the FFT/FHT algorithm has to "know" the sample rate so if there's not a function in the FFT library I'd expect it to be in the library documentation.

Well I can but I am not sure heaping more detail is going to help only confuse but here we go.

The A/D converter is clocked from the main system clock through a frequency divider circuit. A single stage divides the input frequency by two. Basically this is just an edge triggered D-type flip flop with the inverted output wired to the D input. Two stages in cascade will result in a division of four and each additional stage doubled the frequency division achieved.

On an Uno or Nano These work like this:-

There are three bits in an internal memory of the processor chip address 0x7A which is called the ADPS2 register that control the division ratio you get, as shown here:-


To change the division this divider gives you simply change those bits. The Arduino compiler knows about these register names and what address they correspond to so you can change them simply by writing to the three bits of the register without changing any of the other bits. So first you make just these three bits zero by using a logic AND operation on the contents of the register and then you use a logic OR to set these bits to what you want.
So to make the A/D faster you make the division of the prescaler smaller, but if it is too small then you loose accuracy on the resultant value. A division of 16 is a good compromise which means setting those bits to 0x04. This is done by the code

ADCSRA = (ADCSRA & 0xf8) | 0x04;

oh ok, ill add that to the code. Thanks!

Note that while that makes your analogRead faster that is not the only factor in determining the sample rate. The time for storing of the sample also adds to the time it takes to acquire a sample.

The only way to get a true measure of the sample rate is to set a digital pin at the start of you acquiring N samples and clear it when you have finished. Then measure the time this pin is high using an oscilloscope and divide that time by N. This gives the sample time, to get the sample rate then take the reciprocal of this.

Yon need the sample rate to make sense of the FFT results.

I don't know if that is a typo but I am using fht.
I don't need a super accurate decibel reading. I just need a relative sense of volume. I am comparing each frequency bin between left and right.

Blockquote ADCSRA = (ADCSRA & 0xf8) | 0x04;

whenever i replace ADCSRA = 0xe5; // set the adc to free running mode with that, my arduino cant read the adc and i dont get output

Have you looked at what the other bits do in that register? It is all in the processor’s data sheet, the way I showed you how to do it preserved bits in the register that you did not need or want to change.

I am using an Arduino uno. I found a datasheet but didn't find anything about bits. I'm sorry, I'm relatively new.
https://pdf1.alldatasheet.com/datasheet-pdf/view/422609/ATMEL/ATMEGA328.html

was I not supposed to put the part in parenthesis?
ADCSRA = (ADCSRA & 0xf8) | 0x04;
ADCSRA = 0x04;

It is always best to go to the manufacturer for the data sheet. Here is the most recent one for the ATmega328p: https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf

There you will find a complete discussion of the bits in the ADC control registers.

I'm not sure what you meant by the following code. The second statement in this series of two makes the first statement pointless:

ADCSRA = (ADCSRA & 0xf8) | 0x04;
ADCSRA = 0x04;

i put the top line into my code (replacing ADCSRA = 0xe5; // set the ADC to free-running mode)
but then i get no results at all.
i am currently getting aliasing. (any sound over 145 hz and bins 2-64 go crazy)
here is my code (slightly modified example from fht library)

 /*
fht_adc.pde
guest openmusiclabs.com 9.5.12
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.  there is a pure data patch for
visualizing the data.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 128 // set to 256 point fht
int fht_left[128];
int fht_right[128];

#include <FHT.h> // include the library

void setup() {
  Serial.begin(115200); // use the serial port
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
  while(1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    
    ADMUX = 0x40; // use adc0
    
    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    sei(); 
      for (int i = 0 ; i < FHT_N ; i++) { //fht_left = fht_output
        fht_left[i] = fht_log_out[i];
      };


  };
  for (int i=0; i< FHT_N/2; i++) {
    Serial.println(fht_log_out[i]);
  };
}

No surprise there. By "replacing" that statement, you turned off the bits setting the ADC to free running mode.

I take it you have not yet had time to look up the meaning of the bits in the ADCSRA register.

if I'm honest, I have no idea what an adcsra register is. But based on your response, I'm guessing that i need to put the top line under adcsra=0xe5, instead of replacing

There is actually no need to replace that line at all, or make any other changes to the code. As it is, it sets the ADC sample rate to 38 kHz.

If your input has signals with frequency higher that 19 kHz, you will have signal aliasing, which may make it impossible to interpret the results. A good low pass filter is the solution, or change the signal source.

Unfortunately this is a technical hobby, and if you want to get anywhere with it, you must learn to read the processor data sheet, and something about circuits.

It is as almost I never posted reply #8, or you never read it.

Find that piece of the table I posted from the data sheet in reply #8 and above it will be what all the other bits are. If you want to change the free running mode you will have to change both the mask of 0xf8 and the value of 0x04.

Try and understand what this line is doing. The first number 0xf8 is being anded with the value in the register. This means that all the bits in 0xf8 that are zero will result in those same bits in the ADCSRA register being zero. Then the OR with 0x04 results in all the bits with a one in them being set, then the resulting bit pattern is being placed back into the ADCSRA register.

0xf8 is the binary bit pattern 11111000
0x04 is the binary bit pattern 00000100