二自由振动的动态图

image


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

from matplotlib.patches import Circle, FancyArrowPatch



# ====================== 1. 系统参数 ======================
k = 1.0
m = 1.0
omega1 = np.sqrt(k / m)
omega2 = np.sqrt(3 * k / m)

tau_full = np.linspace(0, 12, 1000)
t_full = tau_full / omega1

# 各阶模态位移
u1_mode1 = 0.5 * np.cos(omega1 * t_full)
u2_mode1 = 0.5 * np.cos(omega1 * t_full)

u1_mode2 = 0.5 * np.cos(omega2 * t_full)
u2_mode2 = -0.5 * np.cos(omega2 * t_full)

u1_total = u1_mode1 + u1_mode2
u2_total = u2_mode1 + u2_mode2

# ====================== 2. 画布布局:2行,上2列时程,下3列物理动画 ======================
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
fig = plt.figure(figsize=(18, 9))
gs = fig.add_gridspec(2, 3, height_ratios=[2, 1])

# 上排:u1、u2时程曲线
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1])
# 下排三个物理模型:一阶模态、二阶模态、总振动
ax_mod1 = fig.add_subplot(gs[1, 0])
ax_mod2 = fig.add_subplot(gs[1, 1])
ax_total = fig.add_subplot(gs[1, 2])

# 初始化时程曲线
l1_tot, = ax1.plot([], [], 'k-', lw=2, label='自由振动')
l1_m1, = ax1.plot([], [], 'r-', lw=1, label='一阶模态')
l1_m2, = ax1.plot([], [], 'b--', lw=1.2, label='二阶模态')

l2_tot, = ax2.plot([], [], 'k-', lw=2, label='自由振动')
l2_m1, = ax2.plot([], [], 'r-', lw=1, label='一阶模态')
l2_m2, = ax2.plot([], [], 'b--', lw=1.2, label='二阶模态')

# 时程坐标轴设置
ax1.set_xlim(0, 12)
ax1.set_ylim(-1, 1)
ax1.set_xlabel(r'$\omega_1 t$')
ax1.set_ylabel(r'$u_1$')
ax1.grid(alpha=0.3)
ax1.legend()

ax2.set_xlim(0, 12)
ax2.set_ylim(-1, 1)
ax2.set_xlabel(r'$\omega_1 t$')
ax2.set_ylabel(r'$u_2$')
ax2.grid(alpha=0.3)
ax2.legend()

# 封装创建双质量三弹簧两端固定模型函数
def create_spring_mass_ax(ax, title):
    ax.set_xlim(-3, 9)
    ax.set_ylim(-1, 1)
    ax.set_aspect('equal')
    ax.set_title(title)
    ax.axis('off')
    # 左右固定墙壁
    wall_left = plt.Rectangle((-2, -0.5), 1, 1, color='gray')
    wall_right = plt.Rectangle((7, -0.5), 1, 1, color='gray')
    # 两个质量块初始位置
    m1 = plt.Rectangle((1, -0.4), 0.8, 0.8, color='darkblue')
    m2 = plt.Rectangle((3, -0.4), 0.8, 0.8, color='darkred')
    # 三根弹簧:左墙-m1、m1-m2、m2-右墙
    spring_left, = ax.plot([], [], 'k-', lw=1.5)
    spring_mid, = ax.plot([], [], 'k-', lw=1.5)
    spring_right, = ax.plot([], [], 'k-', lw=1.5)
    ax.add_patch(wall_left)
    ax.add_patch(wall_right)
    ax.add_patch(m1)
    ax.add_patch(m2)
    return m1, m2, spring_left, spring_mid, spring_right

# 三个子图模型对象
m1_mod1, m2_mod1, sp_left1, sp_mid1, sp_right1 = create_spring_mass_ax(ax_mod1, "第一阶模态(同相振型)")
m1_mod2, m2_mod2, sp_left2, sp_mid2, sp_right2 = create_spring_mass_ax(ax_mod2, "第二阶模态(反相振型)")
m1_tot, m2_tot, sp_left_t, sp_mid_t, sp_right_t = create_spring_mass_ax(ax_total, "模态叠加总振动")

# 弹簧绘制工具函数
def draw_spring(x_start, x_end):
    n = 50
    x = np.linspace(x_start, x_end, n)
    y = 0.2 * np.sin(np.linspace(0, 10 * np.pi, n))
    return x, y

# ====================== 3. 动画更新函数 ======================
def update(frame):
    # 更新时程曲线
    tau_data = tau_full[:frame]
    l1_tot.set_data(tau_data, u1_total[:frame])
    l1_m1.set_data(tau_data, u1_mode1[:frame])
    l1_m2.set_data(tau_data, u1_mode2[:frame])

    l2_tot.set_data(tau_data, u2_total[:frame])
    l2_m1.set_data(tau_data, u2_mode1[:frame])
    l2_m2.set_data(tau_data, u2_mode2[:frame])

    # ========== 一阶模态 ==========
    um1_1 = u1_mode1[frame]
    um2_1 = u2_mode1[frame]
    pos_m1 = 1 + um1_1
    pos_m2 = 3 + um2_1
    m1_mod1.set_x(pos_m1)
    m2_mod1.set_x(pos_m2)
    sp_left1.set_data(*draw_spring(-1, pos_m1))
    sp_mid1.set_data(*draw_spring(pos_m1 + 0.8, pos_m2))
    sp_right1.set_data(*draw_spring(pos_m2 + 0.8, 7))

    # ========== 二阶模态 ==========
    um1_2 = u1_mode2[frame]
    um2_2 = u2_mode2[frame]
    pos_m1_2 = 1 + um1_2
    pos_m2_2 = 3 + um2_2
    m1_mod2.set_x(pos_m1_2)
    m2_mod2.set_x(pos_m2_2)
    sp_left2.set_data(*draw_spring(-1, pos_m1_2))
    sp_mid2.set_data(*draw_spring(pos_m1_2 + 0.8, pos_m2_2))
    sp_right2.set_data(*draw_spring(pos_m2_2 + 0.8, 7))

    # ========== 总振动 ==========
    ut1 = u1_total[frame]
    ut2 = u2_total[frame]
    pos_m1_t = 1 + ut1
    pos_m2_t = 3 + ut2
    m1_tot.set_x(pos_m1_t)
    m2_tot.set_x(pos_m2_t)
    sp_left_t.set_data(*draw_spring(-1, pos_m1_t))
    sp_mid_t.set_data(*draw_spring(pos_m1_t + 0.8, pos_m2_t))
    sp_right_t.set_data(*draw_spring(pos_m2_t + 0.8, 7))

    return (l1_tot, l1_m1, l1_m2, l2_tot, l2_m1, l2_m2,
            m1_mod1, m2_mod1, sp_left1, sp_mid1, sp_right1,
            m1_mod2, m2_mod2, sp_left2, sp_mid2, sp_right2,
            m1_tot, m2_tot, sp_left_t, sp_mid_t, sp_right_t)

# 关键修改:repeat=True 开启无限循环播放
ani = FuncAnimation(fig, update, frames=len(tau_full), interval=15, blit=True, repeat=True)
fig.suptitle('二自由度系统:一阶模态、二阶模态、模态叠加同步动态演示(两端固定三弹簧)', fontsize=15)
plt.tight_layout()





# ani.save('sine_waves_and_arrows.gif', writer='pillow', fps=12)


plt.show()




posted @ 2026-06-22 18:09  redufa  阅读(13)  评论(0)    收藏  举报