In terms of hardware specs it seems the ATTiny85 ought to be able to run the FHT, even if it can't run 256 bins at full resolution but I have read that due to the Tiny's reduced instruction set, the code will not compile. Has there been any successful workaround for generic use of the FHT library on the Tiny? I really need to use this hardware to run a transform because of space restrictions. Thank you.
If you are referring to the OpenMusicLabs FHT, it is written mostly in assembler. Major task to rewrite.
So I take it by your response, that there is no ATTiny adaptation for FFT or FHT? I was looking forward to using a piece of hardware that was less wasteful of I/O for such a dedicated task and with an extra 0.5 MHz speed.
I don't know of one, and can't imagine why anyone would want to undertake the effort.
"Wasteful of I/O" is not a valid argument for using the ATTiny85 over an ATmega328, and neither is speed. Both are rated for 20MHz @ 5V.
Well, what I meant was, the Tiny is small and cheap and the board it's implemented on clocks it a tad faster so if you just need to analyze 1 waveform you only need 1 ADC so why waste a more expensive nano or uno with more pins when your project can't afford the space anyway? But I guess it's a moot point if it won't work on the Tiny. Thanks for answering anyway.
Interesting... I found this:
but the language barrier means the comments are difficult to figure out for me and he seems to have specifically catered this to do some light show on the audio he's recording. I was hoping it would be more generic and resemble the original library's basic functions. I guess I'll have to play with this for a while and see if I can brute-force it into working for my project.
The fix_fft(() function has been around for many years, and is written in C. No modifications required for the ATTiny series.
It seems so. However when I read the instructions on how to use the FHT library and then I read this guy's example code, it seems he's re-written all the method calls to suit his project, which is fine but it means I have to cut through the fat and get down to what the actual working methods are that I need. For example, how to set the number of bins, maximum frequency, FHT mode, etc.
I think I've more or less isolated the important parts of the code but I still can't figure out his math where he says the resolution is 500 Hz. I can't reproduce that through any scaling factors. Here's how I think it ought to be done:
CPU speed is 16.5 MHz on the Tiny
Use the ADC prescalar value of 32 so 16500000 / 32 = 515 KHz ADC clock
It takes 13 clocks to perform a conversion in free running mode so the sampling rate is 515/13 = 40 kHz
Since the FHT is mirrored, double-sided or whatever you call it, the largest sample frequency is 20 kHz
Most microphones don't have a frequency response higher than 20 kHz so there should be no aliasing
I am assuming that given the limited SRAM of the tiny, this is why max array size is 128
Therefore bin size being half of that (64) means bin size is 20000/64 = 309 Hz
These settings for the ADC yield 64 bins of 309Hz each. I don't know what the ADC bit depth would be at this sampling frequency but according to the Atmel data sheet, any sample frequency < 1MHz is ok and this is half of that so...
From all this I gather that if I use the fix_fft() library but change the ADC first to the above settings, I should be able to get 64 bins spanning 0Hz - 20 kHz and the Tiny should be able to handle it. Plus with such a compact board, short traces and noise reduction options on-chip, I should be able to read through a shielded cable without too much noise. Only problem is that this library seems to be set to logarithmic output and I don't want that so I may need to apply inverse log math to the output data to get linear magnitudes.
Only problem is that this library seems to be set to logarithmic output
What library? Post your code, using code tags, including the fix_fft function.
In the main fix_fft call he has a 7, which he explains is achieved by log'ing 128. I assume this means he's using the log transform instead of the linear one but maybe I'm wrong. As for how he got 500 Hz bins, I have no idea.
/*
fixFFT http://forum.arduino.cc/index.php/topic,38153.0.html
this should give an fft with
sampling rate: 1ms
frequency resolution: 500Hz
lowest frequency: 7.8Hz
*/
//shin: fft with attiny85, rgb led blend with frequency
#include <fix_fft.h>
int ledG = 1;//pwm
int ledR = 0;//pwm
int ledB = 2;//pwm
int mic = A2; //electret
char im[128];
char data[128];
char data_avgs[128];
//mix max val to map fft
int valMin = 0;
int valMax = 30;
//bias to reduce on low and increase on high
int bias = 0;//+- bias to output
//3 chn selected deliberately out of 64 bins by fft
int chnLow = 0; //blue
int chnMid = 6; //green
int chnHigh = 11; //red
//temp var for bands
int tempLow = 0;
int tempMid = 0;
int tempHigh = 0;
void setup(){
pinMode(ledG, OUTPUT);
pinMode(ledR, OUTPUT);
pinMode(ledB, OUTPUT);
pinMode(mic, INPUT);
}
void loop(){
int static i = 0;
static long tt;
int val;
randomSeed(analogRead(mic));
bias = random(70,150);
for (i=0; i < 128; i++){
val = analogRead(mic);
//data[i] = val / 4 - 128;
data[i] = val;//quick and dirty data.
im[i] = 0;
i++;
}//end for
//this could be done with the fix_fftr function without the im array.
fix_fft(data,im,7,0);
/*
Performs foward or inverse Fourier transform.
//fix_fft (char fr[], char fi[], int m, int inverse)
//fr is a real data set,
//fi is the imaginary data set,
// m is log2(n) where n is number of data points (log2 (128) = 7)
//0 is set for forward transform. 1 would be inverse transform. Apparently inverse does not work,
*/
// I am only interessted in the absolute value of the transformation
for (i=0; i< 64;i++){//real val is for the amplitude
data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
}//end for
//do something with the data values 1..64 and ignore im
//data avg moved to individual func
//shin: styles for colour mapping to frequency
//triChn(bias);
//triChn(0);//no bias
//style2
//grpChnLowPass();
//style3
treshChn();
}//end loop
void triChn(int bias){//read low, mid, high chn
for (int i=0; i<14; i++) {//
data_avgs[i] = data[i*4] + data[i*4 + 1] + data[i*4 + 2] + data[i*4 + 3]; // average together
//data_avgs[i] = map(data_avgs[i], 0, 30, 0, 9);// remap values for LOL(9rowx14col led)
data_avgs[i] = map(data_avgs[i], valMin, valMax, 0, 255);// remap values for RGB LED
}
//bias to give more blue to emphasise low freq
analogWrite(ledB, data_avgs[chnLow]);
analogWrite(ledG, data_avgs[chnMid]-(bias/2));
analogWrite(ledR, data_avgs[chnHigh]-bias);
}
void grpChnLowPass(){//grp low pas 32 out of 64 bins into grp of low mid high, avg out in grp
for (int i=0; i<14; i++) {//
data_avgs[i] = data[i*4] + data[i*4 + 1] + data[i*4 + 2] + data[i*4 + 3]; // average together
//data_avgs[i] = map(data_avgs[i], 0, 30, 0, 9);// remap values for LOL(9rowx14col led)
data_avgs[i] = map(data_avgs[i], valMin, valMax, 0, 255);// remap values for RGB LED
}
int numChn = 4;
for (int i=0; i<numChn; i++) { //14 bins grp into3 bands
//low chn
tempLow=data_avgs[i]+tempLow;
//mid chn
tempMid=data_avgs[(i+4)]+tempMid;
//high chn
tempHigh=data_avgs[i+8]+tempHigh;
}//end for
//avg across the grp
tempLow = tempLow / numChn;
tempMid = tempMid / numChn;
tempHigh = tempHigh / numChn;
//map freq to rgb on pwm pin
tempLow = map(tempLow, valMin, valMax, 0, 255);
tempMid = map(tempMid, valMin, valMax, 0, 255);
tempHigh = map(tempHigh, valMin, valMax, 0, 255);
//output to rgb
analogWrite(ledB, tempLow);
analogWrite(ledG, tempMid);
analogWrite(ledR, tempHigh);
}//grpChnLowPass
void treshChn(){//on if over threshold low, mid, high
for (int i=0; i<14; i++) {//only take lower half of real freq band eg 32 out of 64
data_avgs[i] = data[i*4] + data[i*4 + 1] + data[i*4 + 2] + data[i*4 + 3]; // average together
//data_avgs[i] = map(data_avgs[i], 0, 30, 0, 9);// remap values for LOL(9rowx14col led)
data_avgs[i] = map(data_avgs[i], valMin, valMax, 0, 255);// remap values for RGB LED
}
tempLow = data_avgs[chnLow];
tempMid = data_avgs[chnMid];
tempHigh =data_avgs[chnHigh];
if(tempLow>150){
//more low gives blue
analogWrite(ledB, tempLow);
analogWrite(ledG, 255);
analogWrite(ledR, 255);
//delay(100);
}
else if (tempMid>150){
//more mid gives green
analogWrite(ledB, 255);
analogWrite(ledG, tempMid);
analogWrite(ledR, 255);
//delay(100);
}
else if (tempHigh>150){
//more high gives red
analogWrite(ledB, 255);
analogWrite(ledG, 255);
analogWrite(ledR, tempHigh);
//delay(100);
}
else{
/*
//random colour not visual appealing to music
tempLow=random(0,255);
tempMid=random(0,255);
tempHigh=random(0,255);
*/
analogWrite(ledB, tempLow-70);
analogWrite(ledG, tempMid-100);
analogWrite(ledR, tempHigh-150);
//delay(100);
}
}//end treshChn
2^7 == 128 (the number of samples), and is required input to fix_fft().
The following posted code calculates the linear magnitude of the transform, i.e. the amplitude of the frequency component in each frequency bin.
for (i=0; i< 64;i++){//real val is for the amplitude
data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
}//end for
The frequency bin size depends on the CPU clock frequency, the number of sample bins and the ADC sample rate.
The comment in the code stating that the sample rate = 1 ms can't be correct and makes no sense. You can read up on how to set that here, but be sure to consult the ATTiny85 data sheet for the details.
Ok good to know you noticed the same discrepancy. I think the settings I posted for the ADC should work. Thanks for the advice.
Great. Do you think I can even find the correct libraries to make the code work?? Of course not.
I regret having to ask but, can you point me to the libraries that make the fix_fft method work? I seem to be having trouble getting the right combination of files. I gather this library was made some time ago so the Arduino version might also be a factor. I just wanna get the example running so that I can go off on my own and modify it for my application. Is there a reliable github folder with everything in it?
It appears that you are just copying stuff from other people's web sites, without taking the time to figure out what any of it does.
No libraries are required. The fix_fft function is just a function like any other, which you include in your code.
When your program calls the fix_fft function, it simply replaces the numbers in the arrays data[] and im[] with other numbers. It is up to you to provide useful numbers as input, and interpret the output.
If you look around, I'm sure that you can find some simple example that runs on an Uno. Get that working, and understand what it does, before moving to an ATTiny.
I have worked with the FFT and FHT libraries before. That was a whole other ball of wax that took me weeks to figure out. I just don't want to re-invent the wheel trying to figure out a modified version of it with no documentation to explain it. I assumed the fix_fft method must have an associated library.. otherwise how would the compiler know what constructor to call, what arguments it takes, etc.? Most custom functions are defined elsewhere so I assumed this is why it wouldn't compile. In fact there's explicit proof of this because there's an included header in the code that I do not have on my hard drive. Anyway I don't want to appear lazy but there are only so many hours in the day and sometimes one is in "educational mode" and other times is in "get the job done mode". Since I have put the time into understanding the openmusic FFT and FHT libraries and how they work, I don't feel an overwhelming compulsion to decrypt an obscure flavour of it that works on a similar but not quite the same architecture. Just want to get the code running so I can start chopping it down. The faster I can complete my projects, the faster I can make youtube videos demonstrating new applications, which is my way of paying it back.
it wouldn't compile
289 posts and you STILL haven't learned how to post an error message and ask a question intelligently?
Because I'm not so stupid that I can't figure out something is missing. There's a header include statement in the code trying to include a header that I don't have. The .h file aint on my computer. That's the problem. But anyway, I figured the website from which the code came would have the headers linked... it didn't so I'll just brute-force my way through google till I find it I guess.
Thread resurrection only because my question is directly related to the FHT library...
What is the SLOWEST sampling rate you can get the ADC to work at for the purposes of splitting the FHT buckets into smaller frequencies? Say for example I want each bucket to be 0.5 or 1 Hz for some low frequency sampling. Logic dictates I need to reduce the ADC sampling rate to twice the Nyquist frequency which would be something like 64Hz. Is this even possible? I know you can put a delay in the code but does the FHT library work like that?
The FHT library does not sample.
Your program does that, at any viable sampling frequency of your choosing, and calls the FHT routines with the final array of sampled values.