Se me ocurrió que sumcando y restando se podía calcular rápido el FFT de una señal analógica en arduino.
la salida digital 5 genera un tono de prueba
conectándola a la entrada A0 recibes la señal para medir.
Es una onda cuadrada luego tiene muchos armónicos y la señal no es exacta...
Esta bien de velocidad para un 8 bits
la muestra por la memoria de arduino (tamaño del FFT) esta en 512 bytes por cuestinoes de memoria RAM:
"Las variables Globales usan 823 bytes (40%) de la memoria dinámica, dejando 1225 bytes para las variables locales. El máximo es 2048 bytes."
Se puede subir como mucho a 1024 pero no se nota mucha mejoría
Aún necesita algo de pruebas y trabajo.
* con trigonometría es más preciso pero mucho más lento subiré el código. Estoy probando con señal de audio ahora sacada por una bobina (inducción) desde el ordenador y el audacity.
(Usar coseno para sumar y restar)
*parece que permite mucha resolución en frecuencias bajas (si se configura para poca frecuencia)
*si es suficientemente rapido y vale la pena, aunque enguarre el resultado (aun no lo se)
Un filtro de IA entrenada lo podría limpiar.
Hay placas con capacidad de aceleración de IA pequeñas.
Pues puede que haya distorsión por la onda cuadrada o los bloques que sumo y resto (sumo y sumo si hay onda jeje).
Una de las capacidades de las IA son cosas así.
Tal vez un raspberry pico más rápido y más pequeño pueda meter un algoritmo de red neuronal, pues para 20 o 30 bandas no hace falta aceleración y es para eliminar distorsión (aunque el raspberry seguro puede muchas más, no es una competición de todas formas, también esta el arduino due de 32 bits , este es de 8 bit igual no significa mucho pero en su día era la diferencia entre un spectrum y un amiga de los buenos o una recreativa Z80 era 8 bit y motorola 68000 de 16 y 32)
*estoy comparando la velocidad de este y otro a base de cosenos; no es tan lento como había pensado, estoy probando a pasarle frecuencias desde el ordenador con Audacity y por inducción (usando una bobina) creo que es más preciso pero cuesta de ajustar...
De momento el algoritmo antiguo es así espero actualizarlo pronto quiero provar bien el nuevo.
int latencia; int banda; int sumas; float media; float mediaL; int medias; int cont; int tamanyo; int tamanyoL; int sign; const int arraylength=512; byte valor[arraylength]; int salida; int iter; String text; float milisL; float freq; float freqM; float freqP; int contF; int masF; int threehold=25; // detección de picos; int rnd; void setup() { banda=0; cont=0; sign=1; Serial.begin(9600); pinMode(A0, INPUT); pinMode(5,OUTPUT); noTone(5); freqM=100; } void loop() { //rnd=random(0,123);//para ruido random TEST //valor[cont] = rnd;// para ruido random TEST //contF=700;// introducir frecuencia para medir arduino. TEST //tone (5,contF); // introducir frecuencia para medir arduino. TEST valor[cont] = analogRead(A0); cont=cont+1; if (cont>arraylength){ text=""; cont=0; banda=0; int mediavg; //FFT 2 for (int t=0;t<arraylength;t=t+1) { mediavg=mediavg+(-t%2)*(valor[t]); } mediavg=abs(mediavg/arraylength); //(1000ms / (frecuencia de la medición)ms)*2 // ej 1000ms / 200 ms * 2 = 10 Hz float bandas = 30; // numero de bandas; int chunk; for (int itera=1;itera<(bandas+1);itera=itera+1){ banda++; media=0; iter=0; // SE DEFINE EL TAMAÑO DEL TROZO Y SU INCREMENTO chunk=(itera+1); // SE PARTE EL ARRAY EN TROZOS tamanyo=(arraylength/chunk); // NOS QUEDAMOS UN NÚMERO PAR tamanyo=tamanyo-(tamanyo%2); sumas=0; medias=0; sign=1; // RECORREMOS EL ARRAY (tamanyo*chunk) CON UN TAMAÑO APROPIADO AL TROZO QUE USAMOS* chunk for (int a=0;a<((tamanyo)*chunk);a=a+(chunk)){ medias++; for (int i=a;i<(a+chunk);i=i+1){ media = media + (valor[sumas]); sumas++; } mediaL= mediaL + sign*(media); sign=sign*(-1); media=0; } salida=abs(mediaL/arraylength); // CALCULO FRECUENCIA freq=(((1000/freqM)*2)*medias); if (salida>threehold && salida>masF){ text="(" + String(round(freq),DEC) + "hz)" + text; masF=salida; freqP=freq; } else{ // text=String (round(salida), DEC)+"/"+ String(round(freq),DEC)+ "Hz " + text ; text=String (round(salida), DEC)+ " " + text ; } mediaL=0; masF=0; tamanyoL=tamanyo; } contF=contF+10; //recorre el espectro subiendo la frecuencia de 50 a 1000 noTone(5); //recorre el espectro subiendo la frecuencia de 50 a 1000 tone (5,contF+200); //recorre el espectro subiendo la frecuencia de 50 a 1000 if (contF>2000){contF=1;} //recorre el espectro subiendo la frecuencia de 50 a 1000 freqM=millis()-milisL; Serial.println("[EMITIDA:" + String(200+contF,DEC) + "] " + String(round(freqM),DEC) + "ms " + String(mediavg,DEC) + " -> " + text +" [CAPTADA PICO: " + String(freqP,DEC) + "Hz]"); freqP=0; milisL=millis(); } }