如何在scipy.integrate.solve_ivp中传入矩阵求解多自由度振动方程?
多自由度弹簧-质量-阻尼系统通用求解方案(基于scipy.solve_ivp)
scipy.integrate.solve_ivp本身没有内置直接传入质量、刚度、阻尼矩阵的参数,但你可以通过编写通用的一阶方程右函数实现和Matlab ode45相同的效果,无需逐行编写每个一阶方程,适配任意自由度的系统,具体实现逻辑如下:
核心原理
n自由度弹簧-质量-阻尼系统的控制方程为通用形式:
$$ M \ddot{x} + C \dot{x} + K x = F(t) $$
其中:
- $M$ 为n×n质量矩阵
- $C$ 为n×n阻尼矩阵
- $K$ 为n×n刚度矩阵
- $x$ 为n×1位移向量,$\dot{x}$ 为速度向量,$\ddot{x}$ 为加速度向量
- $F(t)$ 为n×1时变外力向量
转换为一阶状态方程时,定义2n维状态向量 $y = \begin{bmatrix} x \ \dot{x} \end{bmatrix}$,则一阶导数可统一写为:
$$ \dot{y} = \begin{bmatrix} \dot{x} \ \ddot{x} \end{bmatrix} = \begin{bmatrix} y[n:] \ M^{-1} \cdot (F(t) - C \cdot y[n:] - K \cdot y[:n]) \end{bmatrix} $$
该公式对任意n值均成立,不需要针对不同自由度修改逻辑。
通用代码实现
你只需要提前定义好对应维度的M、C、K矩阵和外力函数F(t),不需要逐行编写每个一阶方程,以下是适配你2DOF示例的通用版本代码,直接替换M/C/K和F(t)的定义即可适配30自由度甚至更高维度的系统:
from scipy.integrate import solve_ivp import numpy as np import matplotlib.pyplot as plt # -------------------------- 仅需修改以下参数即可适配不同自由度系统 -------------------------- # 系统参数(以2DOF为例,30自由度则对应生成30×30的M/C/K矩阵即可) n = 2 # 自由度数量 M = np.diag([3, 5]) # 质量矩阵 C = np.array([ [1+2, -2], [-2, 2] ]) # 阻尼矩阵 K = np.array([ [7+9, -9], [-9, 9] ]) # 刚度矩阵 # 时变外力函数,输入t返回n维外力向量 def external_force(t): f1 = 40 * np.cos(3*t) f2 = 4 * np.sin(t**2) return np.array([f1, f2]) # 求解配置 start_time = 0 end_time = 60 delta_t = 0.1 # 初始条件:前n个为各质量初始位移,后n个为各质量初始速度 initial_conditions = np.array([6, 9, 0, 4]) # ---------------------------------------------------------------------------------------- # 通用右函数,任意n自由度均不需要修改 def F(t, y): dy_dt = np.zeros(2*n) # 前n维为位移的导数(即速度) dy_dt[:n] = y[n:] # 后n维为速度的导数(即加速度),用solve替代inv计算更稳定 dy_dt[n:] = np.linalg.solve(M, external_force(t) - C @ y[n:] - K @ y[:n]) return dy_dt # 求解 time_interval = [start_time, end_time] sol = solve_ivp(F, time_interval, initial_conditions, max_step=delta_t) T = sol.t Y = sol.y
注意事项
- 30自由度对应的状态向量仅60维,属于极小规模的ODE问题,numpy的矩阵运算效率远高于手动逐行写方程,无需担心性能问题
- 针对更大规模的系统,如果M为稀疏矩阵,可以替换
np.linalg.solve为scipy.sparse.linalg.spsolve进一步提升计算效率 - 该写法和Matlab中传入矩阵给ode45的逻辑完全一致,仅需要提前组装好对应维度的矩阵即可
内容的提问来源于stack exchange,提问作者user15014634
相关产品推荐
相关产品推荐

