From e9531e8609a23922ef076ba96d435161df9b4beb Mon Sep 17 00:00:00 2001 From: Tobias Hienzsch Date: Fri, 12 Jul 2024 15:11:56 +0200 Subject: [PATCH] [python] Add speaker module --- src/python/speaker/__init__.py | 0 src/python/speaker/alignment.py | 33 +++++++++++++++++ src/python/speaker/crossover.py | 42 ++++++++++++++++++++++ src/python/speaker/enclosure.py | 63 +++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 src/python/speaker/__init__.py create mode 100644 src/python/speaker/alignment.py create mode 100644 src/python/speaker/crossover.py create mode 100644 src/python/speaker/enclosure.py diff --git a/src/python/speaker/__init__.py b/src/python/speaker/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/python/speaker/alignment.py b/src/python/speaker/alignment.py new file mode 100644 index 0000000..20f2010 --- /dev/null +++ b/src/python/speaker/alignment.py @@ -0,0 +1,33 @@ +import numpy as np + + +def main(): + c = 343 + + tweeter = np.array([0, 0, 1.2]) + midrange = np.array([0, 0, 1.1]) + woofer = np.array([0, 0, 0.9]) + subwoofer = np.array([0, 0, 0.5]) + + listener = np.array([1.0, 2.0, 1.2]) + + t_tweeter = np.linalg.norm(listener - tweeter)/c + t_midrange = np.linalg.norm(listener - midrange)/c + t_woofer = np.linalg.norm(listener - woofer)/c + t_subwoofer = np.linalg.norm(listener - subwoofer)/c + + rd_midrange = t_midrange-t_tweeter + rd_woofer = t_woofer-t_tweeter + rd_subwoofer = t_subwoofer-t_tweeter + + print(f"t_tweeter={t_tweeter*1000:.2f} ms") + print(f"t_midrange={t_midrange*1000:.2f} ms") + print(f"t_woofer={t_woofer*1000:.2f} ms") + print(f"t_subwoofer={t_subwoofer*1000:.2f} ms") + print(f"rd_midrange={rd_midrange*1000:.3f} ms") + print(f"rd_woofer={rd_woofer*1000:.3f} ms") + print(f"rd_subwoofer={rd_subwoofer*1000:.3f} ms") + + +if __name__ == "__main__": + main() diff --git a/src/python/speaker/crossover.py b/src/python/speaker/crossover.py new file mode 100644 index 0000000..13ba12c --- /dev/null +++ b/src/python/speaker/crossover.py @@ -0,0 +1,42 @@ +import matplotlib.pyplot as plt +import numpy as np +from scipy.signal import butter, filtfilt, firwin, lfilter + + +def main(): + fc = 400 + fs = 48000 + dt = 1/fs + n = fs + + sig = np.zeros(n, dtype=np.float64) + sig[0] = 1.0 + + num_taps = 101 + lowpass_taps = firwin(num_taps, fc, window='hamming', fs=fs) + + # Design a highpass FIR filter by spectral inversion + highpass_taps = -lowpass_taps + highpass_taps[num_taps // 2] += 1 + + lowpass_sig = lfilter(lowpass_taps, 1.0, sig) + highpass_sig = lfilter(highpass_taps, 1.0, sig) + + freqs = np.fft.rfftfreq(n, d=dt) + lowpass_spectrum = np.fft.rfft(lowpass_sig) + highpass_spectrum = np.fft.rfft(highpass_sig) + + lowpass_amplitude = np.abs(lowpass_spectrum) + highpass_amplitude = np.abs(highpass_spectrum) + mix_amplitude = lowpass_amplitude+highpass_amplitude + + # plt.semilogx(freqs, 20*np.log10(lowpass_amplitude), label="LP") + # plt.semilogx(freqs, 20*np.log10(highpass_amplitude), label="HP") + plt.semilogx(freqs, 20*np.log10(mix_amplitude), label="LP+HP") + plt.grid() + plt.legend() + plt.show() + + +if __name__ == "__main__": + main() diff --git a/src/python/speaker/enclosure.py b/src/python/speaker/enclosure.py new file mode 100644 index 0000000..b60958c --- /dev/null +++ b/src/python/speaker/enclosure.py @@ -0,0 +1,63 @@ + +def sealed_enclosure_volume(Vas, Qtc, Qts): + """ + Vas: Equivalent compliance volume + Qtc: Desired system Q, typically around 0.7 for a good balance between transient response and efficiency + Qts: Total Q factor of the driver + """ + return Vas/((Qtc/Qts)**2-1) + + +def ported_enclosure_volume(Vas, Fs, Fb): + """ + Vas: Equivalent compliance volume + Fs: Driver resonant frequency + Fb: Tuning frequency + """ + return (Vas*(0.7*Fs))/(Fb-0.7*Fs) + + +def port_length(Vb, Fb, D): + """ + Port length for a ported speaker enclosure + + Vb: Enclosure volume + Fb: Tuning frequency + D: Port diameter + """ + return (23562.5*(D**2))/((Fb**2) * Vb) + + +def main(): + Vas = 50 + Qtc = 0.707 + Qts = 0.4 + Fs = 30 + Fb = 35 + D = 10 + + Vas = 197 + Qtc = 0.707 + Qts = 0.32 + Fs = 17 + Fb = 25 + D = 12 + + Vas = 103.61 + Qtc = 0.707 + Qts = 0.35 + Fs = 28 + Fb = 32 + D = 10 + + Vs = sealed_enclosure_volume(Vas, Qtc, Qts) + Vp = ported_enclosure_volume(Vas, Fs, Fb) + Lp = port_length(Vp, Fb, D) + + print(f"sealed: {Vs:.2f} l") + print(f"ported: {Vp:.2f} l") + print(f"port: {Lp:.2f} cm") + + +if __name__ == "__main__": + main()