Vor einigen Wochen habe ich Fragen zu Spektrogrammen gestellt und mich
dann für meinen ersten Versuch für morlet-wavelets zum Analysieren von
Audiosignalen entschieden.
Die Sache gefällt mir mittlerweile ganz gut, auch wenn ich einige der
ursprünglichen Vorgaben, vor allem "Anzahl der Filter" reduzieren
musste.
Derzeit arbeite ich mit 300 logarithmisch skalierten Frequenzen "freqs"
zwischen 20Hz und 20kHz. Alle "omegas" sind > 6.0. Mein Testsignal ist
ein Sinuston, der innerhalb von 1 Sek durch 10 Oktaven steppt.
Meine Wavelets entstehen in python so:
1 | widths = omegas * sample_rate / (2 * freqs * np.pi) # F
|
2 | omegas = np.reshape(omegas, (-1, 1)) # F x 1
|
3 | widths = np.reshape(widths, (-1, 1)) # F x 1
|
4 |
|
5 | # From scipy.morlet2
|
6 | coords_t = np.reshape(np.arange(0, M) - (M - 1.0) / 2, (1, -1)) # 1 x M
|
7 | coords_t = coords_t / widths # F x M
|
8 |
|
9 | wavelets = (
|
10 | np.exp(1j * coords_t * omegas) * np.exp(-0.5 * (coords_t**2)) * (np.pi ** (-0.25))
|
11 | ) # F x M
|
12 | wavelets = wavelets / widths # F x M
|
13 | return wavelets # F x M
|
Besonders wichtig ist hier wohl die vorletzte Zeile, da ich hier nicht
mit sqrt(widths) sondern mit widths direkt skaliere. Damit weiche ich
von der scipy-Bibiothek ab, bekomme aber Spektrogramme, die meiner
Meinung nach gefühlt besser die Lautstärke abbilden.
Der Vergleich mit dem DSP-Spektrukmanalyzer meiner Studiosoundkarte
bestätigt das.
Jetzt war meine Überlegung, wie ich aus einem damit erzeugten
Spektrogramm das ursprüngliche Signal wieder herstellen könnte.
Das beste, was ich bisher erreichen konnte ist dieser Code:
1 | intermed = spectrogram # F x T
|
2 | intermed *= np.reshape(np.sqrt(freqs), (-1, 1))
|
3 | intermed = np.mean(intermed, axis=0)
|
4 | intermed = np.real(intermed)
|
5 | audio = intermed
|
Allerdings ist die Amplitude des Signals wieder leicht frequenzabhängig.
Kann jemand erkennen, was noch fehlt?
Oder ist das prinzipbedingt, da die mittleren Frequenzen einfach von der
größten Zahl an Wavelets abgedeckt werden?