The modes of an object are obtained by solving the second order differential equation
\[
Ku + C\dot{u} + M\ddot{u} = f
\]
where \(K\) is the stiffness matrix, \(C\) is the damping matrix and \(M\) is the damping matrix. \(f\) is the force we apply to the system. To solve for the natural modes of the system we set \(f = 0\).
We define a mesh using the material properties density or \(\rho\), young modulus or \(E\), poisson number or \(\nu\), and Rayleigh damping coefficients\(\alpha\) and \(\beta\)
The Lamé parameters are then given by \[
\lambda = \frac{E}{2(1 + \nu)}, \quad \mu = \frac{E \nu}{(1+ \nu)(1 - 2 \nu)},
\]
To retrieve the vibrational modes, we must follow three steps:
Assemble the stiffness and desitity matrices
Set the boundary conditions (set degrees of freedom, by setting zeroes in the matrices)
Solve the generalised eigenvalue problem
These steps are performed by the Material.modes property, which returns a tuple (eigenvalues, eigenvectors). This is cached for each instantiation to solve computation time if subsequent evaluations are required, e.g. in constructing a dataset.
The Material enumeration also provides a damped_frequencies property — also cached — which applies the formula:
to derive the frequencies, where \(\lambda_i\) are the eigenvalues.
Example usage
m = MATERIALS["polycarbonate"]s = System(m)fig, axs = plt.subplots(4, 1, figsize=(8, 8))# plot the eigenvaluesaxs[0].stem(s.eigenvalues)axs[0].set_title("Eigenvalues")# plot the damped frequenciesaxs[1].stem(s.damped_frequencies)axs[1].set_title("Damped Frequencies")axs[1].set_yscale("log")# plot node gainsaxs[2].stem(np.abs(s.get_mode_gains(100)))axs[2].set_title("Mode Gains")# plot amplitude envelopes given by damping coefficientsaxs[3].plot( np.exp(-s.damping_coefficients * np.linspace(0, 2000.0/44100.0, 2000)[..., None]))fig.tight_layout()fig.show()
/tmp/ipykernel_80158/1503038420.py:25: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.
fig.show()
Rendering audio from predefined materials:
f_s =44100T =0.75num_modes =64mesh = create_mesh(n_refinements=4)# get the dimensions of the meshx_min, x_max = mesh.p[0].min(), mesh.p[0].max()y_min, y_max = mesh.p[1].min(), mesh.p[1].max()print(f"Mesh dimensions: {x_max - x_min} x {y_max - y_min}")print(f"Mesh bounding box: ({x_min}, {y_min}) - ({x_max}, {y_max})")for m in MATERIALS: s = System(MATERIALS[m], k=num_modes, mesh=mesh) signal = s.render(T, f_s)print(f"{m.lower()}:") save_and_display_audio(signal, f"{m.lower()}.wav", f_s)