Comment obtenir le spectre d’un signal en temps réel ?

NIVEAU 4

Objectifs

  • Calculer la FFT d’un signal analogique à l’aide d’une carte Nucléo
  • Afficher la FFT à l’aide d’une sortie analogique

Pré-requis

Coeur DSP sur Nucléo

DSP signifie Digital Signal Processor ou processeur de traitement de signaux numériques.

TO COMPLETE…

Pour cela, une bibliothèque, nommée mbed-dsp, est à votre disposition ici (ou ). Elle contient tous les objets en lien avec les filtres FIR et les méthodes permettant la mise en place de la structure matérielle associée à un filtre de type FIR.

Téléchargez cette bibliothèque dans un répertoire de votre ordinateur et importez-la dans votre projet (Cliquez droit sur votre projet, puis Import Library / From Import Wizard, puis Upload, sélectionnez le fichier zip contenant la bibliothèque, puis Import / Import).

Mise en oeuvre

Dans l’exemple suivant, on réalise la transformée de Fourier numérique d’un signal sonore récupéré à l’aide d’un microphone à électret amplifié.

Le signal analogique entrant sur l’une des broches de la carte Nucléo doit être compris entre 0 et 3.3V. Il est indispensable alors de modifier la valeur moyenne du signal pour qu’elle ait une valeur de 1.65V (la moitié de 3.3V).

Schéma de cablage

Noémie MARQUET (Promo 2021)

Code complet

Code proposé par Gary FOURNEAU (Promo 2021)

Ce code réalise une FFT sur 256 échantillons à une période d’échantillonnage de 40µs (soit une fréquence d’échantillonnage de 25kHz) sur un signal analogique appliqué sur A0 (signal à valeurs uniquement positives) et donne le résultat sous forme d’un signal analogique (sortie analogique A2), visualisable à l’oscilloscope.

#include "mbed.h"
#include "arm_math.h"
#include "dsp.h"
#include "arm_common_tables.h"
#include "arm_const_structs.h"

#define SAMPLES                 512             
/* 256 real party and 256 imaginary parts */
#define FFT_SIZE                SAMPLES / 2     
/* FFT size is always the same size as we have samples, so 256 in our case */
 
float32_t Input[SAMPLES];
float32_t Output[FFT_SIZE];
bool      trig=0;
int       indice = 0;

DigitalOut myled(LED1);
AnalogIn   myADC(A0);
AnalogOut  myDAC(A2);
Serial     pc(USBTX, USBRX);
Ticker     timer;
 
void sample(){
    myled = 1;
    if(indice < SAMPLES){
        Input[indice] = myADC.read() - 0.5f;    
        //Real part NB removing DC offset
        Input[indice + 1] = 0;                  
        //Imaginary Part set to zero
        indice += 2;
    }
    else{ trig = 0; }
    myled = 0;
}
 
int main() {
    float maxValue;            // Max FFT value is stored here
    uint32_t maxIndex;         // Index in Output array where max value is

    while(1) {
        if(trig == 0){
            timer.detach();
            // Init the Complex FFT module, intFlag = 0, doBitReverse = 1
            //NB using predefined arm_cfft_sR_f32_lenXXX, in this case XXX is 256
            arm_cfft_f32(&arm_cfft_sR_f32_len256, Input, 0, 1);
 
            // Complex Magniture Module put results into Output(Half size of the Input)
            arm_cmplx_mag_f32(Input, Output, FFT_SIZE);
            Output[0] = 0;
            //Calculates maxValue and returns corresponding value
            arm_max_f32(Output, FFT_SIZE/2, &maxValue, &maxIndex);
        
            myDAC=1.0f;     //SYNC Pulse to DAC Output
            wait_us(20);    //Used on Oscilliscope set trigger level to the highest
            myDAC=0.0f;     //point on this pulse 
    
            for(int i=0; i < FFT_SIZE / 2; i++){
                myDAC=(Output[i]) * 0.9f;   // Scale to Max Value and scale to 90 / 100
                wait_us(10);                //Each pulse of 10us is 50KHz/256 = 195Hz resolution
            }
            myDAC=0.0f;

            pc.printf("MAX = %lf, %d \r\n", maxValue, maxIndex);

            trig = 1;
            indice = 0;
            timer.attach_us(&sample,40);      //40us 25KHz sampling rate
        }
    }
}

MInE Prototyper Prototyper avec Nucleo et MBED

Nucleo – Obtenir le spectre d’un signal en temps réel / 4