Analyseur de spectre

Objectif : réaliser un analyseur de spectre (son, lumière, …) et afficher le résultat sur un écran LCD

Présentation

Décomposition de Fourier Discrète

Tout signal périodique peut être décomposé en une somme de signaux sinusoïdaux (série de Fourier) appelées harmoniques :

\(u_m(t)=U_0+\displaystyle \sum_{k=1}^\infty U_k\sqrt{2}\sin\left(2\pi f_k\cdot t+\varphi_k\right)\)

avec :

  • \(U_0\) : valeur moyenne de \(u_m(t)\)
  • \(U_k\) : valeur efficace de l’harmonique de rang \(k\)
  • \(f_k\) : fréquence de l’harmonique de rang \(k\)
  • \(\varphi_k\) : phase de l’harmonique de rang \(k\)

Cette décomposition permet de représenter un signal sous forme fréquentielle :

Un analyseur de spectre est un logiciel qui réaliser une transformation de Fourier discrète (TFD) afin d’afficher le spectre d’amplitude d’un signal physique.

 

Matériel nécessaire

  • Un Arduino UNO
  • Un capteur pour le signal analogique (microphone, photodiode, …)
  • Un afficheur LCD 16×2

 

Logiciels nécessaires

 

 

Travail demandé

Affichage des barres sur le LCD

Câblage du module d’affichage

Suivre les instructions de câblage sur la page dédiée à cet afficheur :

Écran LCD

Pour utiliser un afficheur LCD avec la bibliothèque LiquidCrystal, il faut commencer par importer la bibliothèque, puis créer un objet de type LiquidCrystal :

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

Puis, dans le fonction setup, initialiser l’objet lcd avec les dimensions de l’afficheur :

void setup() {
  lcd.begin(16, 2);
}

 

Création des caractères « barre »

Il n’existe pas de caractères permettant d’afficher des barres verticales, mais la bibliothèque LiquidCrystal permet de créer jusqu’à 8 caractères personnalisés.

Ça tombe bien puisque les caractères de ce type d’afficheur font 8 lignes de pixels, ce qui va nous permettre de définir les 8 caractères suivants, pour les niveaux 1 à 8 :

La barre de niveau « zéro » sera réalisée avec le caractère  »  » (espace).

 

Pour créer un caractère personnalisé, il faut utiliser la méthode createChar.

Par exemple pour créer un caractère « smiley » , on commence par créer un tableau (array) de 8 nombres (type byte) de 5 bits, correspondants aux 8 lignes de 5 pixels du caractère :

byte smiley[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b10001,
  0b01110,
  0b00000,
  0b00000
};

Écrire ces 8 nombres les uns sous les autres, et sous forme binaire (0b...), permet de directement visualiser l’emplacement des pixels à 1.

Ensuite, on utilise la méthode createChar (dans le setup par exemple afin d’utiliser les caractères personnalisés dans tous le reste du programme) :

lcd.createChar(0, smiley);

Le premier argument correspond au code du caractère personnalisé, un entier de 0 à 7.

Et pour l’afficher :

lcd.write(byte(0));

 

Créer puis afficher les caractères suivants :

 

Pour les barres, nous allons stocker les données des caractères dans un tableau barres. On définit alors un tableau de 8 caractères (tableaux de 8 lignes de 5 pixels) :

byte barres[8][8] = {
  {
    ...,
    ...,
    ...,
    ...,
    ...,
    ...,
    ...,
    ...
  },
   {
    ...,
    ...,
    ...,
    ...,
    ...,
    ...,
    ...,
    ...
  },
  ...
};

 

Afin de simplifier la création puis l’utilisation des 8 caractères, on décide d’utiliser une boucle for.

Créer le tableau de caractères barres[8][8] puis définir une fonction print_barre (voir signature ci-dessous) qui permet d’afficher une barre de niveau niv (0 à 16) à la colonne col (0 à 15) :
void print_barre(byte col, byte niv) {
  ...
  }

 

Réaliser un programme permettant d’afficher les 16 barres de niveaux 1 à 16 (utiliser une boucle for pour itérer sur les colonnes) :

 

Analyse du signal analogique

Installation d’un capteur analogique

N’importe quel capteur analogique convient.

Il faut cependant que le signal soit périodique (même si la période change régulièrement).

Exemple : signal sonore avec un microphone (comme ce modèle)

signal lumineux PWM (tel qu’émit par les lampes LED avec variateur) avec une photodiode ou simplement une LED.

 

Utilisation de la bibliothèque ArduinoFFT

Voici un programme simple illustrant l’utilisation de la bibliothèque ArduinoFFT :

#include "arduinoFFT.h" // import de la bibliothèque

// Nombre d'échantillons (puissance de 2)
const uint16_t samples = 32; // = nombre de fréquences analysées

// Fréquence d'échantillonage [Hz] (doit être <10000)
const double samplingFrequency = 2000; // = 2xfréquence maximale analysée
unsigned long microseconds;

// Période d'échantillonage (à calculer)
unsigned int sampling_period_us;

// Vecteurs d'entrée et de sortie pour stocker les données
double vReal[samples];
double vImag[samples];

// Creation de l'objet FFT
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, samples, samplingFrequency);

// Port numérique du signal à analyser
#define CHANNEL A0

/******************************************************************************************/
void setup() {
  Serial.begin(115200);
  while(!Serial);

  // Calcul de la période d'échantillonage
  sampling_period_us = round(1000000*(1.0/samplingFrequency));
  
  //...
}

/******************************************************************************************/
void loop() {
  // Échantillonage ********************************
  microseconds = micros();
  for(int i=0; i<samples; i++) {
      vReal[i] = analogRead(CHANNEL);
      vImag[i] = 0;
      while(micros() - microseconds < sampling_period_us) {
        // attente ...
      }
      microseconds += sampling_period_us;
  }

  // Analyse FFT ***********************************
  FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward);
  FFT.compute(FFTDirection::Forward);
  FFT.complexToMagnitude();
  
  // Affichage des résultats (magnitudes) **********
  Serial.println("Magnitudes :");
  for (uint16_t i = 0; i < samples/2; i++) {
    double freq = ((i * 1.0 * samplingFrequency) / samples);
    Serial.print(freq , 1);
    Serial.print("Hz");
    Serial.print("\t");
    Serial.println(vReal[i], 2);
  }
  
  Serial.println("Fréquence à magnitude maximale :");
  double x = FFT.majorPeak();
  Serial.println(x, 6);

  Serial.println();
  delay(200);
}
Tester le bon fonctionnement de ce programme, puis le modifier pour afficher les résultats sous forme de barres sur l’afficheur LCD. Pour calculer le niveau des barres (nombre de 0 à 16) on utilisera la fonction log, ainsi qu’un gain pour ajuster la hauteur.

 

Vous aimerez aussi...

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *