这篇文章中,UncleBob 对于使用数学软件进行系统相图与相曲线的绘制方法进行了小结。
相图,相曲线
设U⊂Rn+1是开集,f:U→Rn连续。
对于以下n维系统上的IVP(初值问题)
{X˙=f(t,X)X(t0)=X0
它的解φ(t):I→Rn满足
φ˙(t)=dtdφ(t)=f(t,φ(t))
且满足初值φ(t0)=X0。
设Γ是U上C1光滑的曲线,具有如下的参数化:
Γ:={(t,φ(t)):t∈I}
此时称Γ是系统X˙=f(t,X)的一条积分曲线。
更特殊地,设V⊂Rn是开集,g:V→Rd连续。
我们称系统
X˙=g(X)
是一个自治系统,V为相空间,g为向量场(相图)。
设它的解为φ(t):I→U,此时称曲线
Cφ:={φ(t):t∈I}
是一条相曲线。
单纯看定义可能有些抽象,我们在下面的实际操作观察。
Mathematica实现
系统1
考虑如下系统
X˙=JX
这里J=[λ1λ]
使用Mathematica绘制相图:
1
| Manipulate[StreamPlot[{Lambda*x + y, Lambda*y}, {x, -5, 5}, {y, -5, 5}], {Lambda, -3, 3}]
|
这里的Manipulate函数让我们能很方便的交互式操作调整λ的值观察相曲线的变化。
系统2
考虑如下系统
{x˙=sinxy˙=siny
使用Mathematica绘制相图:
1
| StreamPlot[{Sin[x], Sin[y]}, {x, -5, 5}, {y, -5, 5}]
|
系统3
考虑如下系统(Lorenz系统)
⎩⎨⎧x˙=σ(y−x)y˙=rx−y−xzz˙=xy−bz
取σ=10,b=8/3,r=28,选取初值t0=0,X0=(11,45,14),
使用Mathematica绘制相曲线:
1 2
| s = NDSolve[{x'[t] == 10 (y[t] - x[t]), y'[t] == 28*x[t] - y[t] - x[t]*z[t], z'[t] == x[t]*y[t] - 8/3*z[t],x[0] == 11, y[0] == 45, z[0] == 14}, {x, y, z}, {t, 50}] ParametricPlot3D[Evaluate[{x[t], y[t], z[t]} /. s], {t, 0, 50}, PlotRange -> Full]
|
Matlab实现
与上述系统相同。
对于第一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| lambda = -0.5; J = [lambda, 1; 0, lambda];
[x1, x2] = meshgrid(-5:0.5:5, -5:0.5:5);
dx1 = lambda*x1 + x2; dx2 = lambda*x2;
figure; quiver(x1, x2, dx1, dx2, 'b'); hold on;
title(['Phase Portrait with \lambda = ', num2str(lambda)]);
|
对于第二个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| [x, y] = meshgrid(-2*pi:0.5:2*pi, -2*pi:0.5:2*pi);
dx = sin(x); dy = sin(y);
figure; quiver(x, y, dx, dy, 'b'); hold on;
initial_conditions = [-6 -6; -4 -2; 0 0; 2 4; 6 6]; tspan = [0, 10];
for i = 1:size(initial_conditions, 1) [t, traj] = ode45(@(t, X) [sin(X(1)); sin(X(2))], tspan, initial_conditions(i, :)'); plot(traj(:,1), traj(:,2), 'r', 'LineWidth', 1.5); end
title('Phase Portrait of \dot{x} = sin(x), \dot{y} = sin(y)');
|
这里额外添加了一些典型相曲线。
对于第三个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| sigma = 10; b = 8/3; r = 28;
X0 = [11, 45, 14]; tspan = [0, 50];
lorenz = @(t, X) [ ... sigma * (X(2) - X(1)); r * X(1) - X(2) - X(1) * X(3); X(1) * X(2) - b * X(3) ];
[t, X] = ode45(lorenz, tspan, X0);
figure; plot3(X(:,1), X(:,2), X(:,3), 'b', 'LineWidth', 1.5); grid on;
xlabel('x'); ylabel('y'); zlabel('z'); title('Lorenz System Phase Curve (\sigma=10, b=8/3, r=28)'); view(3);
|
其他实现
例如对于系统1,使用python中的Matplotlib和NumPy绘制相图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import numpy as np import matplotlib.pyplot as plt from scipy.integrate import solve_ivp
lambda_val = -0.5 J = np.array([[lambda_val, 1], [0, lambda_val]])
def system(t, X): return J @ X
x1 = np.linspace(-5, 5, 20) x2 = np.linspace(-5, 5, 20) x1, x2 = np.meshgrid(x1, x2)
dx1 = lambda_val * x1 + x2 dx2 = lambda_val * x2
magnitude = np.sqrt(dx1**2 + dx2**2) dx1 /= magnitude dx2 /= magnitude
plt.figure(figsize=(8, 6)) plt.quiver(x1, x2, dx1, dx2, color='b', alpha=0.6)
initial_conditions = [[-4, -4], [-3, 3], [4, -4], [3, 3]] t_span = [0, 10]
for ic in initial_conditions: sol = solve_ivp(system, t_span, ic, t_eval=np.linspace(0, 10, 200)) plt.plot(sol.y[0], sol.y[1], 'r', linewidth=1.5)
plt.title(f'Phase Portrait with λ = {lambda_val}', fontsize=14) plt.xlabel('x₁', fontsize=12) plt.ylabel('x₂', fontsize=12) plt.axhline(0, color='black',linewidth=0.5, linestyle='--') plt.axvline(0, color='black',linewidth=0.5, linestyle='--') plt.grid(True) plt.axis('equal') plt.show()
|
这里我们进行了归一化处理(让每个向量长度一致),实际上是否归一化要看不同的场景。