<jupyter_start><jupyter_text>Modes of a Vibrating Building Under Sinusoidal ForcingThe equations of motion for the four story building take this form:$$\mathbf{M} \dot{\bar{s}} + \mathbf{K} \bar{c} = \bar{F}$$where$$\bar{c} = \begin{bmatrix} x_1 \\ x_2 \\ x_3 \\ x_4 \end{bmatrix},\bar{s} = \begin{bmatrix} v_1 \\ v_2 \\ v_3 \\ v_4 \end{bmatrix}$$$$\mathbf{M} =\begin{bmatrix}m_1 & 0 & 0 & 0 \\0 & m_2 & 0 & 0 \\0 & 0 & m_3 & 0 \\0 & 0 & 0 & m_4\end{bmatrix}$$$$\mathbf{K} =\begin{bmatrix}k_1+k_2 & -k_2 & 0 & 0 \\-k_2 & k_2 + k_3 & -k_3 \\0 & -k_3 & k_3+k_4 & -k_4 \\0 & 0 & -k_4 & k_4\end{bmatrix}$$$$\bar{F} = \begin{bmatrix} F_1(t) \\ F_2(t) \\ F_3(t) \\ F_4(t) \end{bmatrix}$$The forces $F_1, F_2, F_3, F_4$ are the lateral, arbitrary, forces applied to each floor.<jupyter_code>import numpy as np
import matplotlib.pyplot as plt
from resonance.linear_systems import FourStoryBuildingSystem<jupyter_output><empty_output><jupyter_text>This gives a bit nicer printing of large NumPy arrays.<jupyter_code>np.set_printoptions(precision=5, linewidth=100, suppress=True)
%matplotlib widget<jupyter_output><empty_output><jupyter_text>Determine the model frequiences by calculating the eigenvalues<jupyter_code>sys = FourStoryBuildingSystem()
M, C, K = sys.canonical_coefficients()
L = np.linalg.cholesky(M)
K_tilde = np.linalg.inv(L) @ K @ np.linalg.inv(L.T)
evals, evecs = np.linalg.eig(K_tilde)<jupyter_output><empty_output><jupyter_text>These are the modal frequencies in radians per second:<jupyter_code>ws = np.sqrt(evals)
ws<jupyter_output><empty_output><jupyter_text>Forcing the fourth floor at the largest natural frequency Note that the initial state values are not all zero. Set them all to zero so we see only the effects of forcing.<jupyter_code>sys.states
sys.coordinates['x1'] = 0.0
sys.coordinates['x2'] = 0.0
sys.coordinates['x3'] = 0.0
sys.coordinates['x4'] = 0.0
sys.states<jupyter_output><empty_output><jupyter_text>Create two new constants that describe an amplitude for a sinusoidal forcing.$$F(t) = A\sin(\omega T)$$<jupyter_code>sys.constants['amplitude'] = 100  # N
sys.constants['frequency'] = np.deg2rad(10.0)  # rad/s<jupyter_output><empty_output><jupyter_text>Now define a function that takes constants and/or time as inputs and outputs the entries of $\bar{F}$ in the same order as the coordinates and speeds. The following definition applies a sinusoidal force only to the 4th floor.<jupyter_code>def push_floor(amplitude, frequency, time):
    F1 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    F2 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    F3 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    F4 = amplitude * np.sin(frequency * time)
    return F1, F2, F3, F4<jupyter_output><empty_output><jupyter_text>This function should work with scalar values of time and 1d arrays of time:<jupyter_code>push_floor(1.0, 2.0, 3.0)
push_floor(1.0, 2.0, np.ones(5))<jupyter_output><empty_output><jupyter_text>Now add the forcing function to the system:<jupyter_code>sys.forcing_func = push_floor<jupyter_output><empty_output><jupyter_text>The `forced_response()` function works like the `free_response()` function but it will apply the forcing in the simulation.<jupyter_code>traj = sys.forced_response(100)
traj[sys.coordinates.keys()].plot(subplots=True);
sys.animate_configuration(fps=10, repeat=False)<jupyter_output><empty_output><jupyter_text>Exercise: Forcing at the modal frequenciesUpdate the `frequency` value to simulate the fourth floor being forced at each of the four natural frequencies and note your observations. Compare the obeserved motion to the mode shapes associated with that modal frequency. Use the animation to help visualize what is happening.<jupyter_code>sys.constants['frequency'] = ws[0]  # rad/s
traj = sys.forced_response(100)
traj[sys.coordinates.keys()].plot(subplots=True)
sys.animate_configuration(fps=10, repeat=False)
sys.constants['frequency'] = ws[1]  # rad/s
traj = sys.forced_response(100)
traj[sys.coordinates.keys()].plot(subplots=True)
sys.animate_configuration(fps=10, repeat=False)
sys.constants['frequency'] = ws[2]  # rad/s
traj = sys.forced_response(100)
traj[sys.coordinates.keys()].plot(subplots=True)
sys.animate_configuration(fps=10, repeat=False)
sys.constants['frequency'] = ws[3]  # rad/s
traj = sys.forced_response(100)
traj[sys.coordinates.keys()].plot(subplots=True)
sys.animate_configuration(fps=10, repeat=False)<jupyter_output><empty_output><jupyter_text>Exercise: Forcing at a nodeRecall that the 3rd mode shape has an eigenvector component that is zero:<jupyter_code>evecs<jupyter_output><empty_output><jupyter_text>This is called a "node". This node is associated with $x_3$, the third floor and it tells us that there is no motion at floor 3 if this mode is excited.Adjust the forcing function to apply sinusoidal forcing at the third floor. Use the third modal frequency to apply forcing to the third floor, then use one of the other modal frequencies to force the third floor. Compare the results and discuss your observations.<jupyter_code>sys.constants['frequency'] = ws[2]  # rad/s
def push_floor(amplitude, frequency, time):
    F1 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    F2 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    F3 = amplitude * np.sin(frequency * time)
    F4 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    return F1, F2, F3, F4
sys.forcing_func = push_floor
traj = sys.forced_response(100)
traj[sys.coordinates.keys()].plot(subplots=True)
sys.animate_configuration(fps=10, repeat=False)
sys.constants['frequency'] = ws[0]  # rad/s
def push_floor(amplitude, frequency, time):
    F1 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    F2 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    F3 = amplitude * np.sin(frequency * time)
    F4 = 0.0 if np.isscalar(time) else np.zeros_like(time)
    return F1, F2, F3, F4
sys.forcing_func = push_floor
traj = sys.forced_response(100)
traj[sys.coordinates.keys()].plot(subplots=True)
sys.animate_configuration(fps=10, repeat=False)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12559670781893004, 'fraction_numerical': 0.02831275720164609, 'mean_word_length': 5.625954198473282, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '145288', 'license': 'MIT', 'n_tokens_mistral': 2284, 'n_tokens_neox': 2157, 'n_words': 562, 'path': 'notebooks/13-2020/vibrating_building_forcing.ipynb', 'repo_name': 'gbrault/resonance', 'size': '6075'}