聊一个比较硬核但跑通之后非常有成就感的玩法用四阶龙格库塔法Runge-Kutta methods手写求解常微分方程再把RK4的迭代式拿到MATLAB里绘制非线性系统的分叉混沌图。这个组合在非线性动力学、振动分析、混沌理论研究里非常常见也是很多课程项目和论文复现绕不开的一关。我最早接触它是在复现某篇驱动振子论文的时候当时对着network上下的分叉图一脸懵明明就是一堆点怎么就能看出周期倍增和混沌后来自己把整套流程走了一遍才发现真正卡人的不是算法本身而是从“数学公式”到“能出图的代码”中间那些没人明说的细节。很多人第一次看到这个需求时会有两个直觉反应第一MATLAB不是有ode45吗为什么还要自己写四阶龙格库塔第二分叉混沌图到底是怎么从一串数值解里画出来的这篇文章把整条链路拆开来讲从方程怎么写成状态空间、RK4公式怎么在循环里迭代到参数扫描怎么组织、图上每个参数点对应的那一列点到底怎么提取都会详细过一遍。适合刚学完数值分析、想拿非线性动力学做课程设计的本科生也适合需要复现文献分叉图的研一新生以及所有想搞清楚“混沌图背后到底在算什么”的人。1. 这个标题到底在解决什么问题1.1 一条很硬核的技术链这个标题可以拆成三个环节常微分方程求解、RK4迭代式实现、分叉混沌图绘制。三个环节一环扣一环先写出目标系统的常微分方程再用四阶龙格库塔法把方程在时间轴上数值推进最后把推进得到的大量状态数据按参数整理画成分叉混沌图。为什么要手写RK4而不是直接用现成求解器我后面会细说。这里想先强调一个容易被忽略的点画分叉混沌图本质上不是“解一个方程”而是“解成千上万个方程”。因为分叉图的横轴是某个系统参数比如驱动力幅值、阻尼系数、瑞利数纵轴是系统到达稳态后的状态特征比如位移极值、速度极值、某个变量的采样值。你要在横轴上取几百个参数值对每一个参数值都做一次完整的长时间数值积分然后从积分结果里提取稳态特征。也就是说一次分叉图绘制背后可能是几百次乃至上千次常微分方程求解。这时候“能不能画出来”的关键就变成了你的积分器是否足够稳定、足够快、足够可控。这也是为什么这个话题值得单独拿出来写一篇。它把数值分析里最基础的RK4方法和非线性动力学里最直观的分叉混沌可视化方法串在了一起中间还夹着大量工程实现的取舍。1.2 为什么首选四阶龙格库塔而不是ode45答案很实在为了可控。ode45本质上是带自适应步长的Runge-Kutta-Fehlberg方法精度确实高但在分叉图这种场景下有个很麻烦的问题——自适应步长在混沌区会变得非常“神经质”。系统处于混沌状态时轨迹对误差极其敏感ode45会在某些时刻把步长压得特别小导致计算量剧增而当你为了追求速度手动限制步长上限时它又可能跳过一些瞬态细节产生伪分叉。四阶龙格库塔法是完全固定步长的。它的优点是每一步的计算模式完全一致循环结构极其规整你只需要找一个足够小的dt让数值误差被压在可控范围内剩下的事情就是机械地迭代。固定步长带来的另一个好处是结果可复现。不管在谁的电脑上跑只要参数和步长一致得到的序列就是完全一致的。这对做分叉图这种对确定性要求很高的任务来说非常关键——混沌系统本来就有“蝴蝶效应”如果积分器本身还带有不确定的自适应步长策略你会很难判断观察到的差异到底是物理本质还是数值误差。当然固定步长需要你自己定dt这就带来一个“步长怎么选”的问题。我一般会在第3节单独讲因为这里面的经验判断远比公式本身重要。1.3 分叉图和混沌图先搞清楚在看什么先纠正一个术语上的小细节中文教材里更多写“分岔图”标题写成“分叉”也完全不影响理解英文统一是bifurcation diagram。所谓分叉指的是系统参数连续变化时系统长期行为吸引子在某个临界点发生定性改变的现象。最常见的类型就是周期倍增分叉系统从周期1变成周期2再变成周期4之后进入混沌。而分叉混沌图就是把这种转变用图形直观展示出来。横轴是分叉参数纵轴是稳态特征量。当系统是周期运动时纵轴上只会有有限个离散点——周期1一个点周期2两个点当系统进入混沌后纵轴上会变成一大片密集的点带看起来像一团“雾”。这种“点带”正是混沌最直观的可视化证据。所以图名里的“混沌”两个字不是额外加的它指的就是图中那些成片的、看似杂乱但又有内部结构的点云。理解了这一点你再看任何一张分叉混沌图都不会觉得它神秘了它不过是一大批不同参数下的积分结果被抽取出稳态特征后按参数值排开、画在同一张图上而已。2. 第一步把工程问题写成状态方程组2.1 用Duffing方程做主线案例画分叉图需要一个经典非线性系统。我选Duffing方程原因很简单它形式简洁、物理背景明确非线性弹簧振子而且是混沌文献里被研究得最透彻的系统之一。Duffing方程的标准形式是x δ x - x x³ γ cos(ω t)其中δ是阻尼系数γ是驱动力幅值ω是驱动角频率x是位移x是速度x是加速度。这个系统里有一项-x x³对应的势函数V(x) -x²/2 x⁴/4是一个双阱势——正是这个双阱结构让系统在周期激励下可以出现大幅振荡、倍周期分叉和混沌。用这个方程画分叉图时最常见的做法是固定δ和ω让驱动力幅值γ作为分叉参数从某个小值逐渐增大。随着γ增大振子的响应会经历周期1 → 周期2 → 周期4 → 混沌这样的经典路线偶尔还会出现周期窗口。这个“参数增加但行为突变”的过程就是分叉画出来就是分叉图。2.2 二阶方程降阶为一阶方程组RK4是求解一阶常微分方程组的方法所以第一步必须把二阶Duffing方程改写成一阶状态方程组。做法在数值分析里叫降阶引入状态变量y1 xy2 x原方程变成y1 y2 y2 γ cos(ω t) - δ y2 y1 - y1³这是一个二维一阶常微分方程组完全符合RK4的适用范围。写成向量形式就是y f(t, y)其中f是一个输入时间t、状态向量y输出导数向量的函数。后面所有MATLAB代码都基于这个状态空间形式。这个“降阶”步骤不仅适用于Duffing方程也适用于所有高阶常微分方程和大部分力学系统。很多新手一开始直接拿二阶方程去套数值方法发现套不进去就是因为少了这一步。我自己的习惯是所有物理系统拿到手第一件事就是列状态变量、写状态方程然后再想数值解法。2.3 参数设置与初值选择复现分叉图的时候参数和初值的选择直接决定结果长什么样。Duffing方程常用的参数组合是δ 0.3ω 1.2γ扫描范围取0.10到0.80。这套参数下系统在γ较小时是单周期响应随着γ增大出现倍周期分叉进入混沌区并且会在某些γ区间出现周期窗口图像层次非常丰富。初值一般不需要太讲究因为分叉图关注的是稳态行为前面一段暂态会被丢弃。但有一点要注意初值不要取在奇点上。比如双阱势系统如果你把初值x0取得特别大系统可能一直在某个阱里振荡导致你只看到一半的吸引子。稳妥的做法是取x(0) 0.01、v(0) 0这种靠近零的小扰动初值让系统自行演化进入吸引子。如果画出来的图不对称或者和你预期的结构不一致可以先检查初值是不是恰好落在了某种特殊轨道上。3. RK4迭代式的推导与MATLAB落地3.1 四阶龙格库塔公式拆开看四阶龙格库塔法的迭代式是数值分析教材里的经典内容但很多人背过公式却不知道每一步在干嘛。它本质上是“多次试探斜率、加权平均进行推进”的策略。给定当前状态yn和时间tn以及步长h下一步状态yn1按下式计算k1 f(tn, yn); k2 f(tn h/2, yn h/2 * k1); k3 f(tn h/2, yn h/2 * k2); k4 f(tn h, yn h * k3); yn1 yn h/6 * (k1 2*k2 2*k3 k4);其中k1是起点斜率k2和k3是区间中点处的两个不同试探斜率k4是终点试探斜率。最终的增量是这四个斜率的加权平均权重分别是1/6、2/6、2/6、1/6。之所以要折腾四个斜率是为了把局部截断误差压到O(h⁵)全局误差达到O(h⁴)——这就是“四阶”这个名字的来历。类比一下如果你在开车想知道从A点开到B点大概需要多久只问起点一个路人一阶欧拉法显然不准。四阶龙格库塔相当于问了四个路人起点、中点的两个不同位置、终点然后按信任度加权。这样得到的估计比单一斜率可靠得多。3.2 步长怎么取直接给经验值固定步长RK4的步长选择是画分叉图时最重要的调参项之一。步长太大数值误差会伪造出虚假混沌步长太小计算时间成倍增长。对于Duffing这种带周期激励的系统我的经验是一个驱动周期内至少采样50个点推荐128个点。为什么是128驱动角频率ω 1.2时驱动周期T 2π/ω ≈ 5.236。取每个周期128步相当于dt ≈ 0.041。这个步长尺度下RK4对Duffing方程的数值耗散已经小到不会影响分叉结构同时计算速度仍可接受。如果取dt 0.01每个周期要500多步精度确实更高但600个参数点画下来计算时间会变成原来的4倍对最终图形几乎无可见改善。判断步长是否合适的通用方法很简单把步长减半再跑一次如果分叉图画出来几乎不变说明步长已经收敛如果图形结构大变说明原步长不够小。这个“缩半步长对比法”适用于任何系统的任何分叉图是我反复使用且最有效的验证手段。3.3 手写一个通用myRK4函数在MATLAB里实现RK4迭代式非常直接。我一般维护一个通用的myRK4函数接受微分方程函数句柄、时间区间、初值和总步数返回时间序列和状态轨迹function [t, Y] myRK4(f, tspan, y0, N) t0 tspan(1); tf tspan(2); h (tf - t0) / N; t linspace(t0, tf, N1); Y zeros(N1, length(y0)); Y(1, :) y0(:); for n 1:N tn t(n); yn Y(n, :); k1 f(tn, yn); k2 f(tn h/2, yn h/2 * k1); k3 f(tn h/2, yn h/2 * k2); k4 f(tn h, yn h * k3); Y(n1, :) (yn h/6 * (k1 2*k2 2*k3 k4)); end end这个函数里有两个不起眼但很关键的地方。一是f(tn, yn)返回的必须是列向量因为后面k1、k2、k3、k4都要参与向量加法二是Y按行存放状态所以每一行是系统在某个时刻的完整状态向量。这样设计的好处是求解二维系统、三维系统乃至更高维系统时这个myRK4函数本身一行都不用改。3.4 怎么验证迭代式没写错写完之后先别急着画分叉图必须验证积分器本身正确。最简单的验证方式是把你手写的myRK4和MATLAB自带的ode45在相同参数下对比。对Duffing方程取固定参数γ 0.2用myRK4积分20秒用ode45积分同样时间然后对比末时刻的状态值。两者的差值应该在10⁻⁴量级甚至更小。第二个验证方式是能量检查。对保守系统或弱阻尼系统系统的总能量随时间变化应该符合物理预期。虽然Duffing是被驱动系统能量非守恒但你可以先拿一个无驱动项的版本测试令γ 0系统应该逐渐衰减到平衡点。如果你的积分器引入了过多数值能量可能会看到永远不衰减的振荡——那是数值假象。我踩过最深的坑是状态向量维度错误定义f的时候返回了行向量但是yn是列向量两者相加时MATLAB自动广播结果算出完全错误的值而且不会报错。强烈建议写完后先用小维度测试跑一遍确认维度匹配再上大规模参数扫描。4. 主线实战参数扫描画Duffing分叉混沌图4.1 极值提取法图上每个点怎么来的现在到了核心环节怎么从积分结果中提取分叉图上的点。Duffing方程的解x(t)是一条随时间振荡的曲线。如果系统处于周期1状态稳态下x(t)在每个周期内会有一个极大值和一个极小值你把这些极大值收集起来在图上对应γ位置处画一个点就得到分叉图里的一个点如果是周期2状态极大值交替出现两个不同的值图上就会出现两个点。具体实现方法是“速度过零检测”对每一个积分步检查速度v y2是否从正变为负。当v(n) 0且v(n1) ≤ 0时说明在这个步长区间内x到达了一个局部极大值把此时的x值记录下来即可。这个方法比直接找最大值简单而且天然适合离散数值序列。之所以只记录极大值而不记录极小值是为了图形简洁——只用极大值序列已经足以区分周期1、倍周期和混沌极小值只是镜像信息。混沌区的情况是极值点到来的间隔不再有规律每次极大值的大小也不重复于是同一个γ下你会收集到大量不同的极值点画出来就是一片密集点带。分叉混沌图上的“雾区”就是这样产生的。4.2 完整代码从积分器到分叉图把前面几节的内容组合起来就是一套完整的Duffing分叉混沌图绘制代码。我把它整理成一个可复制运行的脚本clear; clc; close all; delta 0.3; omega 1.2; gamma_list linspace(0.10, 0.80, 600); % 分叉参数扫描范围 T 2*pi / omega; % 驱动周期 N_period 128; % 每个驱动周期的步数 dt T / N_period; N_warm 100; % 丢弃的暂态周期数 N_keep 150; % 用于提取极值的稳态周期数 total_steps (N_warm N_keep) * N_period; extreme_all cell(length(gamma_list), 1); for idx 1:length(gamma_list) g gamma_list(idx); f (t, y) [y(2); ... -delta*y(2) y(1) - y(1)^3 g*cos(omega*t)]; [~, Y] myRK4(f, [0, total_steps*dt], [0.01; 0], total_steps); x Y(:, 1); v Y(:, 2); % 丢掉暂态 start_idx N_warm * N_period 1; x x(start_idx:end); v v(start_idx:end); % 速度由正转负处即局部极大值 idx_ext find(v(1:end-1) 0 v(2:end) 0); extreme_all{idx} x(idx_ext); end figure(Color, w, Position, [100 100 900 600]); hold on; for idx 1:length(gamma_list) g gamma_list(idx); if ~isempty(extreme_all{idx}) plot(g * ones(size(extreme_all{idx})), extreme_all{idx}, ... ., MarkerSize, 3, Color, [0.1 0.2 0.8]); end end xlabel(驱动力幅值 \gamma); ylabel(稳态位移极大值 x_{max}); title(Duffing方程分叉混沌图RK4); xlim([gamma_list(1), gamma_list(end)]); box on; grid on;这段代码里有几个细节值得说明。Gamma_list用linspace取600个点是分辨率和计算量的折中600个参数下每个参数都要积分250个周期、每周期128步总步数是1920万步。这个规模在普通笔记本上跑大约几分钟属于可以接受的范围。如果你只是想先看看图的大致结构可以先把600改成200确认没问题再跑全分辨率。4.3 结果怎么看倍周期、混沌与周期窗口代码跑完后你会看到一幅非常典型的分叉混沌图。从左往右γ较小时图上只有一个点表示系统做周期1运动随着γ增大某个临界点处一个点突然变成两个点这是第一次倍周期分叉接着两个点变成四个点是第二次再往后点带迅速“糊”成一片连续区间系统进入混沌。继续向右你还会看到混沌区里偶尔“裂开”出一些干净的窗口比如γ在某段区间内重新变成少量离散点。这些周期性窗口是非线性系统中最迷人的现象之一——系统在混沌中突然恢复规律然后再次进入混沌。如果你见过一些著名分叉图里“混沌雾中镶嵌着三条细线”的图案那就是周期窗口的典型样子。我第一次画出这张图的时候非常震撼一个看似简单的二阶方程仅仅改变一个驱动幅值参数就能在图上演化出如此复杂的结构。而且整个过程完全用自己手写的RK4迭代式完成没有调用任何现成的求解器这种“从零搭起整条链路”的掌控感是直接用ode45画图完全体会不到。4.4 参数换一换图形就会变Duffing分叉图对参数的依赖非常敏感这也是它的魅力所在。你可以固定γ把扫描对象换成阻尼δ或者驱动频率ω图形结构会发生戏剧性变化。我建议初学者在跑通标准案例后至少再尝试一次改变扫描参数比如固定γ 0.4、扫描ω从0.8到1.6你会发现完全不同的分叉结构——这能帮你理解“分叉参数选择”在非线性研究中的意义。这里给出一个实用建议如果画出的图没有任何“分叉结构”而只有一条单调曲线大概率不是系统没问题而是扫描范围没选对。分叉图的价值在于参数跨过临界点时行为突变如果你的参数范围完全避开临界点图就会非常无聊。先花点时间用几个单参数算例摸清系统的行为区间再确定扫描范围比一上来就全范围扫描高效得多。5. 扩展案例Lorenz系统分叉图5.1 从二维系统到三维混沌系统Duffing方程画完你对整个流程已经有感觉了。如果只停留在二维系统其实有点可惜因为更高维系统能画出更复杂的分叉图。这里推荐一个经典三维案例Lorenz系统它也是混沌学史上最具代表性的方程之一。Lorenz系统的方程为x σ(y - x) y x(ρ - z) - y z xy - βz其中σ、ρ、β是参数。经典的参数是σ 10、β 8/3让ρ作为分叉参数进行扫描。Lorenz系统在ρ 24.74左右时收敛到固定点或周期轨道超过这个值后逐渐进入混沌是一个非常理想的扫描案例。三维系统画分叉图时提取特征量的方式和二维略有不同。Duffing方程可以直接取位移极大值Lorenz系统更常用的做法是取x变量的局部极大值序列——即检测x从上升转为下降的那一刻记录对应的x值。这样得到的序列同样能区分周期状态和混沌状态。5.2 Lorenz系统RK4迭代的MATLAB实现Lorenz系统是自治系统方程右侧不显含时间t所以实现上比Duffing还要简单一点。关键代码是定义右侧函数和单步RK4迭代function dydt lorenz_rhs(y, sigma, rho, beta) dydt [sigma*(y(2) - y(1)); y(1)*(rho - y(3)) - y(2); y(1)*y(2) - beta*y(3)]; end function y_next stepRK4(f, t, y, h) k1 f(t, y); k2 f(t h/2, y h/2 * k1); k3 f(t h/2, y h/2 * k2); k4 f(t h, y h * k3); y_next y h/6 * (k1 2*k2 2*k3 k4); end主脚本按如下逻辑组织对每个ρ值从初值出发先用若干步积分丢掉暂态然后继续积分并在每一步检查x方向变化率符号记录局部极大值。步长取dt 0.01即可因为Lorenz系统的特征时间尺度比Duffing快得多0.01是经过验证的安全值。完整代码框架如下clear; clc; close all; sigma 10; beta 8/3; rho_list 1:0.5:350; dt 0.01; warm_steps 3000; % 丢弃的暂态步数 record_steps 60000; % 提取极值的步数 xmax_all cell(length(rho_list), 1); for i 1:length(rho_list) rho rho_list(i); y [1; 1; 1]; x_old y(1); vx_old 0; maxima []; for k 1:warm_steps record_steps y stepRK4((t, y) lorenz_rhs(y, sigma, rho, beta), 0, y, dt); x_now y(1); vx_now (x_now - x_old) / dt; if k warm_steps vx_old 0 vx_now 0 maxima(end1) x_now; end x_old x_now; vx_old vx_now; end xmax_all{i} maxima; end figure(Color, w, Position, [100 100 900 600]); hold on; for i 1:length(rho_list) if ~isempty(xmax_all{i}) plot(rho_list(i) * ones(size(xmax_all{i})), xmax_all{i}, ... ., MarkerSize, 2, Color, [0.8 0.2 0.1]); end end xlabel(参数 \rho); ylabel(x 的局部极大值); title(Lorenz系统分叉混沌图RK4); xlim([rho_list(1), rho_list(end)]); box on; grid on;这段代码在往数组里追加元素时用了maxima(end1) x_now这在小规模时没问题但记录步数较多时会影响效率。如果你需要大幅提速可以预先分配一个较大数组或者用计数指针记录写入位置。跑Lorenz扫描时建议先用rho_list 1:5:350的低分辨率版本确认整体结构和运行时间再加密到0.5甚至0.1的间隔。5.3 Lorenz分叉图的特征跑出来的Lorenz分叉图有一个非常明显的结构ρ较小的时候图上只有一条水平线或少量点对应系统的稳定固定点在某个临界ρ附近图开始“分叉”出一条主曲线随后逐渐演变成点带对应混沌吸引子的出现。这个点带中间还会出现若干“空洞”和密集区对应混沌吸引子内部结构的变化。如果你拿这张图和文献里常见的Lorenz分叉图对比会发现主流文献更多画的是Poincaré截面而不是局部极大值序列两者不完全等价但整体结构非常相似。局部极大值法的优势是实现简单、不需要额外处理截面条件对初学者友好。当你想和文献严格对比时再改用Poincaré截面即可。顺带一提Lorenz系统的初值敏感性是出了名的。两个差10⁻⁸的初值在几十步之后就会完全分道扬镳所以画Lorenz分叉图时不要对“精确复现某特定轨迹”抱期望你要观察的是统计特征和整体结构——分叉图恰恰就是这种“通过大量轨迹点的分布来看系统长期行为”的典型工具。6. 常见问题速查与避坑技巧实录6.1 图上全是噪点没有清晰结构怎么办最常见的“噪点”问题是步长不够小导致的伪混沌。如果你的图在任何参数下都显得非常毛糙甚至γ很小时就出现大范围散点第一步先把每周期步数从128提到256或512重新跑一次。如果图形结构突然变清晰说明原步长不满足精度要求。第二个原因是暂态没有丢干净。系统在较大参数下可能需要很长的过渡时间才能落到吸引子上如果你只丢了50个周期后面的采样点里还混着暂态数据那图上就会多出一堆“过渡噪声”。解决办法是把N_warm提到200甚至400。这一点最容易忽略因为暂态完全看不出错误——所有点都是真实的数值解只是还没收敛到稳态而已。第三个原因是极值检测条件过于宽松。当v刚好在某个步长间从正值变成负值时如果采样点刻意避开了精确过零点检测到的x值会有微小偏差。对绝大部分分叉图来说这个偏差可以忽略但如果你画的是高精度局部放大图建议做一步线性插值在过零区间内插出更精确的极值位置。6.2 分叉临界点和文献对不上复现论文分叉图时经常遇到这种情况图的大体形状对但分叉点位置偏移了。偏移来源通常是参数定义差异。同一个Duffing方程有人写成x δx - x x³ γcos(ωt)有人写成x 2ζx - x x³ f cos(ωt)还有人在方程两边同时除以质量项——这些写法看起来差不多但实际参数值差了一倍甚至更多。我的建议是对比文献之前先把参数定义完全对齐尤其是阻尼项、驱动力项前面的系数。还有一种可能是有量纲方程和归一化方程的区别文献中常先把方程无量纲化再扫描如果你直接用原始物理参数分叉范围可能整体平移或缩放。遇到图样相似但临界点对不上的情况先回看方程形式别急着怀疑代码。我自己就吃过这个亏对着某篇论文调了一整天最后发现只是对方的阻尼系数是δ/2。6.3 出现NaN、Inf或程序闪退NaN和Inf在分叉图绘制中出现时基本可以锁定两个原因。一是步长过大导致RK4推进过程中状态值发散到天文数字。混沌系统的轨迹在数值上可能会在一段时间后出现溢出如果你用的是长积分时间建议先检查中间轨迹的最大绝对值确认状态量还在合理范围内。二是右端函数里有奇点某些参数组合下y1³这项可能变得极大导致溢出。处理方式有三层优先减小步长其次给状态量加上约束如果绝对值超过某个阈值就提前终止该参数点的积分最后在扫描循环外面包一层try-catch让个别参数点出错时不影响整体扫描。这里强调一下出现NaN时不要简单地“跳过这个参数点”因为这说明该参数附近很可能有某种导致数值不稳定的真实动力学行为——你可以先小步长重试该点如果依然发散再在图上标注为“无收敛解”而不是默默剔掉。6.4 计算太慢怎么优化扫描速度分叉图绘制的计算量确实随参数点数线性增长所以慢是常态。但有几个优化手段立竿见影。第一先跑低分辨率。600个参数点变成150个图形轮廓已经能看出来确认结构和预期一致后再跑全分辨率。第二用预分配替代动态追加尤其是在Lorenz这种记录海量极值的场景。第三MATLAB的parfor并行循环在参数扫描中效果极好因为每个参数点之间完全独立没有数据依赖。把脚本里的for改成parfor之前需要先开启并行池并且确保myRK4这类函数能被所有工作进程访问。第四点比较少人提把“每个参数点都重新初始化积分”变成“持续跟踪吸引子”。具体做法是用上一个参数点的最终状态作为下一个参数点的初值这样系统会沿着吸引子连续演化暂态时间可以大幅缩短。这种技术叫连续参数追踪既能提速又让分叉图更有连续性。不过它也有代价如果你初始选择了不同的吸引子分支追踪会一直停留在这个分支上可能错过其他共存吸引子。所以它适合作为复现时的提速手段不适合作为发现新结构的首选方法。踩过几次坑之后我最大的体会是画分叉混沌图80%的功夫其实花在“判断结果是否可信”上只有20%花在写代码。RK4的公式十分钟就能抄下来但搞清楚步长怎么选、暂态怎么去、参数区间怎么定、出图以后怎么解读才是这项技能真正的门槛。当你绕着这些坑走完一遍再回头看任何一张分叉混沌图都能一眼看出它背后大概经历了怎样的计算过程——这感觉比跑通代码本身还值。如果你第一次跑出来的图不理想别急着怀疑自己的代码按上面的检查清单一项项排查大概率很快就能找到问题所在。
阅读完成 · 觉得有帮助?