[Résolu] Décibels mètre pour salle de classe

Bonjour,

Bonne nouvelle année à tous ! :slight_smile:

J'ai quasiment terminé mon projet de décibels mètre visuel et sonore pour la salle de classe de ma femme.
En revanche, j'ai encore quelques soucis avec le micro, du coup c'est un peu (beaucoup) embétant pour un sonomètre...

J'ai réalisé un support en bois, ressemblant à un feu tricolore, composé de 3 matrices de 15 leds RGB WS2812B, pilotées par un arduino nano, un micro avec gain, un écran LCD i2C, un potentiomètre pour régler la luminosité et deux buzzers.

Le principe est assez simple, le micro doit mesurer le volume sonore et l'écran affiche en temps réel le niveau sonore en décibels.
Le feu tricolore affiche les couleurs suivantes :
-Vert (matrice du bas), si dB < 60
-Orange (matrice du milieu), si dB > 60 et dB < 75
-Rouge (matrice du haut), si dB > 75 et dB < 90
-Rouge (sur les 3 matrices) + buzzer, si dB > 90

Mon souci est que le micro capte bien des variations quand je souffle dessus, mais pas quand je mets de la musique dans la pièce ; le nombre de décibels reste au minimum.
Jouer sur la vis de réglage du gain du micro ne change rien.
Pourriez-vous me dire où j'ai pu me planter ?

Comme je débute en arduino, je me suis inspiré d'un script trouvé sur le net pour la formule de calcul des dB, que j'ai incorporé à mon script ci-dessous.

Voici le code que j'ai compilé :

#include <FastLED.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define COLOR_ORDER GRB
#define LED_TYPE WS2812B
#define MAX_BRIGHTNESS 250
#define MIN_BRIGHTNESS 20

LiquidCrystal_I2C lcd(0x27, 20, 4); // Set the LCD address to 0x27 for a 16 chars and 2 line display

char Buzzer = 2;
const int brightnessInPin = A7;    // The Analog input pin that the brightness control potentiometer is attached to.
const int sampleWindow = 50;       // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;

#define NUM_LEDS_PER_STRIP 15
CRGB redLeds[NUM_LEDS_PER_STRIP];
CRGB greenLeds[NUM_LEDS_PER_STRIP];
CRGB orangeLeds[NUM_LEDS_PER_STRIP];

void setup() {
 FastLED.addLeds<NEOPIXEL, 8>(greenLeds, NUM_LEDS_PER_STRIP);
 FastLED.addLeds<NEOPIXEL, 7>(orangeLeds, NUM_LEDS_PER_STRIP);
 FastLED.addLeds<NEOPIXEL, 6>(redLeds, NUM_LEDS_PER_STRIP);
 FastLED.setBrightness( MAX_BRIGHTNESS );

 Serial.begin(9600);
 lcd.init();
}

void loop() {
 // read the analog brightness value:
 //int brightValue = analogRead(brightnessInPin);
 // map it to the range of the FastLED brightness:
 int mappedValue = map(analogRead(brightnessInPin), 0, 1023, 0, 255);
 //int outputValue = constrain(mappedValue, MIN_BRIGHTNESS, MAX_BRIGHTNESS);

 // now we set the brightness of the strip
 FastLED.setBrightness(constrain(mappedValue, MIN_BRIGHTNESS, MAX_BRIGHTNESS));

 unsigned long startMillis = millis();                  // Start of sample window
 float peakToPeak = 0;                                  // peak-to-peak level
 unsigned int signalMax = 10;                         //minimum value
 unsigned int signalMin = 1024;                         //maximum value

 while (millis() - startMillis < sampleWindow)          // collect data for 50 mS
 {
   sample = analogRead(0);                             //get reading from microphone
   if (sample < 1024)                                  // toss out spurious readings
   {
     if (sample > signalMax)
     {
       signalMax = sample;                             // save just the max levels
     }
     else if (sample < signalMin)
     {
       signalMin = sample;                           // save just the min levels
     }
   }
 }
 peakToPeak = signalMax - signalMin;                    // max - min = peak-peak amplitude
 float dB = map(peakToPeak, 100, 900, 40, 100);        //calibrate for deciBels

 Serial.println (dB);

// Print a message to the LCD.
 lcd.backlight();
 lcd.setCursor(0, 0);
 lcd.print("Niveau sonore :");
 lcd.setCursor(2, 1);
 lcd.print(dB);
 lcd.setCursor(4, 1);
 lcd.print("  dB");

 if (dB < 60)
 {
   for (int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
     redLeds[i] = CRGB::Black;
     orangeLeds[i] = CRGB::Black;
     greenLeds[i] = CRGB::Green;
     FastLED.show();
     delay (30);
   }
 }

 else if (dB > 60 && dB < 75)
 {
   for (int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
     redLeds[i] = CRGB::Black;
     orangeLeds[i] = CRGB::Orange;
     greenLeds[i] = CRGB::Black;
     FastLED.show();
     delay (30);
   }
 }

 else if (dB > 75 && dB < 90)
 {
   for (int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
     redLeds[i] = CRGB::Red;
     orangeLeds[i] = CRGB::Black;
     greenLeds[i] = CRGB::Black;
     FastLED.show();
     delay (30);
   }
 }

 else if (dB > 90)
 {
   for (int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
     redLeds[i] = CRGB::Red;
     orangeLeds[i] = CRGB::Red;
     greenLeds[i] = CRGB::Red;
     FastLED.show();
     delay (30);
   }
   tone(Buzzer, 2960, 1000);
   delay (30);
}

}

Est ce que tu obtiens les valeurs de décibels sur ton écran LCD et sur la console ?

Je pense que ton problème vient de la présence de plusieurs bandeaux de leds. FastLED a une façon de gérer plusieurs bandeaux un peu complexe. Tu as deux solutions

  • Soit tu utilises cette façon complexe, il faut que tu t'inspires de ce lien
  • Soit tu bricoles. Tu peux chaîner tes bandeaux, les relier les uns aux autres en série. Tu obtiens en bandeau de 4*15 = 60 leds que tu allumes selon tes besoins.

Les valeurs s'affichent bien sur l'écran et sur le moniteur série.
Les leds s'allument bien aussi, comme je le souhaite ; je me suis d'ailleurs inspiré de ce code pour construire le mien.

Le problème vient du fait que le micro ne perçoit pas le son de la musique ou des cris de mes enfants (béta testeurs). Le micro n'enregistre que des changements de niveau de décibels quand je souffle dessus.

Bonjour
un lien vers le modèle de micro utilisé ?

quelles valeurs apparaissent dans le moniteur série quand le micro reçoit les sons qui posent problème et cellesen cas de souffle sur le micro ?

pour débugger : ajouter un
Serial.println(peakToPeak);
avant Serial.println(dB);
ça permettra de voir ce qui se passe avant la fonction map()

mattx38:
Les valeurs s'affichent bien sur l'écran et sur le moniteur série.

Le problème vient du fait que le micro ne perçoit pas le son de la musique ou des cris de mes enfants (béta testeurs). Le micro n'enregistre que des changements de niveau de décibels quand je souffle dessus.

Donc les valeurs affichées sont correctes (ou tout du moins cohérentes avec le bruit) quand vous faites du bruit près du micro?
C'est quel type de microphone?
Quelle référence?

Cordialement,
bidouilleelec

Salut

Il s'agit peut-être d'un micro destiné au chant ?
Je suppose qu'il s'agit d'un micro dynamique, donc peu sensible.
Il faudrait peut-être t'orienter sur un modèle à condensateur.

dans notre monde Arduino, on rencontre la pluspart du temps des modules dotés d'un electret suivi d'un AOP
.......attendons la réponse sur la référence de micro utilisé.
La fonction map() chargée de faire une sorte de 'conversion en db' (... sans logarithmes...) n'est probablement pas encore calibrée

Voici le modèle que j'ai retenu, car il me semblais le plus réactif :
[u]https://www.amazon.fr/gp/product/B07KTLHYSK/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1[/u]

J'ai aussi testé des MAX4466, mais avec moins de succès ; je ne comprends pas comment fonctionne la vis sans fin de réglage du gain, située dessous.

Les valeurs sont les mêmes sur l'écran LCD et dans la fenêtre du Moniteur série :

-Sans bruit j'obtiens 34 dB
-Si je souffle, j'arrive à monter jusqu'à 102 dB
-Quand je mets de la musique dans la pièce, ça reste à 34 dB

J'ai ajouté la ligne "Serial.println(peakToPeak);"

Sans bruit j'obtiens :
34.00
12.00
34.00
11.00
34.00
19.00
34.00
13.00
34.00
13.00
34.00
11.00
34.00
12.00
34.00
15.00

Ensuite j'ai soufflé un coup sur le micro :
34.00
12.00
34.00
861.00
97.00
9.00
34.00
14.00
34.00
14.00

Le modèle choisi n'est qu'un détecteur de son, il comporte un circuit intégré LM393 qui compare le niveau sonore avec un seuil réglable. Sa sortie est binaire, tout ou rien (son supérieur ou pas au niveau choisi grâce au potentiometre), aucune progressivité.... Donc impropre à un usage en 'mesure' ou il faut impérativement une proportionnalité entre son et tension.

le comportement observé rend bien compte de ce phénomène de seuil !! (34 ou 97 dB, rien entre...)

Il faut revenir vers un module microphone à MAX4466
Adafruit a bien documenté ce genre de modules , basé sur un bon circuit intégré avec un gain réglable
Noter qu'en absence de sons la sortie du module est à la moitié de la tension d'alimentation.
Il faut tenir compte de ce décalage dans le code ou insérer un condensateur pour bloquer la composante continue de la tension de sortie du MAX4466

ça doit fonctionner avec un module utilisant un CI MAX4466..... une fois trouvée la bonne combinaison réglage/code

'vis sans fin' : on trouve parfois, pour un réglage fin, des potentiomètres multi-tours avec un débrayage quand le curseur est en fin de piste résistive.

Je viens de désouder le micro installé et brancher un Max4466 avec des fils Dupont.
J'obtiens un peu plus de réactions, mais c'est assez "on/off" comme comportement...

le code est sans doute à retoucher
pour le mettre au point surveiler les données avant et après l'application de la fonction map() et ceci pour des conditions sonores 'normales'

float dB = map(peakToPeak, 100, 900, 40, 100);

Içi map() travaille sur un 'peakToPeak' entre 100 et 900 et produit des données 'dB' entre 40 et 100
Il faut d'abord observer peakToPeak selon les divers niveaux sonores représentatifs
Jouer avec le gain de la carte micro pour que peakTo Peak évolue dans la bonne plage

Ta façon de calculer des dB est pour le moins fantaisiste.
voir Décibel — Wikipédia

J'ai déjà fait des essais avec un MAX4466, et cela marche plutôt pas mal.
Comment est alimentée le MAX4466 ? 5V ou 3.3V ?
Le 3.3V serait préférable, car moins bruité.

biggil:
Ta façon de calculer des dB est pour le moins fantaisiste.
voir Décibel — Wikipédia

J'ai repris la formule et le code d'ici : https://www.youtube.com/watch?v=149TXc_bPeA

Le micro est bien alimenté en 3.3V.
En revanche, je pense que la solution est à trouver dans le calibrage de la formule map().
En fait, je viens seulement de comprendre comment elle fonctionne...

Peu importe qu'on appelle ça des décibels ou d'un autre nom, l'important est de choisir des seuils pour l'allumage des différents bandeaux

Oui !

....dans un premier temps obtenir une bonne plage de variation des données brutes 'peakToPeak' avant traitement

....ensuite 'calibrer' la fonction map() en fonction de "l'effet visuel recherché"

Le code récupéré linéarise la conversion en 'dB' , c'est une simplification grossière mais mattx38 ne prétend pas faire un véritable sonomètre. Son appareil donnera des "décibels entre guillemets".....

C'est certain, en revanche, j'avais besoin d'un référentiel pour décider quand le niveau passe au orange, puis au rouge.

Merci pour votre aide précieuse.
J'ai passé pas mal de temps pour faire un outil vraiment utile pour la classe de ma femme, ça aurait été dommage d'échouer si près du but.

J'ai un dernier souci avec l'affichage des chiffres lorsque les dB passent à 3 digits et qu'ils repassent à 2 ; le dernier digit reste affiché.
Il y a un post qui parlait de cela, mais le lien du dernier message ne fonctionne plus et je ne peux pas répondre au post (trop ancien peut-être) :
http://forum.arduino.cc/index.php?topic=33535.0

Pour l'instant, j'ai ajouté un "lcd.clear();" après un "if dB > 99"
Auriez-vous une astuce pour ce souci ?

Il suffit d'afficher un espace à l'endroit du chiffre à effacer