Overview of the mdof package#

cc7c27405f594c1a88c1f60150ab47e2

The mdof package is designed to provide a convenient interface for computing dynamic analyses of structural vibrations.

Installation#

If you are running this notebook locally, install mdof from pypi.

pip install mdof

If you are running this notebook from an external server on JupyterHub/JupyterLab, DataHub, or Binder, uncomment and run the next cell to install the required packages.

[1]:
# !pip install -Ur requirements.txt

Import#

In Python, import the package.

[2]:
import mdof

Investigate Structural Vibrations#

1. Simulate or load a structural response.#

Given the modal parameters, what is the structural response data?#

[3]:
from mdof.utilities.config import *
# time parameters
nt, dt, tf, times = create_time_vector(nt=5000,dt=0.03)
# system parameters
T, m, c, k, Phi = gather_system_parameters(T=[3,2],m=10,c=1)
import numpy as np
zeta = c/(2*np.sqrt(m*k))
print(f"Damping ratios:", zeta)
# input motion
input_motion = generate_input(times)
Periods: [3 2]
Modeshapes:
[[1. 0.]
 [0. 1.]]
Damping ratios: [0.02387324 0.01591549]
[4]:
# Calculate the response using numerical integration.
import sdof, numpy as np
output_motion = np.array([sdof.integrate(input_motion,dt,k[i],c,m)[0] for i in range(len(T))])
[5]:
# Plot the input and output motions.
from mdof.utilities.printing import plot_io
plot_io(input_motion, output_motion, times)
../_images/examples_00_Overview_15_0.png

2. Modal identification from data.#

Given the structural response data, what are the modal parameters?#

5668bd04ea774af0af56bcdf8bf174c2

16f32a5f2b5e40329246b99dc9d7587a

[6]:
# With a state-space model:
periods, modeshapes = mdof.modes(input_motion, output_motion, dt=dt, order=2*len(T), method='srim')
print(f"Periods identified from data: {np.round(periods, 3)}")
print(f"Mode shapes identified from data:\n {np.round(np.abs(modeshapes), 3)}")
100%|█████████▉| 4700/4701 [00:00<00:00, 7961.68it/s]
Periods identified from data: [3.001 2.001]
Mode shapes identified from data:
 [[0.071 0.   ]
 [0.    0.071]]

[7]:
# With a frequency domain, output-only model:
from mdof.utilities.printing import plot_fdd
periods, modeshapes = plot_fdd(outputs=output_motion, dt=dt)
print(f"Periods identified from data: {np.round(periods, 3)}")
print(f"Mode shapes identified from data:\n {np.round(np.abs(modeshapes), 3)}")
Periods identified from data: [3.    2.027]
Mode shapes identified from data:
 [[1.    0.001]
 [0.001 1.   ]]
../_images/examples_00_Overview_20_1.png

3. Response prediction from data.#

For any given input motion, can we generate the response of the system?#

[8]:
# Reproduce the response with the state space model
from control import ss, forced_response
from mdof.utilities.printing import plot_pred
realization = mdof.system(method="okid-era", inputs=input_motion, outputs=output_motion,order=2*len(T))
modes = mdof.modal.system_modes(realization,dt)
from mdof.utilities.printing import print_modes
print_modes(modes)
out_pred = forced_response(ss(*realization,dt), U=input_motion, squeeze=False, return_x=False).outputs
plot_pred(ytrue=output_motion, models=out_pred, t=times, title="State Space Model Displacement Response")
print(f"mean absolute error: {np.mean(np.abs(output_motion-out_pred))}")
Spectral quantities:
       T(s)        ζ        EMACO      MPC       EMACO*MPC
      3.001      0.02386    1.0        1.0        1.0
      2.001      0.01589    1.0        1.0        1.0
Mean Period(s): 2.5012359909299633
Standard Dev(s): 0.4997540734771231
mean absolute error: 4.502252727933867e-06
../_images/examples_00_Overview_22_1.png
[9]:
input_motion_2 = np.sin(times)
output_motion_2 = np.array([sdof.integrate(input_motion_2,dt,k[i],c,m)[0] for i in range(len(T))])
out_pred_2 = forced_response(ss(*realization,dt), U=input_motion_2, squeeze=False, return_x=False).outputs
plot_pred(ytrue=output_motion_2, models=out_pred_2, t=times, title="State Space Model Displacement Response on New Input")
print(f"mean absolute error: {np.mean(np.abs(output_motion_2-out_pred_2))}")
mean absolute error: 2.137245385693206e-07
../_images/examples_00_Overview_23_1.png
[10]:
from mdof.macro import stabilization
fig = stabilization(input_motion, output_motion, dt=dt, orders=(2,50,8), plotly=True)
100%|█████████▉| 4700/4701 [00:00<00:00, 5952.00it/s]
100%|█████████▉| 4700/4701 [00:00<00:00, 6087.07it/s]
100%|█████████▉| 4700/4701 [00:00<00:00, 4729.69it/s]
100%|█████████▉| 4700/4701 [00:01<00:00, 3381.52it/s]
100%|█████████▉| 4700/4701 [00:01<00:00, 3117.06it/s]
100%|█████████▉| 4700/4701 [00:02<00:00, 2337.15it/s]
100%|█████████▉| 4700/4701 [00:02<00:00, 1749.45it/s]
/mnt/c/Users/16507/Documents/GitHub/mdof/src/mdof/validation.py:22: RuntimeWarning: divide by zero encountered in scalar divide
  (abs(Phi_final[j,i])/abs(Phi_final_hat[j,i])),
/mnt/c/Users/16507/Documents/GitHub/mdof/src/mdof/validation.py:25: RuntimeWarning: divide by zero encountered in scalar divide
  Pij = np.angle(Phi_final[j,i]/Phi_final_hat[j,i])
/mnt/c/Users/16507/Documents/GitHub/mdof/src/mdof/validation.py:25: RuntimeWarning: invalid value encountered in scalar divide
  Pij = np.angle(Phi_final[j,i]/Phi_final_hat[j,i])
100%|█████████▉| 4700/4701 [00:03<00:00, 1462.44it/s]
100%|█████████▉| 4700/4701 [00:03<00:00, 1294.46it/s]
100%|█████████▉| 4700/4701 [00:04<00:00, 1144.78it/s]
100%|█████████▉| 4700/4701 [00:05<00:00, 852.54it/s]
100%|█████████▉| 4700/4701 [00:06<00:00, 778.18it/s]
100%|█████████▉| 4700/4701 [00:06<00:00, 671.73it/s]
100%|█████████▉| 4700/4701 [00:08<00:00, 582.11it/s]
100%|█████████▉| 4700/4701 [00:08<00:00, 541.13it/s]
100%|█████████▉| 4700/4701 [00:09<00:00, 470.55it/s]
100%|█████████▉| 4700/4701 [00:10<00:00, 456.09it/s]
100%|█████████▉| 4700/4701 [00:11<00:00, 397.76it/s]
100%|█████████▉| 4700/4701 [00:12<00:00, 376.56it/s]
100%|█████████▉| 4700/4701 [00:14<00:00, 334.79it/s]
100%|█████████▉| 4700/4701 [00:14<00:00, 316.72it/s]
100%|█████████▉| 4700/4701 [00:16<00:00, 287.28it/s]
100%|█████████▉| 4700/4701 [00:17<00:00, 268.64it/s]
100%|█████████▉| 4700/4701 [00:21<00:00, 221.61it/s]
[11]:
fig.update_layout({'xaxis': {'autorange': True},
                  'xaxis2':{'range':(0,0.1), 'autorange': False},
                  'yaxis':{'range':(0,10), 'autorange': False}})