2021
HOME

Ergänzungen zum Buch MSR mit MicroPython und RP2040
RP-Pico-Schallmessungen
Raspberry Pi Pico als Werkzeug in Grundlagenversuchen der Naturwissenschaften

Pi Pico and LW RadioMit dem Pi Pico lassen sich Untersuchungen mit Schall und dessen Welleneigenschaft auf einfache und preiswerte Weise durchführen.

Die Rolle des RP2040 beschränkt sich hier auf das Messen und Darstellen der Messgrößen Schallpegel in Form von Spannungswerten an den analogen Eingängen. Ein Micro-Pico-Oszilloskop auf einem Mini-OLED-Display gestattet visuelle Analysen, MicroPython steuert das Oszilloskop, was dadurch frei programmierbar ist. 

Dieser Abschnitt benutzt ein Grundgerüst in MicroPython, welches für die jeweilige Verwendung nur in geringem Maße angepasst wird. Weitere Komponenten sind:

  • Smartphone mit App zur Tonerzeugung 4000 und 2000 Hertz
  • Zwei Mikrofone aus Abschnitt 3 als Breakout
  • Ein Zollstock oder Lineal. Auch ein Maßband/Zollstock ist möglich

Folgende Anwendungen und Versuche werden hiermit durchgeführt:

In den Klammern ist die Zahl der benötigten Mikrofone angegeben.

Der Aufbau der Schaltung ist nicht so kompliziert, wie obige Abbildung vermuten lassen könnte. Dies ist ein Testaufbau in der Entwicklungsphase mit Breadboards, die auch nicht verwendete Bauteile, wie verschiedene IC, nur lagern. Die Verbindungen der Komponenten beschränken sich auf nur sechs Verbindungen zum Pi Pico.

Pin
Pi Pico Board OLED Mikrofon 1 Mikrofon 2
8
GND GND GND GND
36
VCC VCC VCC VCC
11
SDA(0) SDA
12
SCL(0) SCL
31
ADC(0) OUT
32
ADC(1) OUT

Eines der beiden Mikrofone sollte längere Verbindungen aufweisen, damit eine gewisse Ortsunabhängigkeit gegeben ist. Die angegebenen Zahlen des Pico-Boards beziehen sich auf die durchnummerierten Pins der Platine von 1 bis 40.


Darstellung eines Tonsignals

Eine kleine OLED-Anzeige aus Abschnitt 3 dient als Bildschirm eines einfachen Oszilloskops. Der Schirm ist in horizontaler Richtung zehnmal geteilt, in vertikaler Richtung nur siebenfach. Das Bildschirmgitter wird nur einmal gezeichnet und dann vor der Darstellung mit der Framebuffer-Funktion blit vor jeder neuen Darstellung aus dem Speicher in den Framebuffer kopiert. 

from machine import ADC,Pin,I2C
from ssd1306 import SSD1306_I2C
from utime import *

WIDTH = 128 # oled display width
HEIGHT = 64 # oled display height

import framebuf
oram = framebuf.FrameBuffer(bytearray(WIDTH * HEIGHT * 1), _
 WIDTH, HEIGHT, framebuf.MONO_VLSB)
oled = SSD1306_I2C(WIDTH,HEIGHT,I2C(0))
#defaults,SCL=Pin(GP9), SDA=Pin(GP8), freq=400000

def drawH(x0,y0,x1,y1,color):#DOTTED
    for x in range(x0,x1,2):oram.pixel(x,y0,color)

def drawV(x0,y0,x1,y1,color):
    for y in range(y0,y1,2):oram.pixel(x0,y,color)
    
def drawgrid():
    for i in range(11): drawV(OFF+i*11,0,OFF+i*11,64,1)
    for i in range(9):  drawH(OFF,i*9,120,i*9,1)

OFF = 8
N = 56*2
a1=N*[0]
drawgrid()

# off=offset()

def read():
    for i in range (N): # ca. 25 ms/DIV
        a1[i]=ADC(0).read_u16()
   
def draw(color=1):
    dx=int(WIDTH/N)
    k=(HEIGHT-1)/65535
    oled.blit(oram,0,0)#drawgrid()
    for i in range(0,N-1):
        if (i>0):
            j =i - 1
            oled.line(OFF+i*dx,int(k*a1[i]),OFF+j*dx,int(k*a1[j-1]),color)

oled.text('OSZ 2MC SCHALL',12,8*6-1)
oled.show()
sleep(2)

while(True):
    read()
    draw()
    oled.show()

Dies ist quasi das Minimum, um einen Ton auf dem OLED am Pi Pico darzustellen. Bei entsprechender Tonerzeugung sollte ein Wechselsignal erkennbar sein. Pfeift man mit dem Mund einen sauberen Ton, so müsste ein Sinusverlauf sichtbar werden. Da das Oszilloskop aber noch frei läuft, stellt sich ein stehendes Bild nur bei bestimmten Frequenzen ein. Da das Mikrofon laut Angabe einen Offset von 1,25 Volt aufweist, wird in einer Zusatzfunktion dieser Offset vor der eigentlichen Messung einmal bestimmt, um dann die eigentlichen Messungen erst bei Überschreitung dieses Pegels zu starten, was dem Triggern eines Oszilloskops entspricht. Die Funktion aus Abschnitt 3 liefert hier den Ruhepegel in Digitaleinheiten. Dieser Wert sollte etwa 33480 betragen, je nach Exemplar. Mit diesem Offset wartet die erweiterte Routine read, bis eine gewünschte Schwelle überschritten ist.

def offset():
    sampleT=20 # ms
    start = ticks_ms()
    mx = 0
    mn = 65535
    while ticks_ms() - start < sampleT:
        m = machine.ADC(0).read_u16()
        if m > mx: mx = m
        if m < mn: mn = m           
    p2p= mx - mn
    return mn+(mx-mn)

def read():
    while(ADC(0).read_u16()<off):pass #trigger
    while(ADC(0).read_u16()>=off):pass #trigger
    for i in range (N): # ca. 25 ms/DIV
        a1[i]=ADC(0).read_u16()

Nachdem im ursprünglichen Listing off=offset() entkommentiert, bzw. neu hinzugefügt ist, stellt sich nun auch bei verschiedenen Tönen ein stehendes Bild ein, da erst ab einem vorgegebenen Pegel gemessen und danach dargestellt wird.


Frequenzmessung - einfach

Ohne gleich die Fourier-Transformation in MicroPython zu bemühen, soll hier eine sehr einfache Frequenzmessung für sinusförmige Töne zur Anwendung kommen. Das Prinzip beruht darauf, die Zeit einer vollen Schwingung zu erfassen, was der Periodendauer T entspricht. Der Kehrwert entspricht dann der Anzahl der Schwingungen pro Sekunde, also der Frequenz f in Hertz. Die Routine freq wartet dabei ähnlich wie beim Triggern einfach beide Nulldurchgänge ab und berechnet aus den ermittelten Zeiten die Frequenz.

def freq():
    while(ADC(0).read_u16()>=off):pass #trigger
    while(ADC(0).read_u16()<off):pass #trigger
    t0=ticks_us()
    while(ADC(0).read_u16()>=off):pass #trigger
    while(ADC(0).read_u16()<off):pass #trigger
    t1=ticks_us()
    T=1*(t1-t0)*1e-6
    return int(1/T)
while(True):
    read()
    draw()
    oled.fill_rect(12,8*6-2,8*6,8,0)
    oled.text(('{:5d}'.format(freq())),12,8*6-1)
    oled.show()

Die Hauptschleife erweitert sich durch die Frequenzanzeige. Der Texthintergrund besteht aus einem schwarzen Rechteck in der Größe der formatierten Textausgabe.


Kalibrierte Zeitablenkung
Um in MicroPython die schnellstmögliche Messfolge für eine Messreihe oder Bildschirmbreite zu erhalten, erfolgt die Messung ohne Verzögerung. Damit stellt sich die Frage nach der Größe der Zeiteinheit pro Bildschirmteilung, also das was beim Oszilloskop der Zeitablenkung t/DIV entspricht. Der Tongenerator erzeugt dazu verschiedene Frequenzen so, dass die Schwingungsperioden auf ganzzahligen Teilungen liegen.
- 4 DIV
1000 Hz
- 5 DIV
750 Hz
- 1 DIV
4000 Hz
Eine Tabelle mit Beispielmessungen ist rechts angegeben. Berechnet man die entsprechen Zeiten in Millisekunden, so ergibt sich im Mittel etwa 25 ms/DIV. Somit ist die Zeitbasis bei diesem Mini-Oszilloskop fest auf diesen Wert eingestellt.


Abstandsmessung
Mit zwei Mikrofonen kann die Laufzeit des Schalls mittels Klopfsignal ermittelt werden, also ganz ohne elektronischen Tongenerator. Registriert das Mikrofon 1 an ADC(0) einen bestimmten Pegel, so beginnt die Messung. Das Mikrofon 2 an ADC(1) empfängt den Schallimpuls etwas später, da es etwas nach hinten versetzt gegenüber dem ersten Mikrofon positioniert ist.

Abbildung: Draufsicht der Messanordnung. Schematischer Aufbau nach obigen Foto

Der Abstand entspricht einer Zeit, die auf dem Schirm ablesbar ist. Bei kalibrierter Zeitablenkung von 0,25 ms/DIV kommt ein Klopfsignalpegel bei einem um 20 cm versetzten Mikrofon bei einer gegebenen Schallgeschwindigkeit von 340 m/s in Luft mit einer Verzögerung von 0,59 ms an, da für Schall die Gesetzmäßigkeiten der Bewegung mit konstanter Geschwindigkeit gelten

Das Programm für diese Untersuchung unterscheidet sich nur in der Funktion read. Die Messauslösung oder Triggern erfolgt über Kanal 0, dem Referenzmikrofon, welches zuerst das Klopfen wahrnimmt. Da die beiden Mikrofone mit AGC – automatischer Verstärkung – arbeiten, ist es möglich über die verstrichene Zeit des Triggers mehrere kurze Klopfzeichen zu erfassen, um ein möglichst eindeutiges Signal für Mikrofon 2 zu reproduzieren. Ist ein brauchbares Signal auf dem Schirm dargestellt und das Klopfsignal unterbleibt, wartet die Routine 5 Sekunden zwecks visueller Auswertung der Kurvenform. In der Ausgabe erscheinen Hinweise zur Durchführung. Die Deutung der erhaltenen Kurvenform erfordert etwas Übung, wie das auch bei Schirmbildern von Ultraschallechos erforderlich ist.

def read():
    t0=ticks_ms()
    while(ADC(0).read_u16()<off):pass 	#Trigger MIC 1
    while(ADC(0).read_u16()>=off):pass 
    t1=ticks_ms()
    if t1-t0 >1000: sleep(5)
    for i in range (N): 			# ca. 25 ms/DIV
        a1[i]=ADC(1).read_u16()		# Signal MIC 2

print("Zwei Mikrofone in 20 cm-Abstand.")
print("Mic 1 an ADC0 als Trigger s = 20 cm")
print("Mic 2 an ADC1 als Quelle  s =  0 cm")
print("Time/DIV ist etwa 0,25 ms")
print("Stift klopft auf Tisch mehrmals schnell")
print("bis erster Peak bei 2 DIV reproduzierbar.")
print("0.2/340=0.59, also etwa 2 DIV")

while(True):
    read()
    draw()
    oled.show()


Schallgeschwindigkeit in Luft

Auch zur Bestimmung der Schallgeschwindigkeit in Luft mit dieser Anordnung sind zwei Mikrofone erforderlich. Dabei strahlt ein Lautsprecher einen kontinuierlichen Sinus-Ton ab. Als Generator dient hier eine Smartphone-App, die verschiedenen Frequenzen erzeugen kann und diese über den Lautsprecher ausgibt. Hier der Software-Funktionsgenerator von Keuwlsoft aus dem Play Store.

Da der Generator im Smartphone es nicht zulässt ein Signal elektrisch abzugreifen, um es als Trigger-Kriterium heranzuziehen, übernimmt das eines der beiden Mikrofone an einem festen Ort und liefert quasi die Referenz des erzeugten Tons. Referenz ist hier gleich Auslöser oder Trigger, so dass die Messung immer dann beginnt, wenn dieses Mikrofon einen bestimmten Pegel registriert.

Mikrofon 1 ist der Messaufnehmer bei der Anordnung nach obiger Abbildung, dessen Sinus-Signal nun durch Verschiebung dieses Mikrofons auf dem Schirm in horizontaler Richtung bewegt werden kann. Man 'fährt' quasi die „Welle“ ab, die physikalisch eine Druckänderung in Ausbreitungsrichtung ist, die im Mikrofon in eine Spannungsänderung gewandelt wird und auf dem Schirm zur Anzeige kommt.

Da Schall sich im selben Medium mit konstanter Geschwindigkeit ausbreitet, ist der Weg proportional zur Zeit t. Die horizontale Achse des Bildschirms kann also auch als Weg-Achse fungieren. Verschiebt man nun den Messaufnehmer Mikrofon 1, so kann am Schirm eine Weg-Verschiebung beobachtet werden. Eine Verschiebung um eine Schwingung auf dem Schirm entspricht der Wellenlänge Lambda des Tons. Mit diesem Messwert und der eingestellten Frequenz f kann das Ergebnis der Schallgeschwindigkeit c mit Hilfe der Grundgleichung

ermittelt werden. Bei einer Frequenz von 4000 Hz und einer gemessenen Weglänge als Wellenlänge Lambda von 8,5 cm, erhält man durch Einsetzten die Schallgeschwindigkeit in Luft, je nach Raumtemperatur.

mit als Ergebnis 340 m/s.

Ändert man die Frequenz auf geringfügig angenehmere 2000 Hertz, so verdoppelt sich im gleichen Medium die Wellenlänge, so dass bei gleicher Mikrofonverschiebung die Sinusdarstellung auf dem Schirm nur um die Hälfte wandert.

So lässt sich beweisen, dass die Schallgeschwindigkeit im Medium nicht von der Frequenz abhängig ist, womit auch sicher gestellt ist, dass alle Klänge eines Orchesters gleichzeitig beim Hörer eintreffen und es keine spektrale Verzögerung gibt. Das Programm ändert sich im Aufbau nicht im Vergleich zum vorigen Listing. Die read-Routine ist identisch, lediglich die Hinweise können eine Anpassung erfahren. Die Durchführung unterscheidet sich durch die Verwendung des Dauertons eines Signalgenerators.

oled.text('OSZ 2MC LAMBDA',12,8*6-1)
oled.text('f=4000Hz 8,5cm',12,8*7-1)
oled.show()
sleep(2)
print("Handy mit 4000Hz-App")
print("Zwei Mikrofone in 10 cm Abstand, hintereinander")
print("Max oder Min auf Skalenstrich wg. Ablesbarkeit")
print("Mic 1 an ADC0 als ext. Trigger")
print("Mic 2 an ADC1 als Quelle s =  0 cm")
print("Time/DIV ist 0,25ms +/-1ms")
print("MIC 1 auf 14,25 cm, 19 cm ist L/2, L")
print("L=c/f, L=340/4000=8,5cm")
print("Mittlerer Schallpegel bei etwa 34000")
print('Mittlerer Schallpegel:',off)

while(True):
    read()
    draw()
    oled.show()


Akustische Interferenz
Mit dieser Anordnung kann eine akustische Interferenz sowohl über das Ohr als auch elektrisch über die beiden Mikrofone erfahren werden. Interferenz entsteht bei der Überlagerung von Wellenzügen gleicher Frequenz und Polarisation. Beide Bedingungen erfüllt die Schallwelle als Längswelle im nahen Raum. Bei der Überlagerung addieren sich die beiden Amplituden bzw. Auslenkungen, so dass Verstärkung oder Abschwächung an einem Ort auftreten kann. Die Begriffe sind konstruktive- und destruktive Interferenz.

Verstärkung tritt ein, wenn zwei Wellen der Form aus Abbildung A zusammen treffen und deren Drücke sich addieren. An einem anderen Ort, der eine halbe Wellenlänge weiter entfernt liegt, tritt das Signal aus Abbildung B auf. Addiert man nun beide Druckamplituden, so heben sich die Unterschiede auf und das Resultat ist Stille. Eingebaut in Kopfhörer nennt sich das Prinzip Noise-Canceling.

Die beiden Abbildungen repräsentieren quasi die beiden Mikrofonsignale bei einem Dauerton einer bestimmten Frequenz an verschiedenen Orten. Der Beginn der Messung wird ausgelöst durch das Signal in Abbildung A an ADC(0).

Das Programm benötigt eine angepasste read-Routine, die diese beiden Mikrofonspannungen addiert, um sie dann wie gewohnt zur Anzeige zu bringen. Alle anderen Algorithmen bleiben gleich.

def read():
    while(ADC(0).read_u16()<off):pass #trigger
    while(ADC(0).read_u16()>=off):pass #trigger
    for i in range (N): # ca. 25 ms/DIV
        a1[i]=(ADC(0).read_u16()+ADC(1).read_u16())>>1
        
oled.text('OSZ 2MC LAMBDA',12,8*6-1)
oled.text('f=4000Hz 8,5cm',12,8*7-1)
oled.show()
sleep(2)
print("Lambda durch akustische Interferenz.")
print("Addition von MC1- und MC2-Pegel")
print("Schallquelle: Handy mit 4000/2000Hz-App")
print("Zwei Mikrofone in 10cm Abstand, hintereinander")
print("Max oder Min auf Skalenstrich wg. Ablesbarkeit")
print("Mic 1 an ADC0 als Trigger s=10cm")
print("Mic 2 an ADC1 als Quelle  s= 0cm")
print("Time/DIV ist 0,25ms +/-1ms")
print("MIC 1 auf Minimum, dann auf Maximum")
print("Wegdiff. ist L/2:  ist L=c/f, L=340/4000=8,5cm")
print("Mittlerer Schallpegel bei etwa 33224")
print('Mittlerer Schallpegel:',off)

while(True):
    read()
    draw()
    oled.show()

Ist im Aufbau nach der Abbildung ganz oben das Smartphone mit Schallquelle hinter der Kamera, so ist dieser Effekt auch akustisch wahrnehmbar, wenn der Kopf etwas bewegt wird. Ein kurzes Kochrezept zur Durchführung:

  •          Anordnung aufbauen in Anlehnung an Abbildung 1
  •          Abstand der Mikrofone zu Beginn etwa 10 cm
  •          Programm starten
  •          Abstand ändern bis maximale Auslenkung sichtbar
  •          Standort markieren und ein Mikrofon nicht mehr bewegen
  •          Zweitmikrofon verschieben bis minimale Auslenkung sichtbar
  •          Standort markieren
  •          Weg-Differenz der Markierungen ausmessen

Der Abstand der beiden Markierungen entspricht der halben Wellenlänge. Zur Kontrolle kann bis zum nächsten Maximum verschoben werden, um die ganze Wellenlänge zu erhalten. Eine weitere Probe ist mit der doppelten oder halben Frequenz möglich, falls der Lautsprecher des Smartphone in der Lage ist solche Frequenzen mit entsprechendem Pegel zu produzieren.



.
Startseite Bücher Software Digital RTV Musik Kontakt

Für Inhalt und weitere Verzweigung externer Links sind die Betreiber der dortigen Seiten verantwortlich - H.-J. Berndt