ATTiny FHT question

I don't think this concern is related to the specific library I'm using but for the record, I'm using a lib called Fix_FFT, which is supposed to be a butchered version of FFT that will function on a Tiny. It "appears" to work, spitting out values that do change (albeit the output only seems to be 0, 1, 2 or 3 at the most).

The problem is, I have come to understand that the FFT buckets you get on the output array are evenly spaced across the sampled frequency. What is the sampled frequency? For the longest time I tried to figure out how to set that and I believe now it is actually the ADC capture frequency that determines it. Set the ADC capture frequency to 1MHz for example, it takes 13 clocks to grab a value, so that's 77 KHz and then by Nyquist, you can get an accurate sampling at half that rate so that means 38KHz. This would then be split into 64 buckets, each 601 Hz in size.

In my case, I want to do a knock sensor for a car. I've estimated the knock to be at 6500 Hz. Now if I set ADPS2 and ADPS1 bits per the datasheet, that yields a prescaler of 64. 16500000 / 64 is 257812Hz and with 13 clocks per sampling, you get 19831 Hz. Then by Nyquist, halving that you get, 9916 Hz. If this is split into 64 buckets, each bucket is 155 Hz and 6500 Hz would be bucket #42.

Putting that aside for the moment, normally if you do an FFT in open air, you'll get a lot of noise on the first bucket where all the 60 Hz noise would be and then a bunch of nothing after that. This is precisely what I get if I don't touch the prescaler bits at all (30 something on bucket 0 and 0,1,2 on bucket 1). However if I set the prescaler bits to 1 1 1, which is 128 (and this is supposed to be the default, so no change at all), Then I get all 1s on bucket 0. It makes no sense. It's like setting the bits somehow breaks the FFT. But I need to set the bits to get the resolution I want.

Can anyone shed some light on this? If you have a Digispark Tiny85 this code should compile and work with no additional effort. You merely have to place your cursor in a notepad window because the program will spew numbers into whatever your cursor is on due to the keyboard library.

#include <fix_fft.h>
//#include <TinyWireM.h>
#include "DigiKeyboard.h"

byte i = 0;
int8_t data[128];
int8_t im[128];
byte sent = 0;

void setup() {

  ADCSRA = (1 << ADPS2) | (1 << ADPS1); // approx 10kHz sample rate
//  ADCSRA = (1 << ADPS0);
//  ADMUX = 00000001; // use adc1
//  DIDR0 = 00000100; // turn off the digital input for adc1

//  TinyWireM.begin();

}

void loop() {

  for (i=0; i < 128; i++){  
    data[i] = analogRead(PB3)*0.25-128;
    im[i] = 0; 
  }

  fix_fft(data,im,7,0);

  for (i=0; i< 64;i++)  //real val is for the amplitude 
    data[i] = sqrt(data[i] * data[i] + im[i] * im[i]); 

  sent = data[16];
  DigiKeyboard.println(data[1]);

 // TinyWireM.beginTransmission(1);     // Begin transmission mode to slave 1
  //TinyWireM.send(sent);               // Send 1 byte to the mega  
  //TinyWireM.endTransmission();        // End transmission

    
}

The resolution of the FFT is simply the sampling frequency divided by the size of the FFT.

So sampling at 77kSPS with 64-size FFT gives 64 buckets of size 1203Hz, ranging from -38.5kHz
to +38.5kHz

FFT is defined as a complex transform so shows positive and negative frequency buckets - if you give
an FFT real-valued samples the positive and negative buckets are redundant. This is by far the commonest
case.

Some FFT implementations hide the negative buckets from you, so you need to double check the code
actually used, but if you put 64 samples in, you'll only have 32 useful buckets out, whether it returns
all 64 or not.

BTW did you intend the subject line to be about the Fast Hartley Transform?

I believe this particular implementation is a misnomer because it is labelled FFT but is actually an FHT (note how the imaginary values are nullified on input).

In my case, I just want 6500 Hz in the smallest possible bucket, which I thought was prescaler 64. However what you are saying is that you don't divide by 2 for Nyquist first? So instead of my presumed 10KHz divided into 64 buckets it's actually 20 KHz divided into 64 buckets? So I should use 128 prescaler instead?

Also, the input array is 128 elements so there are 64 actual outputs.

I'm just puzzled by the weird outputs I'm getting especially when setting the prescaler to the exact same value that it already is by default.

If its not an FFT my answer may not apply, they are different transforms.

Perhaps. I don't doubt that they are different mathematical models. However my gut tells me that this is an FFT... "sans" the imaginary part. It is probably just a nerfed FFT.

Furthermore, the symptoms I'm experiencing manifest from changing the prescaler register, which would seem to be a separate issue. Or, maybe I should say that if the FFT works on default settings, then changing a register on the chip for the ADC sampling rate, shouldn't break the FFT algorithm. It doesn't change the nature of how it samples voltages. Merely changes the speed at which this is done. That's why I'm thinking there's something silly wrong with the sketch or I'm not doing what I think I'm doing.

Do you have a Tiny to compile the code on? You would quickly see what I mean if you comment/uncomment the prescaler bits at the top. Both settings seem to literally work but with very different results when you look at buckets 0 and 1 for example.