| | import numpy as np |
| |
|
| | import tmatrix |
| | from utils import layer_wise_dot_product, struve, bessel |
| | from config import AcousticalConstantsConfig |
| |
|
| |
|
| | def simulate_loudspeaker( |
| | thiele_small_params: dict, |
| | angular_freq_array: np.ndarray, |
| | acoustical_constants: AcousticalConstantsConfig, |
| | ): |
| |
|
| | n_bins = len(angular_freq_array) |
| | Re_tmatrix = tmatrix.resistance_series(thiele_small_params["Re"], n_bins) |
| | Z_Le_tmatrix = tmatrix.inductance_series( |
| | thiele_small_params["Le"], angular_freq_array |
| | ) |
| | Bl_tmatrix = tmatrix.gyrator(thiele_small_params["Bl"], n_bins) |
| | Z_Mm_tmatrix = tmatrix.inductance_series( |
| | thiele_small_params["Mm"], angular_freq_array |
| | ) |
| | Z_Cm_tmatrix = tmatrix.capacitance_series( |
| | thiele_small_params["Cm"], angular_freq_array |
| | ) |
| | Rm_tmatrix = tmatrix.resistance_series(thiele_small_params["Rm"], n_bins) |
| |
|
| | electro_mechanical_tmatrix = layer_wise_dot_product( |
| | Re_tmatrix, |
| | Z_Le_tmatrix, |
| | Bl_tmatrix, |
| | Z_Mm_tmatrix, |
| | Z_Cm_tmatrix, |
| | Rm_tmatrix, |
| | ) |
| |
|
| | t_11 = electro_mechanical_tmatrix[0, 0] |
| | t_12 = electro_mechanical_tmatrix[0, 1] |
| | t_21 = electro_mechanical_tmatrix[1, 0] |
| | t_22 = electro_mechanical_tmatrix[1, 1] |
| |
|
| | |
| | electrical_impedance_shorted_output = t_12 / t_22 |
| |
|
| | |
| | electrical_input_voltage = np.ones(n_bins) |
| | electrical_input_current = ( |
| | electrical_input_voltage / electrical_impedance_shorted_output |
| | ) |
| |
|
| | electro_mechanical_tmatrix_det = np.abs(t_11 * t_22 - t_12 * t_21) |
| |
|
| | electro_mechanical_tmatrix_inv = np.array( |
| | [ |
| | [ |
| | t_22 / electro_mechanical_tmatrix_det, |
| | -t_12 / electro_mechanical_tmatrix_det, |
| | ], |
| | [ |
| | -t_21 / electro_mechanical_tmatrix_det, |
| | t_11 / electro_mechanical_tmatrix_det, |
| | ], |
| | ] |
| | ) |
| |
|
| | mechanical_force, mechanical_velocity = layer_wise_dot_product( |
| | electro_mechanical_tmatrix_inv, |
| | np.array( |
| | [ |
| | [electrical_input_voltage, electrical_input_voltage], |
| | [electrical_input_current, electrical_input_current], |
| | ] |
| | ), |
| | )[:, 0] |
| |
|
| | mechanical_displacement = mechanical_velocity / ( |
| | 1j * angular_freq_array |
| | ) |
| | mechanical_displacement = mechanical_displacement * 1000 |
| |
|
| | |
| | air_impedance = acoustical_constants.air_density * acoustical_constants.sound_speed |
| | wave_number_array = angular_freq_array / acoustical_constants.sound_speed |
| |
|
| | effective_radiation_radius = thiele_small_params["effective_diameter"] / 2 |
| |
|
| | ka_array = wave_number_array * effective_radiation_radius |
| | Sd_value = np.pi * effective_radiation_radius**2 |
| | Sd_tmatrix = tmatrix.transformer(Sd_value, n_bins) |
| |
|
| | |
| | ZM_rad_real_array = Sd_value * air_impedance * (1 - bessel(2 * ka_array) / ka_array) |
| | ZM_rad_imag_array = ( |
| | Sd_value * air_impedance * (1j * (struve(2 * ka_array) / ka_array)) |
| | ) |
| | ZM_rad_array = (ZM_rad_real_array + 1j * ZM_rad_imag_array).astype(np.complex128) |
| | ZM_rad_tmatrix = np.array( |
| | [[np.ones(n_bins), ZM_rad_array], [np.zeros(n_bins), np.ones(n_bins)]] |
| | ) |
| |
|
| | |
| | ZA_rad = ( |
| | 1j |
| | * angular_freq_array |
| | * acoustical_constants.air_density |
| | * acoustical_constants.directivity_factor |
| | ) / ( |
| | 4 |
| | * np.pi |
| | * acoustical_constants.measurement_distance |
| | * np.exp(1j * wave_number_array * acoustical_constants.measurement_distance) |
| | ) |
| | Z_delay = np.exp( |
| | -1j * wave_number_array * acoustical_constants.measurement_distance |
| | ) |
| |
|
| | electro_mechanical_acoustic_tmatrix = layer_wise_dot_product( |
| | electro_mechanical_tmatrix, ZM_rad_tmatrix, Sd_tmatrix |
| | ) |
| |
|
| | electrical_input_voltage = 2.83 |
| |
|
| | t_11 = electro_mechanical_acoustic_tmatrix[0, 0] |
| | t_12 = electro_mechanical_acoustic_tmatrix[0, 1] |
| | t_21 = electro_mechanical_acoustic_tmatrix[1, 0] |
| | t_22 = electro_mechanical_acoustic_tmatrix[1, 1] |
| |
|
| | voltage_pressure_transfer_function = (ZA_rad) / (t_11 * ZA_rad + t_12) |
| |
|
| | acoustical_pressure = ( |
| | electrical_input_voltage |
| | * (voltage_pressure_transfer_function / Z_delay) |
| | / acoustical_constants.reference_pressure |
| | ) |
| |
|
| | |
| | mechanical_fs = 1 / (2*np.pi*(thiele_small_params["Mm"]*thiele_small_params["Cm"])**(1/2)) |
| | Qm = 2*np.pi*mechanical_fs*(thiele_small_params["Mm"]+0.00092)/thiele_small_params["Rm"] |
| | Qe = 2*np.pi*mechanical_fs*(thiele_small_params["Mm"]+0.00092)/(thiele_small_params["Bl"]**2/thiele_small_params["Re"]) |
| | Qt = (Qm*Qe) / (Qm+Qe) |
| | |
| |
|
| | loudspeaker_responses = { |
| | "electrical_impedance": electrical_impedance_shorted_output, |
| | "mechanical_force": mechanical_force, |
| | "mechanical_velocity": mechanical_velocity, |
| | "mechanical_displacement": mechanical_displacement, |
| | "acoustical_pressure": acoustical_pressure, |
| | "selectivity_params": { |
| | "fs": np.round(mechanical_fs, 2), |
| | "Qm": np.round(Qm, 2), |
| | "Qe": np.round(Qe, 2), |
| | "Qt": np.round(Qt, 2), |
| | }, |
| | } |
| |
|
| | return loudspeaker_responses |
| |
|