Skip to content

Commit

Permalink
[python] Add speaker module
Browse files Browse the repository at this point in the history
  • Loading branch information
tobiashienzsch committed Jul 12, 2024
1 parent d5d2b26 commit e9531e8
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 0 deletions.
Empty file added src/python/speaker/__init__.py
Empty file.
33 changes: 33 additions & 0 deletions src/python/speaker/alignment.py
Original file line number Diff line number Diff line change
@@ -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()
42 changes: 42 additions & 0 deletions src/python/speaker/crossover.py
Original file line number Diff line number Diff line change
@@ -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()
63 changes: 63 additions & 0 deletions src/python/speaker/enclosure.py
Original file line number Diff line number Diff line change
@@ -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()

0 comments on commit e9531e8

Please sign in to comment.