Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
ws1415:ton_zu_bild [2015/02/28 14:33] lennyleass |
ws1415:ton_zu_bild [2016/05/10 14:46] (aktuell) |
||
---|---|---|---|
Zeile 22: | Zeile 22: | ||
===Theoretischer Hintergrund=== | ===Theoretischer Hintergrund=== | ||
- | Zuerst mussten wir uns damit auseinandersetzen, wie Schall mathematisch beschrieben werden kann. Wir haben uns die Begriffe Periode, Frequenz, Amplitude etc. noch einmal vergegenwärtigt. Grundlage für die Verarbeitung und Analyse von Tonsignalen ist die Fourier-Analyse. Sie bietet eine Möglichkeit, Schallsignale in ihre Teilfrequenzen zu zerlegen. Somit kann man z.B. Grundtöne bestimmen, Obertonspektren vergleichen, und vieles mehr - so weit sind wir aber noch nicht gekommen. | + | Zuerst mussten wir uns damit auseinandersetzen, wie Schall mathematisch beschrieben werden kann. Wir haben uns die Begriffe Periode, Frequenz, Amplitude etc. noch einmal vergegenwärtigt. |
- | [[Protokolle]] | + | ==Fourier-Analyse== |
+ | Grundlage für die Verarbeitung und Analyse von Tonsignalen ist die Fourier-Analyse. | ||
+ | Sie bietet eine Möglichkeit, Schallsignale in ihre Teilfrequenzen zu zerlegen. Somit kann man z.B. Grundtöne bestimmen, Obertonspektren vergleichen, und vieles mehr. | ||
+ | |||
+ | |||
+ | ===Unser Programm=== | ||
+ | |||
+ | Um Töne aufnehmen deren Daten verarbeiten zu können, verwenden wir das Modul pyaudio. | ||
+ | Für die Verarbeitung der Daten verwenden wir das Modul numpy. | ||
+ | Für die Generierung und Darstellung der Bilder verwenden wir das Modul matplotlib. | ||
+ | |||
+ | Ein Funktion zum Aufnehmen von Tönen kann z.B. so aussehen: | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | from __future__ import division | ||
+ | import pyaudio | ||
+ | import numpy as np | ||
+ | |||
+ | |||
+ | def recordsnd(filename, time): | ||
+ | ''' | ||
+ | Nimmt eine time Sekunden lange Schallsequenz | ||
+ | auf (mit der Samplerate 44100 Hz) auf, | ||
+ | speichert sie in der Datei filename und gibt die | ||
+ | Aufnahme als numpy-array mit Werten zwischen -1 und 1 zurück | ||
+ | ''' | ||
+ | CHANNELS = 1 | ||
+ | RATE = 44100 | ||
+ | DAUER=time | ||
+ | ANZAHL=int(RATE*DAUER) | ||
+ | |||
+ | |||
+ | p = pyaudio.PyAudio() | ||
+ | raw_input("Aufnehmen "+str(time)+ " Sekunden): Eingabetaste drücken...") | ||
+ | |||
+ | stream = p.open(format =pyaudio.paInt16 , | ||
+ | channels = CHANNELS, | ||
+ | rate = RATE, | ||
+ | input = True, | ||
+ | frames_per_buffer = 1024)#ANZAHL) | ||
+ | |||
+ | |||
+ | yy=stream.read(ANZAHL) | ||
+ | y=np.fromstring(yy,dtype=np.short) | ||
+ | if CHANNELS==2: | ||
+ | y=y.reshape((y.shape[0]//2,2)) | ||
+ | |||
+ | print("Aufgenomen: " + str(ANZAHL) + " Frames") | ||
+ | stream.close() | ||
+ | p.terminate() | ||
+ | yy=np.array(y,dtype='d')/32768.0 | ||
+ | if filename!=None: | ||
+ | wavwrite(filename, yy) | ||
+ | |||
+ | return yy | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Den numpy-array, den wir hierdurch erhalten, können wir uns mit matplotlib anzeigen lassen, z.B. so: | ||
+ | |||
+ | <code python> | ||
+ | import matplotlib.pyplot as plt | ||
+ | |||
+ | y = recordsnd(None,1) | ||
+ | y = y[:2000] | ||
+ | y = y.reshape(len(y), 1) + y.reshape(1, len(y)) | ||
+ | ax = plt.axes() | ||
+ | ax.imshow(y) | ||
+ | plt.show() | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Wenn wir nun auch die Fourier-Analyse ins Spiel bringen, können wir noch interessantere Bilder erzeugen: | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | y = recordsnd(None,1) | ||
+ | y = y[:512] | ||
+ | y = np.abs(np.fft.fft(y)) | ||
+ | y = np.concatenate((y[-50:],y[:50]),axis=0) | ||
+ | y = y.reshape(len(y),1) + y.reshape(1,len(y)) | ||
+ | ax = plt.axes() | ||
+ | ax.imshow(y) | ||
+ | plt.show() | ||
+ | |||
+ | |||
+ | </code> | ||
+ | |||
+ | |||
+ | Nun brauchen wir eine Methode, um Tondaten kontinuierlich verarbeiten und anzeigen zu lassen. | ||
+ | Zunächst erstellen wir ein Anzeigeobjekt, zusammen mit einer Methode, wie sich dieses aktualisiert: | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | class Anzeige(object): | ||
+ | |||
+ | def __init__(self,chunk,rate): | ||
+ | self.chunk=chunk | ||
+ | self.pixels = np.random.rand(chunk,chunk) | ||
+ | plt.pause(0.001) | ||
+ | self.rate=rate | ||
+ | self.fig = plt.figure() | ||
+ | self.ax = self.fig.add_axes((0,0.25,0.5,0.5)) | ||
+ | plt.axis("off") | ||
+ | self.ax2 = self.fig.add_axes((0.5,0.25,0.5,0.5)) | ||
+ | plt.axis("off") | ||
+ | #self.image = self.ax.imshow(self.pixels) | ||
+ | self.fig.canvas.draw() | ||
+ | self.noch_kein_erstes_bild_da=True | ||
+ | |||
+ | |||
+ | def update(self,data): | ||
+ | l=len(data) | ||
+ | self.fourier = np.abs(np.fft.fft(data, axis=0)) | ||
+ | self.fourier = np.concatenate((self.fourier[-50:,0],self.fourier[:50,0]),axis=0) | ||
+ | l2 = len(self.fourier) | ||
+ | self.fourier2 = self.fourier.reshape((l2,1))+self.fourier.reshape((1,l2)) | ||
+ | |||
+ | self.pixels=data.reshape((l,1))+data.reshape((1,l)) | ||
+ | if self.noch_kein_erstes_bild_da: | ||
+ | self.image = self.ax.imshow(self.pixels) | ||
+ | self.image.set_cmap("spectral") | ||
+ | self.fourier_image = self.ax2.imshow(self.fourier2) | ||
+ | self.fourier_image.set_cmap("spectral") | ||
+ | self.noch_kein_erstes_bild_da=False | ||
+ | self.fig.canvas.draw() | ||
+ | plt.pause(0.05) | ||
+ | self.image.set_data(self.pixels) | ||
+ | self.fourier_image.set_data(self.fourier2) | ||
+ | |||
+ | |||
+ | anzeige=Anzeige(CHUNK,RATE) | ||
+ | |||
+ | </code> | ||
+ | |||
+ | |||
+ | Dann erstellen wir eine callback-funktion, welche unser Anzeige-objekt sich mit neuen Daten aktualisieren lässt: | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | def micro_callback(in_data, frame_count, time_info, status): | ||
+ | |||
+ | if CHANNELS==2: | ||
+ | y=y.reshape((y.shape[0]//2,2)) | ||
+ | else: | ||
+ | y=y.reshape((y.shape[0],1)) | ||
+ | anzeige.update(y) | ||
+ | return (in_data, pyaudio.paContinue) | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Nun wird ein Audiostream gestartet, welcher, immer wenn CHUNK frames vom Mikrophon gelesen wurden, unsere callback-funktion aufruft: | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | p = pyaudio.PyAudio() | ||
+ | stream = p.open(format=pyaudio.paInt16 , | ||
+ | channels=CHANNELS, | ||
+ | rate=RATE, | ||
+ | input=True, | ||
+ | output=False, | ||
+ | stream_callback=micro_callback, | ||
+ | frames_per_buffer=CHUNK) | ||
+ | |||
+ | stream.start_stream() | ||
+ | time.sleep(0.5) | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Schließlich startet unsere Hauptschleife, welche das Anzeige-objekt so lange darstellt, wie der Stream aktiv ist: | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | while stream.is_active(): | ||
+ | anzeige.fig.canvas.draw() | ||
+ | anzeige.fig.canvas.flush_events() | ||
+ | |||
+ | | ||
+ | </code> | ||
+ | |||
+ | ===Das Endprodukt=== | ||
+ | |||
+ | {{ws1415:projekte_im_wintersemester_2014_15:bild2.png}} | ||
+ | |||
+ | [[Protokolle]] |