alles war. Dann habe ich einen super nervigen Effekt getroffen: Als der aufgezeichnete Puffer wächst, driftet das aufgetragene Spektrum langsam im Level ab, obwohl sich der Eingangspegel nicht ändert. Klassische Normalisierung wie diese lässt es sinken: < /p>
Code: Select all
yf = np.abs(np.fft.rfft(record))
yf1 = 2 * yf / len(record) # standard amplitude normalization
< /code>
Das ist seltsam, weil sich die aufgezeichnete Signalpegel im Laufe der Zeit nicht ändert. < /p>
Ich habe also angefangen zu experimentieren. Am Ende hatte ich eine Normalisierung, die unabhängig von den Generatorparametern auf magische Weise stabil bleibt: < /p>
yf = np.abs(np.fft.rfft(record))
yf2 = yf / nk
nk = np.sqrt(length * rate / np.log10(band[1] / band[0]) / 10) * 10 ** (0.35726 / 20)
< /code>
Dies funktioniert erschreckend gut. Aber… warum? Es animiert zwei Spuren (line1
Code: Select all
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.axes import Axes
from matplotlib.lines import Line2D
# Setting sweep params
rate: int = 96000
chunksize: int = 4096
band = np.asarray((50, 2000), np.float64) / rate
t_end = 30
length = int(t_end * rate)
nk = np.sqrt(length * rate / np.log10(band[1] / band[0]) / 10) * 10 ** (0.35726 / 20)
# Generating sweep
k = length * band[0] / np.log(band[1] / band[0])
l = length / np.log(band[1] / band[0])
t = np.arange(0, length, dtype=np.float64)
sweep = np.sin(2 * np.pi * k * (np.exp(t / l) - 1))
# Initialise plt in interactive mode
plt.ion()
_, ax = plt.subplots()
ax: Axes = ax
ax.grid(True, which="both")
(line1,) = ax.semilogx([], [])
(line2,) = ax.semilogx([], [])
line1: Line2D = line1
line2: Line2D = line2
ax.set_xlim(20, 20e3)
ax.set_ylim(-60, 60)
for start in range(0, length, chunksize):
end = min(start + chunksize, int(length))
chunk = sweep[:end]
xf = np.fft.rfftfreq(len(chunk), 1 / rate)
yf = np.abs(np.fft.rfft(chunk))
# "Textbook" amplitude normalization
yf1 = 2 * yf / len(chunk)
pinked_yf1 = yf1 * np.sqrt(xf) # pink weighting to look at ~constant SPL per octave
log_yf1 = 20 * np.log10(pinked_yf1.clip(1e-12, None))
line1.set_data(xf, log_yf1)
# My weird normalization
yf2 = yf / nk
pinked_yf2 = yf2 * np.sqrt(xf)
log_yf2 = 20 * np.log10(pinked_yf2.clip(1e-12, None))
line2.set_data(xf, log_yf2)
plt.draw()
plt.pause(0.1)
plt.ioff()
plt.show()
< /code>
Was ich denke < /em> Ich verstehe (vielleicht?) < /H2>
Verwenden von np.sqrt (Länge * Rate) < /code> In der Nenner fühlt sich in Richtung der Spezifische Spezifikum von < /psd.10*log10(|rfft(record)/length/rate|^2) == 20*log10(|rfft(record)| / sqrt(length*rate))
< /code>
Ich kann mit dieser Idee leben. Aber in meiner Falllänge == Len (Sweep)
Code: Select all
/ 10
Code: Select all
10 ** (0.35726 / 20)
$$
stabilisieren Dinge? FFT Bin Breite usw.) und erklären Warum landet der logarithmische Span in einer quadratischen Wurzel ? sonst? Nicht-stationäres "Fenster") < /li>
Rosa-Gewichtung über SQRT (f) < /code> < /li>
log Sweep-Amplitudengesetz
Das würde genau ~ 0,35726 db? & Kontext
Ich mache Echtzeit Analyse , während der Sweep immer noch läuft. Das bedeutet, dass jedes FFT ein unterschiedliches Präfix eines Protokoll -Sweep sieht, kein stationäres Segment eines stationären Prozesses. Ich weiß, dass dies „typischen“ FFT -Annahmen (Stationarität, Periodizität im Fenster usw.) feindlich ist. Ich bin mir bewusst, dass dies eine Leckage einlädt, wenn die augenblickliche Frequenz nicht genau auf einem Behälter landet - was es hier nie tut.
Code: Select all
* sqrt(f)
Beispielcode und Parameter sind oben; Sie können es ausführen und Zeile 1 sinken, während Zeile2 flach bleibt. wachsende Prefix logarithmischer Sweep , die Abhängigkeit von der Gesamtdauer, der Stichprobenrate und der logarithmischen Frequenzspanne erklärt. Wenn es sich tatsächlich um tiefere Fehler handelt (z. B. falsche Referenz der rosa Gewichtung, Jahrzehnt gegen Oktavkonstanten, Ln vs log10, RMS vs Peak, ein-gegen-zweiseitiges PSD), würde ich gerne die Grundursache reparieren, die die Ursache nicht reparieren würde, anstatt die Band-Aid zu behalten. Alle DSP-Leute, die mir helfen können, hartkodierende mysteriöse Konstanten zu stoppen, werden meine ewige Dankbarkeit (und einen knusprigen PR-Link im Repo) verdienen.
Alles, was a sich