Bueno, estoy aprendiendo algo nuevo... Punto Fijo!
Como esto no me está funcionando como es eperado no me queda otra que estudiar bien como funciona!
Las librerías de DSP de las CMSIS estan programadas en punto flotante, para ser usada preferentemente con FPU por hardware, luego hay versiones para punto fijo Q1.31 y Q1.15. El tema es que no tenía idea como funcionaban esos formatos de punto fijo.
La primer referencia, wikipedia:
https://en.wikipedia.org/wiki/Q_(number_format)
Nuestro Q15 no es otra cosa que un typedef a un int16_t, por lo que el contenedor de nuestro Q15 es un número de 16 bits CON signo.
Entonces los que vale es:
Rango: [ -2
0 , 2
0-2
-15 ] = [ -1 , 0,999969482421875 ]
Pero com ose representan los números?
Bien, el primer bit es de signo. 1 -> números negativos. 0-> números positivos.
Luego los numeros positivos cada bit arrancando del 15 hacia el bit 0 valen 2
-n en este caso b15->n=1, b14-> n=2.
O sea:
0.99 = 0111 1111 1111 1111
0.75 = 0110 0000 0000 0000b
0.5 = 0100 0000 0000 0000b
0.25 = 0010 0000 0000 0000b
0 = 0b
Entonces lo que en número binarios comunes van del 0 al 0111 1111 1111 1111(32767o 0x7FFF) es el recorrido de 0 a 0.99999
Con los negativos es un poco menos intuitivo. Pero sería así
-1 = 1000 0000 0000 0000b
-0.75 = 1010 0000 0000 0000b
-0.5 = 1100 0000 0000 0000b
-0.25 = 1110 0000 0000 0000b
O sea que cuántos más 1 hay, mas chico es el número entonces vamos desde 1111 1111 1111 1111 (-0.0 o 0xFFFF) hasta 1000 0000 0000 0000(-1 ó 0x8000)
Luego para pasar de un número flotante a q15 hay que multiplicar por 2
15 y redondear al entero más cercano.
Sabido esto podemos hacer un programita de testeo de todo esto más la FFT.
La idea es crear un seno de 1.5Khz (1562Hz en realidad), muestreado a 10KHz en formato flotante (funcion sin de math.h) Luego pasarla a q15, hacer la FFT y calcular la magnitud de los resultados. Recordar que la salida de la FFT es en formato complejo (real, imaginario) y para obtener un valor "usable" hay que calcular la magnitud (y la fase si se quiere):
float fltSinWave[64];
q15_t q15SinWave[64];
q15_t q15FFT[128];
q15_t MAG_of_fft[64];
uint32_t F=1562;
uint32_t Fs = 10000;
uint8_t i;
for(i=0;i<64;i++)
{
// Seno discreto FLOTANTE
fltSinWave
[i
] = (sin(2*M_PI
*i
*F
/Fs
)); // Seno discreto en Q15
q15SinWave[i] = (q15_t)(fltSinWave[i] * (1<<15));
}
// Preparo el array de la FFT
for(i=0;i<128;i+=2)
{
q15FFT[i] = q15SinWave[i/2];
q15FFT[i+1] = 0;
}
// Calculo la FFT
arm_cfft_q15(&arm_cfft_sR_q15_len64, q15FFT, 0, 1);
// Calculo la magnitud de cada punto
arm_cmplx_mag_q15(q15FFT, MAG_of_fft, 64);
Corriendo esta parte en el uC obtengo:
fltSinWave
0, 0.831295013, 0.924119771, 0.196014598, -0.706217647, -0.981090546, -0.38442421, 0.553740382, 0.999996841, 0.557918906, -0.3797791, -0.980105221
q15SinWave
0, 27239, 30281, 6423, -23141, -32148, -12596, 18144, 32767, 18281, -12444, -32116
Aquí podemos verificar que 0.83129 en float es 27239 en q15. 27239 en binario es 0110 1010 0110 0111. Componiendo en q15 tenemos: 0.5 + 0.25 + 0.0625 + 0.015625 +.... sumando solo esos bits tenemos 0,828125 por lo que podemos verificar que el formato es el correcto.
El siguiente paso es armar un array con el doble de puntos necesario para la FFT.
Finalmente calculamos la FFT y la magnitud de cada bin.
La señal que creamos tiene 1562Hz por una razon. Si calculamos la resolucion de la FFT: Fs/Nfft = 10.000/64 = 156.25 Hz. Por lo que el centro de cada bin estará en un múltiplo de 156.25. En este caso 1562 (.5). En que bin deberíamos encontrar el pico de la FFT? 1562 / 156 = 10.
Cuando voy al visor de expresiones en el IDE obtengo esto para MAG_of_fft:
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8191, 0 <repeats 43 times>
Como ven tengo toda la potencia de la señal en el bin 10
Entonces ahora ya tengo funcionando la FFT y el cálculo de magnitud. Solo resta acomodar los datos del ADC en un q15. Eso queda para dentro de un rato.
Saludos