阻尼振动的可视化 包括源码和推导
flyfish
牛顿第二定律(加速度定律)
胡克定律(Hooke‘s Law)
阻尼振动是指在振动系统中,由于阻力或能量损耗导致振动幅度随时间减小的现象。
左边为无阻尼,右边为有阻尼,有阻尼的摆动会逐渐停止。
对于简单的阻尼振动系统,其运动方程为:
m
d
2
x
d
t
2
+
c
d
x
d
t
+
k
x
=
0
m\frac{d^2x}{dt^2} + c\frac{dx}{dt} + kx = 0
mdt2d2x+cdtdx+kx=0
在摆动系统中,上述方程的对应形式为:
d
ω
d
t
=
−
b
l
ω
−
g
l
sin
(
θ
)
\frac{d\omega}{dt} = -\frac{b}{l} \omega - \frac{g}{l} \sin(\theta)
dtdω=−lbω−lgsin(θ)
- 简单摆动方程(无阻尼) : d θ d t = ω \frac{d\theta}{dt} = \omega dtdθ=ω
d ω d t = − g l sin ( θ ) \frac{d\omega}{dt} = -\frac{g}{l} \sin(\theta) dtdω=−lgsin(θ)
其中:
g
g
g(重力加速度)对应代码中的 GRAVITY = 9.8
。
l
l
l(摆长)对应代码中的 LENGTH = 1.0
。
- 阻尼摆动方程 : d θ d t = ω \frac{d\theta}{dt} = \omega dtdθ=ω
d ω d t = − b l ω − g l sin ( θ ) \frac{d\omega}{dt} = -\frac{b}{l} \omega - \frac{g}{l} \sin(\theta) dtdω=−lbω−lgsin(θ)
其中:
g
g
g(重力加速度)对应代码中的 GRAVITY = 9.8
。
l
l
l(摆长)对应代码中的 LENGTH = 1.0
。
b
b
b(阻尼系数)对应代码中的 DAMPING_COEFFICIENT = 0.2
。
阻尼振动系统的推导
1. 牛顿第二定律
对于一个质量
m
m
m 的物体,其受力情况可以用牛顿第二定律来描述:
F
=
m
d
2
x
d
t
2
F = m \frac{d^2 x}{dt^2}
F=mdt2d2x
其中
x
(
t
)
x(t)
x(t) 是物体的位置函数,
d
2
x
d
t
2
\frac{d^2 x}{dt^2}
dt2d2x 是加速度。
2. 力的组成
在一个简单的阻尼振动系统中,力由以下几部分组成:
弹力 :遵循胡克定律,弹力与位移成正比,并且方向与位移相反。
F
spring
=
−
k
x
F_{\text{spring}} = -kx
Fspring=−kx
其中
k
k
k 是弹簧常数,
x
x
x 是位移。
阻尼力 :阻尼力与速度成正比,并且方向与速度相反。
F
damping
=
−
b
d
x
d
t
F_{\text{damping}} = -b \frac{dx}{dt}
Fdamping=−bdtdx
其中
b
b
b 是阻尼系数,
d
x
d
t
\frac{dx}{dt}
dtdx 是速度。
重力和其他外力 :对于水平振动的简单系统,通常可以忽略重力和其他外力。如果考虑垂直振动,重力可以被包含在弹力的静态部分中。
3. 总受力
总受力为上述各力的叠加:
F
=
F
spring
+
F
damping
=
−
k
x
−
b
d
x
d
t
F = F_{\text{spring}} + F_{\text{damping}} = -kx - b \frac{dx}{dt}
F=Fspring+Fdamping=−kx−bdtdx
4. 代入牛顿第二定律
根据牛顿第二定律:
m
d
2
x
d
t
2
=
−
k
x
−
b
d
x
d
t
m \frac{d^2 x}{dt^2} = -kx - b \frac{dx}{dt}
mdt2d2x=−kx−bdtdx
5. 标准形式
将上述方程整理为标准形式:
m
d
2
x
d
t
2
+
b
d
x
d
t
+
k
x
=
0
m \frac{d^2 x}{dt^2} + b \frac{dx}{dt} + kx = 0
mdt2d2x+bdtdx+kx=0这个方程描述了一个质量
m
m
m 的物体在弹簧常数
k
k
k 和阻尼系数
b
b
b 下的阻尼振动。可以将其简化为无量纲形式,定义以下参数:
固有角频率(不含阻尼):
ω
0
=
k
m
\omega_0 = \sqrt{\frac{k}{m}}
ω0=mk
阻尼比:
γ
=
b
2
m
\gamma = \frac{b}{2m}
γ=2mb
于是方程可以写成:
d
2
x
d
t
2
+
2
γ
d
x
d
t
+
ω
0
2
x
=
0
\frac{d^2 x}{dt^2} + 2\gamma \frac{dx}{dt} + \omega_0^2 x = 0
dt2d2x+2γdtdx+ω02x=0
运动方程
对于阻尼振动系统,方程描述的是阻尼摆动:
d
2
x
d
t
2
+
2
γ
d
x
d
t
+
ω
0
2
x
=
0
\frac{d^2 x}{dt^2} + 2\gamma \frac{dx}{dt} + \omega_0^2 x = 0
dt2d2x+2γdtdx+ω02x=0
动画代码中的公式
之前在动画代码中使用的阻尼摆动方程是:
d
θ
d
t
=
ω
\frac{d\theta}{dt} = \omega
dtdθ=ω
d
ω
d
t
=
−
b
ω
−
g
l
sin
(
θ
)
\frac{d\omega}{dt} = -b \omega - \frac{g}{l} \sin(\theta)
dtdω=−bω−lgsin(θ)这里,
θ
\theta
θ 是摆角,
ω
\omega
ω 是角速度:
b
b
b 是阻尼系数,对应代码中的 DAMPING_COEFFICIENT
。
g
l
\frac{g}{l}
lg 是摆动系统中的恢复力系数,对应代码中的 GRAVITY / LENGTH
。
可视化源码实现
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.integrate import odeint
from math import sin, cos
# Constants
GRAVITY = 9.8
LENGTH = 1.0
DAMPING_COEFFICIENT = 0.2
def pendulum_equations_no_damping(state, t, length):
"""Equations for a simple pendulum without damping."""
theta, omega = state
dtheta_dt = omega
domega_dt = -GRAVITY / length * sin(theta)
return dtheta_dt, domega_dt
def pendulum_equations_damping(state, t, length, damping):
"""Equations for a simple pendulum with damping."""
theta, omega = state
dtheta_dt = omega
domega_dt = -damping * omega - GRAVITY / length * sin(theta)
return dtheta_dt, domega_dt
def solve_pendulum(equations, initial_state, t, args):
"""Solves the pendulum ODE."""
return odeint(equations, initial_state, t, args=args)
def calculate_trajectory(track, length):
"""Calculates the x and y coordinates of the pendulum bob."""
x_data = length * np.sin(track[:, 0])
y_data = -length * np.cos(track[:, 0])
return x_data, y_data
def initialize_animation():
"""Initializes the animation plot."""
for ax in axes:
ax.set_xlim(-1.5 * LENGTH, 1.5 * LENGTH)
ax.set_ylim(-1.5 * LENGTH, 1.5 * LENGTH)
ax.grid()
time_text_no_damping.set_text('')
time_text_damping.set_text('')
return lines + time_texts
def update_animation(frame):
"""Updates the animation for each frame."""
lines[0].set_data([0, x_data_no_damping[frame]], [0, y_data_no_damping[frame]])
lines[1].set_data([0, x_data_damping[frame]], [0, y_data_damping[frame]])
time_text_no_damping.set_text(f'time = {frame * 0.1:.1f}s')
time_text_damping.set_text(f'time = {frame * 0.1:.1f}s')
return lines + time_texts
# Time array
t = np.arange(0, 20, 0.1)
# Initial state (theta, omega)
initial_state = (1.0, 0)
# Solve ODE for pendulum with and without damping
track_no_damping = solve_pendulum(pendulum_equations_no_damping, initial_state, t, args=(LENGTH,))
track_damping = solve_pendulum(pendulum_equations_damping, initial_state, t, args=(LENGTH, DAMPING_COEFFICIENT))
# Calculate trajectory
x_data_no_damping, y_data_no_damping = calculate_trajectory(track_no_damping, LENGTH)
x_data_damping, y_data_damping = calculate_trajectory(track_damping, LENGTH)
# Create plot
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
lines = [axes[0].plot([], [], 'o-', lw=2, color='blue')[0],
axes[1].plot([], [], 'o-', lw=2, color='green')[0]]
time_template = 'time = %.1fs'
time_text_no_damping = axes[0].text(0.05, 0.9, '', transform=axes[0].transAxes)
time_text_damping = axes[1].text(0.05, 0.9, '', transform=axes[1].transAxes)
time_texts = [time_text_no_damping, time_text_damping]
# Add titles
axes[0].set_title('Pendulum without Damping')
axes[1].set_title('Pendulum with Damping')
# Create animation
ani = animation.FuncAnimation(
fig, update_animation, frames=len(x_data_no_damping), init_func=initialize_animation, interval=50
)
# Save animation
ani.save('double_pendulum.gif', writer='imagemagick', fps=100)
plt.show()