Donnerstag, 15. September 2022
Donnerstag, 15. September 2022
Akustische Signale mit MAX9814 aufzeichnen
Das Mikrofonmodul MAX9814 von Adafruit verfügt über einen integrierten Verstärker. Ohne diesen wäre die Spannung am Mikrofon so gering, dass am Analog-Eingang vom Arduino nichts gemessen werden könnte.
Bei völliger Ruhe wird am Ausgangs-PIN 1,25V ausgegeben. Signale werden mit max. 2Vpp und min. UNBEKANNT ausgeben. Werden diese Pegel überschritten, so wird das Signal abgeschnitten. Das Mikrofon kann diese jedoch trotzdem erfassen. Um die Skala zu ändern stehen 2 weitere Verstärkungsstufen bereit, es sollte dann die Verstärkung reduziert werden. Standardmäßig beträgt die Verstärkung 60 dB, es sind aber auch 50 dB und 40 dB möglich.
Folgende Beschaltung ergibt die Verstärkungsleistung:
•60 db: keine weitere Verschalung (standardmäßig)
•50 dB: PIN GND mit PIN Gain verbinden
•40 dB: PIN Vdd mit PIN Gain verbinden
Zur Möglichkeit der Aufnahme einer Schwingung einer bekannten Sinus-Schwingung wurde mit einem Klangerzeuger die 50 Hz Sinus-Frequenz auf dem iPhone erzeugt und neben das Mikrofon gehalten. Um möglichst hochfrequent aufzuzeichnen, wurde im LOOP zuerst eine Aufnahmeschleife mit Aufzeichnung von 65 Werten in einem Array erzeugt. So wenig Befehle wie möglich bei der Erfassung sorgen für eine schnelle Befehlsabarbeitung und damit einer hohen Datenerfassungsrate (ca. 307 µs bzw. 3,25 kHz).
Um zeitkritische Signale aufzunehmen, deren Aufnahmepunkte in definierten Zeitintervallen erfolgen sollen, wäre die Verwendung eines Timer-Interrupt im Arduino besser und würde für eine genauere Abtastung sorgen.
Anschließend ist die zeitkritische Phase vorbei und der Inhalt des Array kann nacheinander ausgegeben werden. Dazu wird ein Zähler verwendet. Ist das Zählerende erreicht wird das Signal mittels eines Unterprogramms an die serielle Schnittstelle ausgegeben und kann so angezeigt werden (siehe Abb. unten).
Um ein Sample vom vorherigen unterscheiden zu können, werden danach noch einige 0-Pegel (Nulllinie) ausgegeben. Wir geben als Nulllinie die 1250 mV an.
void loop() {
for (int i=1; i<65; i++)
{
// read the analog in value:
sensorValue = analogRead(analogInPin);
data[i]=sensorValue;
}
for (int i=1; i<65; i++)
{
Serial.println(map(data[i],0,1023,0,5000));
}
for (int i=0; i<100; i++)
{
Serial.println(1250);
}
delay(5000);
}
Auswertung und Analyse der aufgezeichneten Daten
Im weiteren möchten wir dieses in dieser kurzen Zeitspanne ... genannt „Sample“ .... aufgezeichnete Signal mittels FFT-Analyse auf die enthaltene Frequenz untersuchen und das Ergebnis abspeichern. Am Ende möchten wir die Frequenz und die Pegelhöhe als laufende Werte im Arduino LOGGER sehen.
#include "arduinoFFT.h"
arduinoFFT FFT = arduinoFFT(); /* Create FFT object */
/*
These values can be changed in order to evaluate the functions
*/
const uint16_t samples = 128; //This value MUST ALWAYS be a power of 2
//const double signalFrequency = 65;
//const double samplingFrequency = 5000;
//const uint8_t amplitude = 10;
/*
These are the input and output vectors
Input vectors receive computed results from FFT
*/
const int analogInPin = A0; // Analog input pin that the potentiometer is attached to
double samplingFrequency = 5000;
double vReal[samples];
double vImag[samples];
double data[samples];
int deltaT;
unsigned int sampling_period_us;
unsigned long microseconds;
#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02
#define SCL_PLOT 0x03
int sensorValue = 0; // value read from the pot
int StartZeit, EndeZeit;
//int outputValue = 0; // value output to the PWM (analog out)
//unsigned int data[512];
int schalter = 1;
int frequenz;
int psd;
void setup() {
sampling_period_us = round(1000000*(1.0/samplingFrequency));
Serial.begin(2000000);
}
void loop() {
// für 50 Hz wird genau ein Sinus aufgezeichnet
microseconds = micros();
for (int i=0; i<(samples); i++)
{
StartZeit=micros();
// read the analog in value:
sensorValue = analogRead(analogInPin);
data[i]=sensorValue;
vReal[i]=sensorValue;
vImag[i] = 0.0;
while((micros() - microseconds) < (sampling_period_us)){
//empty loop
}
EndeZeit=micros();
deltaT=EndeZeit-StartZeit;
microseconds += sampling_period_us;
}
samplingFrequency = 1000000/deltaT;
FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);/* Weigh data */
FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */
FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */
double x;
double v;
FFT.MajorPeak(vReal, samples, samplingFrequency, &x, &v);
frequenz=(x);
psd=(v);
Serial.print(x, 6);
Serial.print(", ");
Serial.println(v, 6);
for (int i=0; i<(samples-1); i++)
{
Serial.print(data[i]);
Serial.print(", ");
Serial.print(frequenz);
Serial.print(", ");
Serial.println(psd);
}
delay(500);
}
void PrintVector(double *vData, uint16_t bufferSize, uint8_t scaleType)
{
for (uint16_t i = 0; i < bufferSize; i++)
{
double abscissa;
/* Print abscissa value */
switch (scaleType)
{
case SCL_INDEX:
abscissa = (i * 1.0);
break;
case SCL_TIME:
abscissa = ((i * 1.0) / samplingFrequency);
break;
case SCL_FREQUENCY:
abscissa = ((i * 1.0 * samplingFrequency) / samples);
break;
}
Serial.print(abscissa, 6);
if(scaleType==SCL_FREQUENCY)
Serial.print("Hz");
Serial.print(" ");
Serial.println(vData[i], 4);
}
Serial.println();
}
In der neuen Arduino IDE 2.0 ist der serielle Monitor direkt unter dem Programmcode-Fenster angebracht. Mit dem obigen Programm wird zuerst innerhalb kurzer Zeit mit hoher Samplingrate Ton mit dem Mikrofon aufgenommen. Die Länge ist durch den RAM-Speicher des Mikro-Controller begrenzt.
Nach der Aufnahme wird die Aufnahme ausgegeben und kann dann sowohl im seriellen Monitor als auch im seriellen Logger angezeigt werden.
Die 3 Datenreihen die seriell übertragen werden sind:
• Messwert (blaue Linie)
• Frequenz: Ergebnis der FFT-Auswertung (orange Linie)
• PSD-Wert der FFT-Auswertung (grüne Linie)
Wenn man diese komma-separiert auf den seriellen Port ausgibt werden diese 3 Datenstränge getrennt im seriellen Logger angezeigt und können einzeln zu- und abgeschaltet werden.
Mit der App Funktionsgenerator Pro am dem iPhone können beliebige Töne erzeugt werden ... auch reine Sinus-Töne. Wird ein Ton mit der Rechteck-Funktion erzeugt, so funktioniert die Frequenzanalyse nicht sehr gut, da hierbei sehr viele Oberfrequenzen mit erzeugt werden um einen Rechteckverlauf zu generieren. Bleibt man aber beim Sinus, funktioniert die Frequenzanalyse oberhalb von 130 Hz sehr zuverlässig.
Der PSD-Wert zeigt die Leistung der gefundenen Frequenz an. Die Leistung steigt sehr stark an, wenn ein Sinuston gefunden wird und steht somit für die Sicherheit, dass die gefundene Frequenz enthalten ist. Am besten wird ein Schwellwert eingerichtet, unterhalb dem die angezeigte Frequenz als unsicher gilt. Wenn kein Sinus erzeugt wird zeigt die FFT-Analyse dennoch eine Resonanzfrequenz an, die jedoch sehr stark springt und deren PSD-Wert unter 100 liegt. Damit kann unterschieden werden, ob die gefundene Frequenz auch tatsächlich vorhanden ist.
Ein Audio-Signal ist als Schall in Gasen (Luft) zu sehen und besteht aus Longitudinalwellen. Diese Druckdifferenzen werden vom Mikrofon erfasst und über eine Spule eine Spannung erzeugt. Dieser Druck ist bei völliger Stille der aktuelle Luftdruck ... die Wellen erzeugen Druckspitzen oberhalb und unterhalb des Luftdrucks. Im Mikrofon wird eine Spannung induziert ... diese ist Null wenn kein Geräusch vorliegt und größer Null oder kleiner Null bei Schall.
Da der Arduino keine negativen Spannungen erfassen kann, wurde die Messauswerteelektronik von Adafruit so umgesetzt, dass ein fester Offset von 1,25 Volt der völligen Geräuschlosigkeit entspricht. Es wird das Spannungsniveau um diesem Offset in den positiven Spannungsbereich geschoben.
Um das Schallsignal wieder in den urspünglichen Bereich zurückzuschieben müßte die Offset-Spannung dann wieder von jedem Messpunkt abgezogen werden. Ohne zu tief in die Messtechnik abzudriften ist hier auch eine Kalibrierung nötig, wären wir an dem genauen Pegel des Schalls interessiert. Glücklicherweise möchten wir nur die Frequenzanalyse machen, hierbei ist ein Offset unerheblich, denn es wird ja vergleichend und nicht absolut gemessen. Die Frequenz ist diesselbe egal wie hoch und wie fein die Pegelwerte ermittelt werden oder ob ein fester Offset vorliegt. Deswegen funktioniert die Frequenzerkennung auch mit einer sehr schlechten Ausgangsbasis. Lediglich der Messverstärker, der hier in 3 Verstärkungsstufen 60 dB, 50dB und 40dB vorliegt, ist essentiell um überhaupt einen Spannungsbereich passend zum Arduino Spannungsbereich zu erzeugen.