matlab求解二阶微分代数方程组

求解二阶微分代数方程组(DAE)是多体动力学、电路仿真、化学反应器等领域的核心问题。MATLAB 最标准、最稳定的解法是利用 ode15sode23t 配合 质量矩阵(Mass Matrix)。


一、二阶微分代数方程组的标准形式

一般形式为:

M(t,q)q¨+C(t,q,q˙)q˙+K(t,q)=Q(t,q,q˙)+GTλ\mathbf{M}(t,\mathbf{q})\ddot{\mathbf{q}} + \mathbf{C}(t,\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}} + \mathbf{K}(t,\mathbf{q}) = \mathbf{Q}(t,\mathbf{q},\dot{\mathbf{q}}) + \mathbf{G}^T\boldsymbol{\lambda}M(t,q)q¨+C(t,q,q˙)q˙+K(t,q)=Q(t,q,q˙)+GTλ


二、典型案例:平面双摆(带代数约束)

物理模型

两个质点通过无质量杆连接,受重力作用。

  • 坐标:(x_1, y_1, x_2, y_2)
  • 约束:杆长不变(2 个代数方程)

约束方程

{x12+y12=L12(x2−x1)2+(y2−y1)2=L22\begin{cases} x_1^2 + y_1^2 = L_1^2 \\ (x_2-x_1)^2 + (y_2-y_1)^2 = L_2^2 \end{cases}{x12+y12=L12(x2−x1)2+(y2−y1)2=L22


三、MATLAB 求解源码

1、主脚本:double_pendulum_dae.m

matlab 复制代码
%% Double Pendulum with DAE (Index-3)
clear; clc; close all;

% 参数
L1 = 1; L2 = 1;
m1 = 1; m2 = 1;
g  = 9.81;

% 初始条件
q0 = [L1*sin(pi/6);      % x1
     -L1*cos(pi/6);      % y1
      L1*sin(pi/6)+L2*sin(pi/4); % x2
     -L1*cos(pi/6)-L2*cos(pi/4)]; % y2

dq0 = zeros(4,1); % 初始速度为0

% 拉格朗日乘子初值(猜测)
lambda0 = [0; 0];

% 完整状态向量: [q; dq; lambda]
y0 = [q0; dq0; lambda0];

% 时间跨度
tspan = [0 20];

% 质量矩阵
M = diag([m1 m1 m2 m2 0 0]);

% 选项设置(关键!)
options = odeset(...
    'Mass', M, ...
    'RelTol', 1e-8, ...
    'AbsTol', 1e-10, ...
    'Jacobian', @dae_jacobian, ...
    'Events', @events); % 可选:检测碰撞或奇异

% 求解 DAE
[t, y] = ode15s(@dae_equations, tspan, y0, options);

% 提取结果
x1 = y(:,1); y1 = y(:,2);
x2 = y(:,3); y2 = y(:,4);

%% 动画
figure('Color','white')
for k = 1:5:length(t)
    clf
    plot([0, x1(k)], [0, y1(k)], 'b-o', 'LineWidth', 2)
    hold on
    plot([x1(k), x2(k)], [y1(k), y2(k)], 'r-o', 'LineWidth', 2)
    axis equal
    axis([-3 3 -3 1])
    title(['Time = ', num2str(t(k), '%.2f'), ' s'])
    grid on
    drawnow
end

2、微分方程函数:dae_equations.m

matlab 复制代码
function dy = dae_equations(~, y)
% 状态变量分解
q  = y(1:4);   % 位置
dq = y(5:8);   % 速度
la = y(9:10);  % 拉格朗日乘子

% 解包坐标
x1 = q(1); y1 = q(2);
x2 = q(3); y2 = q(4);

% 约束方程梯度 (Jacobian of g)
Jg = [2*x1, 2*y1, 0, 0;
     -2*(x2-x1), -2*(y2-y1), 2*(x2-x1), 2*(y2-y1)];

% 加速度方程 (M*dq2 = F + Jg'*la)
% 力向量 (重力)
F = [0; -m1*g; 0; -m2*g];

% 加速度
ddq = [F; 0; 0] + Jg' * la;

% 约束二阶导数 (用于稳定性,Baumgarte 稳定法)
alpha = 10; beta = 10;
g_q = [x1^2 + y1^2 - L1^2;
       (x2-x1)^2 + (y2-y1)^2 - L2^2];
dg_dt = Jg * dq;
ddg = dg_dt + 2*alpha*dg_dt + beta^2*g_q; % Baumgarte

% 完整导数
dy = zeros(10,1);
dy(1:4)   = dq;     % dq/dt
dy(5:8)   = ddq(1:4); % ddq/dt
dy(9:10)  = -ddg;   % 乘子动力学 (简化)
end

3、雅可比矩阵(加速收敛):dae_jacobian.m

matlab 复制代码
function J = dae_jacobian(~, y)
% 雅可比矩阵用于牛顿迭代
% 对于刚性 DAE 非常重要

% 这里返回一个稀疏近似或直接用 finite-difference
% 实际工程中建议解析推导
J = sparse(10,10);
% 对角块 (速度-位置关系)
J(1:4,5:8) = eye(4);
% 其余部分由 ode15s 自动差分通常足够
end

四、替代方案:降阶为一阶 ODE

如果你的方程来自机械系统(Simscape/ADAMS 风格),可以手动降阶:

通用模板(无约束系统)

matlab 复制代码
%% 通用二阶 ODE -> 一阶系统
% 原方程: M*qdd + C*qd + K*q = F
% 令: y = [q; qd]

function dydt = second_order_ode(t, y, M, C, K, F_fun)
    n = length(y)/2;
    q  = y(1:n);
    qd = y(n+1:end);
    
    F = F_fun(t, q, qd);
    qdd = M \ (F - C*qd - K*q);
    
    dydt = [qd; qdd];
end

%% 调用
M = eye(2); C = 0.1*eye(2); K = eye(2);
F_fun = @(t,q,qd) [sin(t); 0];

[t, y] = ode45(@(t,y) second_order_ode(t,y,M,C,K,F_fun), [0 10], [1;0;0;0]);

参考代码 求解二阶微分代数方程组源代码 www.youwenfan.com/contentcsw/82516.html

如果是控制系统或复杂机械 ,强烈建议用 Simulink + Simscape Multibody

  1. 建立物理模型(刚体、铰链、弹簧)
  2. 自动生成 DAE
  3. 使用 Simscape Solver(自动处理 Index Reduction)

六、常见错误与解决方案

错误现象 原因 解决方法
Unable to meet integration tolerances 约束违反严重 使用 Baumgarte 稳定法投影法
结果发散 DAE 索引过高 (Index-3) 降阶为 Index-1 或使用 ode15s
代数变量震荡 初始条件不一致 先解 一致性初始化 (Consistent Initialization)
速度太慢 刚性系统 使用 ode23t (梯形法) 或 稀疏 Jacobian