Now that I have my SAMA5D4 development chain under control, it's time to do something with it. My first attempt is to move the Genuino sketch made for my light organ to the SAMA5D4. The design has 4 main steps: sampling, applying a Hamming window function, performing a FFT, drive leds
Moving C++ code from one environment to another is straightforward. In essence, the only thing I had to do is switch out the Arduino analogread() and digitalwrite() functions for the SAMA5D4 counterparts.
This is such a boring exercise that I'm not going to blog about it. |
Partly Success
The porting exercise went really smooth. My code passed the build in less than an hour. When I ran it on the board, the results were promising.
The sampling worked, and the LEDS were flashing.
But the code failed in a part that I didn't expect: the signal processing part.
I did not get a led pattern that was consistent with the Arduino. Even if I applied a single sinus, all 3 leds were flashing.
With a light organ,you expect that the high led is dim when you apply a low frequency input. On my SAMA5D4, the 3 leds were flashing in a pattern, whatever frequency I applied to the input.
Debug Time
So it's time to debug. The symptoms point to an issue with the signal processing. So I created a testbed on both systems that just do that.
I give the program a fixed array with samples (the same array on both boards).
Then I check the output after the Hamming function and after the FFT.
Here's a subset of the SAMA5D4 output:
samada fixed sample string: samples : 0,7,14,21,28,35,42,49,56,63,70,77,84,91,98,105,112,119,126,-123,-116,-109,-102,-95,-88,-81,-74,-67,... window : 0,0,0,0,0,0,0,1,2,3,4,5,7,9,11,13,16,19,23,-25,-26,-26,-27,-27,-27,-27,-26,-25,-24,-22,-20,-18,-16,-13,-9,-6,-2... fft : 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
And this is the known good result from the Arduino:
Arduino fixed sample string samples 0,7,14,21,28,35,42,49,56,63,70,77,84,91,98,105,112,119,126,-123,-116,-109,-102,-95,-88,-81,-74,-67,... window 0,0,0,0,0,0,0,1,2,3,4,5,7,9,11,13,16,19,23,-25,-26,-26,-27,-27,-27,-27,-26,-25,-24,-22,-20,-18,-16,-13,-9,-6,-2... fft 9,1,17,226,34,1,26,82,16,9,17,49,2,10,17,5,5,5,13,2,4,13,5,2,2,9,2,1,4,5,1,4,4,1,1,5,1,2,0,5,5,1,2,1,2,1,4,0,4,1,1,5,1,4,1,4,13,2,0,1,5,1,1,1,
It's obvious, isn't it? My port from the FFT lib from Arduino to SAMA5D4 has issues.
I'll spend some quality time to see where I made mistakes in the port of that FFT lib. I'll post my findings in a next blog.
For reference, here are the two test beds.
Arduino:
#include <fix_fft.h> #define MUESTRAS 128 // Numero de muestras para el cálculo de la FFT #define LOGM 7 // Logaritmo en base 2 del número de muestras #define BAJOS_MEDIOS 7 // Nº de banda para el corte entre Bajos y Medios #define MEDIOS_AGUDOS 35 // Nº de banda para el corte entre Medios y Agudos #define MAX_PASADAS 10 // Nº de pasadas para el cálculo de los lÃmites char data[MUESTRAS] = {0,7,14,21,28,35,42,49,56,63,70,77,84,91,98,105,112,119,126,-123,-116,-109,-102,-95,-88,-81,-74,-67,-60,-53,-46,-39,-32,-25,-18,-11,-4,3,10,17,24,31,38,45,52,59,66,73,80,87,94,101,108,115,122,-127,-120,-113,-106,-99,-92,-85,-78,-71,-64,-57,-50,-43,-36,-29,-22,-15,-8,-1,6,13,20,27,34,41,48,55,62,69,76,83,90,97,104,111,118,125,-124,-117,-110,-103,-96,-89,-82,-75,-68,-61,-54,-47,-40,-33,-26,-19,-12,-5,2,9,16,23,30,37,44,51,58,65,72,79,86,93,100,107,114,121}; // Array con los valores muestreados (parte real) char im[MUESTRAS]; // Array con los valores muestreados (parte imaginaria) unsigned char salida[MUESTRAS/2]; // Valores obtenidos de la FFT (espectro de 64 bandas) unsigned char bajos,medios,agudos; // Valores calculados para cada canal byte pasada, // nº de pasada para el cáculo de los lÃmites acumBajos,acumMedios,acumAgudos, // acumuladores de veces que se supera el lÃmite limBajos,limMedios,limAgudos; // lÃmites calculados para cada canal /* * Funcion que aplica una ventana de Hann a los datos muestreados para reducir el * efecto de las discontinuidades en los extremos */ void aplicaVentana (char *vData) { double muestrasMenosUno = (double(MUESTRAS) - 1.0); // Como la ventana es simétrica , se calcula para la mitad y se aplica el factor por los dos extremos for (uint8_t i = 0; i < MUESTRAS/2 ; i++) { double indiceMenosUno = double(i); double ratio = (indiceMenosUno / muestrasMenosUno); double factorPeso = 0.5 * (1.0 - cos(6.28 * ratio)); vData[i] *= factorPeso; vData[MUESTRAS - (i + 1)] *= factorPeso; } } void setup() { Serial.begin(9600); // Variables para el cálculo de los lÃmites pasada = 0; acumBajos = acumMedios = acumAgudos = 0; limBajos = limMedios = limAgudos = 50; } void loop() { // Realizamos el muestreo for( int i=0; i < MUESTRAS; i++) { im[i] = 0; // parte imaginaria = 0 } Serial.println(" samples\n"); for( int i=0; i < MUESTRAS; i++) { Serial.print(data[i], DEC); Serial.print(","); } Serial.println(" ---"); // Aplicamos la ventana de Hann aplicaVentana (data); Serial.println(" window\n"); for( int i=0; i < MUESTRAS; i++) { Serial.print(data[i], DEC); Serial.print(","); } Serial.println(" ---"); // Calculamos la FFT fix_fft(data,im,LOGM,0); // Sólo nos interesan los valores absolutos, no las fases, asi que // calculamos el módulos de los vectores re*re + im*im. // Dado que los valores son pequeños utilizamos el cuadrado for (int i=0; i < MUESTRAS/2; i++){ salida[i] = data[i] * data[i] + im[i] * im[i]; } Serial.println(" result²²\n"); for( int i=0; i < MUESTRAS/2; i++) { Serial.print(salida[i], DEC); Serial.print(","); } Serial.println(" ---"); }
SAMA5D4:
/* * main.cpp * * Created on: May 16, 2015 * Author: Jan * * * */ #include <iostream> #include <fstream> #include <string> #include <stdlib.h> #include <math.h> #include "fix_fft.h" #include "unistd.h" using namespace std; #define MUESTRAS 128 #define LOGM 7 // Logaritmo en hige 2 del número de muestras #define BAJOS_MEDIOS 7 // Nº de banda para el corte entre Bajos y Medios #define MEDIOS_AGUDOS 35 // Nº de banda para el corte entre Medios y Agudos int data[MUESTRAS] = {0,7,14,21,28,35,42,49,56,63,70,77,84,91,98,105,112,119,126,-123,-116,-109,-102,-95,-88,-81,-74,-67,-60,-53,-46,-39,-32,-25,-18,-11,-4,3,10,17,24,31,38,45,52,59,66,73,80,87,94,101,108,115,122,-127,-120,-113,-106,-99,-92,-85,-78,-71,-64,-57,-50,-43,-36,-29,-22,-15,-8,-1,6,13,20,27,34,41,48,55,62,69,76,83,90,97,104,111,118,125,-124,-117,-110,-103,-96,-89,-82,-75,-68,-61,-54,-47,-40,-33,-26,-19,-12,-5,2,9,16,23,30,37,44,51,58,65,72,79,86,93,100,107,114,121}; // Array con los valores muestreados (parte real) int im[MUESTRAS]; // Array con los valores muestreados (parte imaginaria) #define MAX_PASADAS 10 // Nº de pasadas para el cálculo de los lÃmites unsigned int salida[MUESTRAS/2]; // Valores obtenidos de la FFT (espectro de 64 bandas) unsigned int bajos,medios,agudos; // Valores calculados para cada canal uint pasada, // nº de pasada para el cáculo de los lÃmites acumBajos,acumMedios,acumAgudos, // acumuladores de veces que se supera el lÃmite limBajos,limMedios,limAgudos; // lÃmites calculados para cada canal int toint(std::string s) { return atoi(s.c_str()); } /* * Funcion que aplica una ventana de Hann a los datos muestreados para reducir el * efecto de las discontinuidades en los extremos */ void aplicaVentana (int *vData) { double muestrasMenosUno = (double(MUESTRAS) - 1.0); // Como la ventana es simétrica , se calcula para la mitad y se aplica el factor por los dos extremos for (int i = 0; i < MUESTRAS/2 ; i++) { double indiceMenosUno = double(i); double ratio = (indiceMenosUno / muestrasMenosUno); double factorPeso = 0.5 * (1.0 - cos(6.28 * ratio)); vData[i] *= factorPeso; vData[MUESTRAS - (i + 1)] *= factorPeso; } } int main() { string line; int i = 0; while(1) { // get samples for( i=0; i < MUESTRAS; i++) { // data[i] = i*14-128; //Convertimos de 0..1024 a -128..127 im[i] = 0; // parte imaginaria = 0 } cout << "\nsamples :\n"; for( i=0; i < MUESTRAS; i++) { cout << data[i] << ","; } cout << "\n"; // Aplicamos la ventana de Hann aplicaVentana (data); cout << "\nwindow :\n"; for( i=0; i < MUESTRAS; i++) { cout << data[i] << ","; } cout << "\n"; // Calculamos la FFT fix_fft(data,im,LOGM,0); // Sólo nos interesan los valores absolutos, no las fases, asi que // calculamos el módulos de los vectores re*re + im*im. // Dado que los valores son pequeños utilizamos el cuadrado for (i=0; i < MUESTRAS/2; i++){ salida[i] = data[i] * data[i] + im[i] * im[i]; } cout << "\nresults :\n"; for( i=0; i < MUESTRAS/2; i++) { cout << salida[i] << ","; // this was the biggest mistake. I had a '1' where I should have put an 'i', hard to spot the difference } cout << "\n"; break; // this MUST be removed!!!!!!!!!!!!!!!!!!!!!!!!!!! } return 0; }
Top Comments