微分代数方程式の解析と操作
この例では、Symbolic Math Toolbox™ を使用して微分指数の高い微分代数方程式 (DAE) を求解する方法を説明します。
エンジニアは多くの場合、物体 (機械システム、電子機器など) の振る舞いを微分方程式と代数方程式の組み合わせで指定します。MATLAB® では、このような DAE を積分できる ode15i や ode15s などの特別な数値ソルバーが提供されています (それらの微分指数が 1 を上回らない場合に限る)。 
この例では、代数制約をもつ連立微分方程式としてモデルをセットアップするところから、数値シミュレーションを行うまでのワークフローを説明します。以下の Symbolic Math Toolbox 関数を使用します。
daeFunctionfindDecoupledBlocksincidenceMatrixisOfLowDAEIndexreduceDifferentialOrdermassMatrixFormreduceDAEIndexreduceDAEToODEreduceRedundanciessym/decic
モデルのパラメーターの定義
2 次元の実体振子について考えます。この振子は一定の長さ r の紐で原点に取り付けられた重り m で構成されています。重りに作用するのは重力加速度 g = 9.81 m/s^2 のみです。このモデルは、重りの位置 (x(t), y(t)) と重りを円上に留めている紐の力 F(t) から成る 2 階微分方程式で構成されます。力は紐に沿って掛かっています。
syms x(t) y(t) F(t) m g r eqs = [m*diff(x(t),t,t) == F(t)/r*x(t); m*diff(y(t),t,t) == F(t)/r*y(t) - m*g; x(t)^2 + y(t)^2 == r^2]
eqs =
vars = [x(t),y(t),F(t)]
vars =
この DAE 系を連立 1 階微分代数方程式に書き換えます。
[eqs,vars,newVars] = reduceDifferentialOrder(eqs,vars)
eqs =
vars =
newVars =
高指数 DAE 系を解く
ode15i などの MATLAB の数値ソルバーを使用可能にするため、以下の手順を行う必要があります。
DAE 系を MATLAB 関数ハンドルに変換する。
方程式のシンボリック パラメーターの数値を選択する。
矛盾のない初期条件を設定する。
DAE 系を MATLAB 関数ハンドルに変換するには、daeFunction を使用します。
F = daeFunction(eqs,vars,[m g r])
F = function_handle with value:
    @(t,in2,in3,in4)[in3(4,:).*in4(:,1)-(in2(3,:).*in2(1,:))./in4(:,3);in3(5,:).*in4(:,1)+in4(:,1).*in4(:,2)-(in2(3,:).*in2(2,:))./in4(:,3);-in4(:,3).^2+in2(1,:).^2+in2(2,:).^2;in2(4,:)-in3(1,:);in2(5,:)-in3(2,:)]
方程式のシンボリック パラメーターに次の数値 m = 1kg、g = 9.18m/s^2 および r = 1m を代入します。
f = @(t,y,yp) F(t,y,yp,[1 9.81 1])
f = function_handle with value:
    @(t,y,yp)F(t,y,yp,[1,9.81,1])
関数ハンドル f は数値ソルバー ode15i に適した入力です。次の手順では矛盾のない初期条件を計算します。odeset を使用して数値の許容誤差を設定します。それから、MATLAB 関数 decic を使用して、時間 t0 = 0 における位置と導関数に整合する初期条件 y0, yp0 を計算します。
opt = odeset(RelTol=1e-4,AbsTol=1e-4); t0 = 0; [y0,yp0] = decic(f,t0,[0.98;-0.21;zeros(3,1)],[],zeros(5,1),[],opt)
y0 = 5×1
    0.9777
   -0.2100
         0
         0
         0
yp0 = 5×1
         0
         0
         0
         0
   -9.8100
初期条件をテストします。
f(t0, y0, yp0)
ans = 5×1
10-16 ×
         0
         0
   -0.3469
         0
         0
これで、ode15i を使用して方程式の求解が実施できます。ode15i を呼び出すと、積分は即座に停止し、次の警告を発します。
 Warning: Matrix is singular, close to singular or badly scaled. 
 Results may be inaccurate. RCOND = NaN.
 Warning: Failure at t=0.000000e+00.
 Unable to meet integration tolerances without reducing the step 
 size below the smallest value allowed (0.000000e+00) at time t.
この例では、ode15i はこれらの警告を複数回発します。見やすくするため、ode15i を呼び出す前に warning("off","all") を使用して警告を無効にし、呼び出した後に再び有効にします。
tfinal = 0.5; s = warning("off","all"); ode15i(f,[t0,tfinal],y0,yp0,opt);

warning(s)
DAE 系の解析と調整
DAE 系の微分指数を確認します。
isLowIndexDAE(eqs,vars)
ans = logical
   0
この結果は ode15i でこの方程式が解けない理由を示しています。この関数では入力の DAE 系の微分指数が 0 または 1 である必要があります。いくつかの隠れた代数制約を含む同等のより大きな DAE 系にモデルを拡張することにより微分指数を簡約します。
[eqs,vars newVars,index] = reduceDAEIndex(eqs,vars)
eqs =
vars =
newVars =
index = 3
4 番目の出力からは元のモデルの微分指数が 3 であることが分かります。新しい方程式を単純化します。
[eqs,vars,S] = reduceRedundancies(eqs,vars)
eqs =
vars =
S = struct with fields:
      solvedEquations: [3×1 sym]
    constantVariables: [0×2 sym]
    replacedVariables: [3×2 sym]
       otherEquations: [0×1 sym]
新しい方程式の微分指数が低い (0 または 1) ことを確認します。
isLowIndexDAE(eqs,vars)
ans = logical
   1
低指数 DAE 系を解く
シンボリック パラメーターを数値で置き換える MATLAB 関数ハンドルを生成します。
F = daeFunction(eqs,vars,[m g r])
F = function_handle with value:
    @(t,in2,in3,in4)[-(in2(3,:).*in2(1,:)-in2(7,:).*in4(:,1).*in4(:,3))./in4(:,3);(-in2(3,:).*in2(2,:)+in2(6,:).*in4(:,1).*in4(:,3)+in4(:,1).*in4(:,2).*in4(:,3))./in4(:,3);-in4(:,3).^2+in2(1,:).^2+in2(2,:).^2;in2(4,:).*in2(1,:).*2.0+in2(5,:).*in2(2,:).*2.0;in2(7,:).*in2(1,:).*2.0+in2(6,:).*in2(2,:).*2.0+in2(4,:).^2.*2.0+in2(5,:).^2.*2.0;in2(6,:)-in3(5,:);in2(5,:)-in3(2,:)]
f = @(t,y,yp) F(t,y,yp,[1 9.81 1])
f = function_handle with value:
    @(t,y,yp)F(t,y,yp,[1,9.81,1])
MATLAB 関数 decic によって簡約された指数に整合する初期条件を計算します。ここで、opt は数値の許容誤差を設定するオプション構造体です。これは odeset を使用して計算済みです。
[y0,yp0] = decic(f,t0,[0.98;-0.21;zeros(5,1)],[],zeros(7,1),[],opt)
y0 = 7×1
    0.9779
   -0.2093
   -2.0528
    0.0000
         0
   -9.3804
   -2.0074
yp0 = 7×1
         0
         0
         0
         0
   -9.3804
         0
         0
方程式を解いて解をプロットします。
ode15i(f,[t0 tfinal],y0,yp0,opt)
