= 50
n_modes = 44100
n_steps = 44100
sample_rate = 1.0 / sample_rate
dt = 0.2
excitation_position = 0.5
readout_position = 0.04
initial_deflection = 101 # number of gridpoints for evaluating the eigenfunctions
n_gridpoints = StringParameters() string_params
Non-linear models
The non-linear models are also similar to simulate. We add a non-linear to the equation:
\[\begin{equation} \rho \ddot{w} + \left(d_1 + d_3 \Delta\right)\dot{w} + (D \Delta \Delta - T_0 \Delta) w = f_{\text{ext}} - f_{\text{nl}}, \end{equation}\]
where \(f_{\text{nl}}\) is the non-linear term. Again we get damped harmonic oscillators:
\[\begin{equation} \ddot{q}_{\mu} + 2\gamma_{\mu}\dot{q}_{\mu} + \omega_{\mu}^2 q_{\mu} = \bar{f}_{\text{ext},\mu} - \bar{f}_{\text{nl},\mu}, \end{equation}\]
where \(\bar{f}_{\text{nl},\mu}\) is the non-linear term in modal space. This term differs depending on the type of non-linearity and whether we are simulating a string, membrane or plate.
Tension modulated string
For tension-modulated strings the non-linear term expanded in modal coordinates is given by:
\[\begin{equation} \bar{f}_{nl} = \tau \sum_{\mu} \frac{\lambda_{\mu} q_{\mu}^2}{||\Phi_{\mu}||^2}, \end{equation}\]
where \(\tau\) is:
\[\begin{equation} \tau = \frac{E A}{2 L} \end{equation}\]
First, we set up the parameters for the string.
Get the eigenpairs and the initial condition
Code
= string_eigenvalues(n_modes, string_params.length)
lambda_mu = np.sqrt(lambda_mu)
wn = np.linspace(0, string_params.length, n_gridpoints)
grid = string_eigenfunctions(wn, grid)
K
= create_pluck_modal(
u0_modal
lambda_mu,=excitation_position,
pluck_position=initial_deflection,
initial_deflection=string_params.length,
string_length
)= inverse_STL(K, u0_modal, string_params.length)
u0 = plt.subplots(1, 1, figsize=(6, 2))
fig, ax
ax.plot(grid, u0)"Position (m)")
ax.set_xlabel("Deflection (m)")
ax.set_ylabel("Initial deflection of the string")
ax.set_title(True) ax.grid(
Define the non-linear term and integrate in time
Code
= damping_term(string_params, lambda_mu)
gamma2_mu = stiffness_term(string_params, lambda_mu)
omega_mu_squared
= string_tau_with_density(string_params)
string_tau = string_params.length / 2
string_norm
# include the norm and lambda_mu to make it more compact
= string_tau * lambda_mu / string_norm
string_tau
= make_tm_nl_fn(lambda_mu, string_tau)
nl_fn = solve_tf_initial_conditions(
_, modal_sol
gamma2_mu,
omega_mu_squared,=u0_modal,
u0=jnp.zeros_like(u0_modal),
v0=dt,
dt=n_steps,
n_steps=nl_fn,
nl_fn
)
# transpose to have modes in the first dimension
= modal_sol.T
modal_sol
print(modal_sol.shape)
(50, 44100)
Code
= np.arange(1, n_modes + 1) # mode indices
mu
= evaluate_string_eigenfunctions(
readout_weights
mu,
readout_position,
string_params,
)
# at a single point
= readout_weights @ modal_sol
u_readout
# at all points
= inverse_STL(K, modal_sol, string_params.length)
sol
=sample_rate))
display(Audio(u_readout, rate= plt.subplots(1, 1, figsize=(6, 2))
fig, ax
ax.plot(u_readout)"Sample")
ax.set_xlabel("Deflection (m)")
ax.set_ylabel("Deflection of the string at a single point")
ax.set_title(-2, sample_rate // 10)
ax.set_xlim(True) ax.grid(
Tension modulated plate
The tension-modulated plate works just like the string we saw earlier, same non-linear term, but with a different \(\tau\) value:
\[ \tau = \frac{E h}{2 L_x L_y (1 - \nu^2)} \]
Define the parameters for the plate
Code
= 15
n_modes_x = 15
n_modes_y = n_modes_x * n_modes_y
n_modes = 44100
n_steps = 44100
sample_rate = 1.0 / sample_rate
dt = 1.0 # seconds
excitation_duration = 40
excitation_amplitude = (0.05, 0.05)
force_position = (0.1, 0.1)
readout_position = PlateParameters(
plate_params =0.0,
Ts0=1e-4,
d1=1e-2,
d3 )
Get the eigenpairs and the excitation
Code
= plate_wavenumbers(
wnx, wny
n_modes_x,
n_modes_y,
plate_params.l1,
plate_params.l2,
)= plate_eigenvalues(wnx, wny)
lambda_mu_2d = 101
n_gridpoints_x = 151
n_gridpoints_y = np.linspace(0, plate_params.l1, n_gridpoints_x)
x = np.linspace(0, plate_params.l2, n_gridpoints_y)
y = plate_eigenfunctions(wnx, wny, x, y)
K
# Sort the eigenvalues and get the indices
= np.argsort(lambda_mu_2d.ravel())
indices = np.unravel_index(indices, lambda_mu_2d.shape)
ky_indices, kx_indices = ky_indices + 1, kx_indices + 1
ky_indices, kx_indices = np.stack([kx_indices, ky_indices], axis=-1)
selected_indices = np.sort(lambda_mu_2d.reshape(-1))
lambda_mu
= create_1d_raised_cosine(
rc =excitation_duration,
duration=0.010,
start_time=0.012,
end_time=excitation_amplitude,
amplitude=sample_rate,
sample_rate
)
= (
weights_at_ex
evaluate_rectangular_eigenfunctions(
selected_indices,
force_position,=plate_params,
params
)/ plate_params.density
)
= evaluate_rectangular_eigenfunctions(
weights_at_readout
selected_indices,
readout_position,=plate_params,
params
)
= np.outer(rc, weights_at_ex) modal_excitation
Define the non-linear term and integrate in time
Code
= damping_term(
gamma2_mu
plate_params,
lambda_mu,
)= stiffness_term(
omega_mu_squared
plate_params,
lambda_mu,
)
= (plate_params.E * plate_params.h) / (
plate_tau 2 * plate_params.l1 * plate_params.l2 * (1 - plate_params.nu**2)
)= plate_tau / plate_params.density
plate_tau = 0.25 * plate_params.l1 * plate_params.l2
plate_norm
= plate_tau * lambda_mu / plate_norm
plate_tau
= make_tm_nl_fn(lambda_mu, plate_tau)
nl_fn
= solve_tf_excitation(
_, modal_sol
gamma2_mu,
omega_mu_squared,
modal_excitation,
dt,=nl_fn,
nl_fn
)
= modal_sol.T modal_sol
Von Karman plate
In the Von Karman plate we have a different non-linear term:
\[\begin{equation} \bar{f}_{nl} = \frac{E S_w}{2 \rho} \sum_{p, q, r}^n \frac{H_{q, r}^n C_{p, n}^s}{\zeta_n^4} q_p q_q q_r, \end{equation}\]
We will use the same parameters as in the tension-modulated plate above but now we need the coupling coefficients (assuming simply supported boundary conditions). Calculating the coupling coefficients can take a while, so we will only use 10 in-plane modes and all transverse modes. We will also set \(S_w = ||\Phi||^2\) and increase the excitation amplitude to make the coupling effect more noticeable
Integrate in time. This is fast however with more modes it will take longer. In any case, this will take longer than the tension-modulated plate.
Code
= damping_term(
gamma2_mu
plate_params,
lambda_mu,
)= stiffness_term(
omega_mu_squared
plate_params,
lambda_mu,
)
= make_vk_nl_fn(H1_scaled)
nl_fn
= solve_tf_excitation(
_, modal_sol
gamma2_mu,
omega_mu_squared,* amplitude_scaling,
modal_excitation
dt,=nl_fn,
nl_fn
)
= modal_sol.T modal_sol