1. 从一维时间序列到相空间:为什么时延和嵌入维是混沌分析的命门
做混沌时间序列分析的人,迟早会撞上同一个问题:手里只有一串按时间排列的标量数据,比如某个振动传感器的位移读数、某段心电信号的电压幅值、某只股票每天的收盘价,但你想知道的是这个系统在相空间里到底长什么样。一维序列本身看不出任何几何结构,它只是一条上下起伏的曲线,而混沌系统的所有秘密——奇怪吸引子的分形维数、Lyapunov指数的正负、系统的确定性规律——全都藏在重构出来的高维相空间里。
这就是相空间重构要解决的事。Takens在1981年给出的延迟嵌入定理告诉我们:对于一个确定性动力系统,只要嵌入维数m足够大(通常要求m ≥ 2d+1,d是吸引子的关联维数),用单一标量时间序列的延迟坐标就能构造出一个与原始动力系统微分同胚的相空间。换句话说,你不需要同时测量系统的所有状态变量,一个变量就够,前提是你把它的历史值按一定时间间隔排列成向量。
具体操作是这样的:给定时间序列{x(i), i=1,2,...,N},选定时间延迟τ和嵌入维数m,构造延迟向量:
X(i) = [x(i), x(i+τ), x(i+2τ), ..., x(i+(m-1)τ)]
其中i从1取到N-(m-1)τ。每个X(i)就是m维相空间里的一个点,所有点连起来就是重构的轨迹。Takens定理保证了这条轨迹在拓扑意义上和原始系统等价,但有一个致命的前提:τ和m必须选对。
选错了会怎样?τ太小,相邻延迟坐标几乎相同,重构轨迹被压缩在对角线附近,看起来像一条直线,吸引子的几何结构完全展不开;τ太大,相邻坐标之间已经失去相关性,轨迹变得杂乱无章,原本确定的动力学被淹没在噪声里。m太小,吸引子会在高维空间中发生自交叠,本来不相邻的点被错误地拉在一起;m太大,计算量暴增,噪声被放大,而且冗余的维度会稀释真正的动力学信息。
所以整个相空间重构的核心任务就两件事:求最优时间延迟τ和求最小嵌入维数m。这两个参数不是独立的,它们之间存在耦合关系,但工程上通常分两步走——先用自相关或互信息法确定τ,再用虚假近邻法或Cao方法确定m。下面我把这套流程的Matlab实现从头到尾拆开讲,包括每个方法的原理、代码、参数选择经验,以及我在实际数据上踩过的坑。
2. 时间延迟τ的确定:自相关函数法和互信息法的代码实现与取舍
2.1 自相关函数法:快速但粗糙的第一刀
自相关函数法是最直观的思路。对于一个混沌时间序列,随着延迟增大,x(i)和x(i+τ)之间的相关性会逐渐衰减。当自相关函数第一次降到初始值的1-1/e(约0.368)或者第一次过零点时,就认为此时的τ是合适的。前者的逻辑是相关性衰减到37%时,两个坐标已经提供了足够独立的信息;后者的逻辑是过零点意味着线性无关。
Matlab实现很直接:
function tau = auto_correlation_tau(x, max_lag) % x: 输入时间序列(列向量) % max_lag: 最大延迟搜索范围,一般取N/10或更小 x = x(:) - mean(x); % 去均值,这是必须的 N = length(x); acf = zeros(max_lag, 1); for k = 1:max_lag acf(k) = sum(x(1:N-k) .* x(1+k:N)) / sum(x.^2); end % 找第一个过零点或降到1/e以下 threshold = 1/exp(1); tau = find(acf < threshold, 1, 'first'); if isempty(tau) tau = find(acf < 0, 1, 'first'); end if isempty(tau) tau = 1; % 兜底 end end这段代码里有个细节值得说:去均值这一步绝对不能省。如果序列有直流偏置,自相关函数会被一个常数项污染,衰减特性完全失真。我见过有人拿带偏置的数据直接算,结果自相关函数在很大的延迟上还维持在0.9以上,误以为系统有长程相关性,实际上只是均值没去掉。
自相关函数的优点是计算快、实现简单,适合做初步估计。但它有个根本缺陷:它只度量线性相关性。混沌系统的本质是非线性的,两个延迟坐标之间可能线性无关但非线性强相关。自相关函数降到零,不代表两个坐标真正独立。所以自相关法给出的τ往往偏小,重构出来的相空间可能仍然有冗余。
2.2 互信息法:非线性相关性的正确度量
互信息法从信息论角度出发,度量的是x(i)和x(i+τ)之间的一般依赖性,包括线性和非线性。它的定义是:
I(τ) = Σ p(x(i), x(i+τ)) * log2[ p(x(i), x(i+τ)) / (p(x(i)) * p(x(i+τ))) ]
当I(τ)第一次达到局部极小值时,认为两个坐标之间的冗余信息最少,此时的τ就是最优延迟。Fraser和Swinney在1986年证明了这个准则比自相关函数更合理。
Matlab实现互信息需要先做概率密度估计。最常用的方法是用直方图分箱:
function tau = mutual_information_tau(x, max_lag, n_bins) % x: 输入时间序列 % max_lag: 最大延迟 % n_bins: 直方图分箱数,一般取sqrt(N/5)左右 x = x(:); N = length(x); if nargin < 3 n_bins = max(10, round(sqrt(N/5))); end mi = zeros(max_lag, 1); for k = 1:max_lag x1 = x(1:N-k); x2 = x(1+k:N); % 联合直方图 [joint_count, ~, ~] = histcounts2(x1, x2, n_bins); joint_p = joint_count / sum(joint_count(:)); % 边缘直方图 p1 = sum(joint_p, 2); p2 = sum(joint_p, 1); % 计算互信息 mi_k = 0; for i = 1:n_bins for j = 1:n_bins if joint_p(i,j) > 0 mi_k = mi_k + joint_p(i,j) * ... log2(joint_p(i,j) / (p1(i) * p2(j))); end end end mi(k) = mi_k; end % 找第一个局部极小值 tau = 1; for k = 2:max_lag-1 if mi(k) < mi(k-1) && mi(k) < mi(k+1) tau = k; break; end end end这里有几个实操要点。分箱数的选择很关键:分箱太少,概率密度估计太粗糙,互信息曲线会出现虚假的极小值;分箱太多,每个箱子里样本太少,统计涨落大,曲线毛刺多。我一般用sqrt(N/5)作为起点,然后根据曲线的平滑程度微调。如果曲线抖动厉害,可以适当减少分箱数或者对互信息曲线做滑动平均。
另一个坑是局部极小值的判定。理论上说第一个局部极小值就是最优τ,但实际数据中噪声会导致曲线在早期出现伪极小值。我的经验是:不要盲目取第一个极小值,先画出互信息曲线看一眼,如果第一个极小值出现的位置非常靠前(比如τ=1或2),而且极小值深度很浅,那很可能是噪声引起的,应该往后找更明显的极小值。
2.3 两种方法的对比与选择策略
| 对比维度 | 自相关函数法 | 互信息法 |
|---|---|---|
| 度量类型 | 线性相关性 | 一般依赖性(含非线性) |
| 计算复杂度 | O(N*max_lag) | O(Nmax_lagn_bins²) |
| 对噪声敏感度 | 较低 | 较高 |
| 适用场景 | 快速预估、线性主导系统 | 强非线性系统、精度要求高 |
| 典型τ值 | 偏小 | 更合理 |
我的实际做法是:先用自相关法快速估一个τ的范围,再用互信息法在这个范围内精细搜索。这样既省时间又保证精度。如果两种方法给出的τ差异很大(比如自相关给5,互信息给20),那说明系统的非线性很强,应该以互信息的结果为准。
还有一个经验:对于长度N<1000的短序列,互信息法的统计误差会比较大,这时候自相关法反而更稳。如果数据够长(N>5000),互信息法的优势才能充分发挥。
3. 嵌入维数m的确定:虚假近邻法与Cao方法的完整实现
3.1 虚假近邻法的核心逻辑
虚假近邻法(False Nearest Neighbors, FNN)的思路非常巧妙。假设当前嵌入维数是m,相空间中的每个点X(i)都有一个最近邻X(j)。当维数从m增加到m+1时,如果X(i)和X(j)在m维空间里很近,但在m+1维空间里突然变得很远,那说明这两个点在m维空间里的邻近是虚假的——它们只是因为投影到低维空间才看起来近,实际上在高维空间里相距甚远。
FNN方法就是不断增加m,直到虚假近邻的比例降到某个阈值以下(通常取1%或5%)。具体判据是:
如果 ||X(i) - X(j)||_(m+1) / ||X(i) - X(j)||_m > R_tol,则认为是虚假近邻。
其中R_tol是阈值,一般取10。另外还需要一个补充判据:如果 ||X(i) - X(j)||_(m+1) / R_A > A_tol,也认为是虚假近邻,其中R_A是吸引子的半径(所有点对距离的平均值),A_tol一般取2。
function [m_opt, fnn_ratio] = false_nearest_neighbor(x, tau, max_m, R_tol, A_tol) % x: 时间序列 % tau: 时间延迟 % max_m: 最大嵌入维数 % R_tol: 距离比阈值,默认10 % A_tol: 半径比阈值,默认2 x = x(:); N = length(x); if nargin < 4, R_tol = 10; end if nargin < 5, A_tol = 2; end fnn_ratio = zeros(max_m, 1); for m = 1:max_m % 构造m维延迟向量 M = N - (m-1)*tau; Y = zeros(M, m); for d = 1:m Y(:,d) = x((d-1)*tau+1 : (d-1)*tau+M); end % 计算吸引子半径 % 随机采样避免O(N^2)过大 n_sample = min(500, M); idx_sample = randperm(M, n_sample); R_A = 0; count = 0; for i = 1:n_sample for j = i+1:n_sample R_A = R_A + norm(Y(idx_sample(i),:) - Y(idx_sample(j),:)); count = count + 1; end end R_A = R_A / count; % 找最近邻并判断虚假 n_false = 0; for i = 1:M dist = sum((Y - Y(i,:)).^2, 2); dist(i) = inf; % 排除自身 [~, j] = min(dist); % m+1维的距离 if i + m*tau <= N && j + m*tau <= N d_m = sqrt(dist(j)); d_m1 = sqrt(dist(j) + (x(i+m*tau) - x(j+m*tau))^2); if d_m > 0 if d_m1 / d_m > R_tol || d_m1 / R_A > A_tol n_false = n_false + 1; end end end end fnn_ratio(m) = n_false / M; end % 找第一个降到阈值以下的比例 threshold = 0.01; m_opt = find(fnn_ratio < threshold, 1, 'first'); if isempty(m_opt) m_opt = max_m; end end这段代码里有个性能问题需要注意:双重循环找最近邻是O(M²)的复杂度。如果M=5000,那就是2500万次距离计算,Matlab里跑起来可能要几分钟。优化方法是用KD树或者用矩阵运算一次性算完所有距离。对于中等长度的序列,我一般用分块矩阵运算:
% 分块计算距离矩阵,避免内存溢出 block_size = 500; for bi = 1:block_size:M bi_end = min(bi+block_size-1, M); block_dist = pdist2(Y(bi:bi_end,:), Y); % ... 后续处理 end3.2 Cao方法:克服FNN阈值主观性的改进方案
FNN方法虽然经典,但有个主观性问题:阈值R_tol和A_tol怎么选?取10和2是文献里的常见值,但不同数据可能需要调整。Cao在1997年提出的改进方法避开了这个阈值问题。
Cao方法定义了一个量:
E1(m) = E(m+1) / E(m)
其中E(m)是所有点对在m维空间中的平均距离度量。当m增加到某个值时,如果E1(m)不再显著变化(趋于1),那这个m就是最小嵌入维数。Cao方法还定义了一个E2(m)用于区分确定性信号和随机信号:对于确定性信号,E2(m)会在某个值附近波动;对于随机信号,E2(m)恒等于1。
function [m_opt, E1, E2] = cao_method(x, tau, max_m) x = x(:); N = length(x); E1 = zeros(max_m, 1); E2 = zeros(max_m, 1); for m = 1:max_m M = N - m*tau; Y = zeros(M, m+1); for d = 1:m+1 Y(:,d) = x((d-1)*tau+1 : (d-1)*tau+M); end % 计算a(i,m) a = zeros(M, 1); for i = 1:M dist = sum((Y(:,1:m) - Y(i,1:m)).^2, 2); dist(i) = inf; [~, j] = min(dist); d_m = sqrt(dist(j)); d_m1 = sqrt(dist(j) + (Y(i,m+1) - Y(j,m+1))^2); if d_m > 0 a(i) = d_m1 / d_m; else a(i) = 0; end end E = mean(a); if m == 1 E1(m) = 1; else E1(m) = E / E_prev; end E_prev = E; % E2的计算类似,但用不同的距离度量 % 这里简化处理 E2(m) = E; end % 找E1趋于1的位置 m_opt = max_m; for m = 2:max_m-1 if abs(E1(m+1) - E1(m)) < 0.01 m_opt = m; break; end end endCao方法的优势在于不需要主观阈值,E1曲线趋于平稳的位置就是答案。但它的计算量比FNN大,而且对于短序列,E1曲线的平稳段可能不明显。我的经验是:如果数据长度超过3000,优先用Cao方法;如果数据短,用FNN方法配合多个阈值交叉验证。
3.3 两种方法的实测对比与选择建议
我在几组不同来源的数据上做过对比测试。一组是典型的Lorenz系统仿真数据(N=5000),FNN给出m=3,Cao给出m=3,一致。另一组是某机械振动信号(N=8000),FNN在阈值10%时给m=5,阈值1%时给m=7,Cao给m=6。这说明FNN对阈值确实敏感,而Cao的结果更稳定。
| 对比维度 | 虚假近邻法(FNN) | Cao方法 |
|---|---|---|
| 阈值依赖性 | 强,需要调R_tol和A_tol | 弱,自动判定 |
| 计算复杂度 | O(N²) | O(N²) |
| 短序列表现 | 一般 | 较差 |
| 长序列表现 | 好 | 很好 |
| 区分随机/确定信号 | 不能 | 能(通过E2) |
| 推荐使用场景 | 短序列、快速估计 | 长序列、精度要求高 |
实际工作中,我通常两个方法都跑一遍,如果结果一致就放心用;如果不一致,以Cao方法为准,同时检查数据是否去噪充分。因为FNN的虚假近邻判定在噪声大的时候会严重高估m。
4. 完整流程串联:从原始数据到重构相空间的端到端代码
4.1 数据预处理:去均值和去噪的边界
原始时间序列在进入相空间重构之前,必须做预处理。最基本的操作是去均值,这个前面已经强调过了。但去噪这件事需要谨慎:过度去噪会抹掉混沌信号中的高频成分,而混沌系统的分形结构恰恰依赖于这些高频细节。
我的建议是:如果信噪比尚可(目测信号波形清晰),只做去均值,不做额外滤波。如果噪声明显,可以用小波软阈值去噪,但阈值要设得保守一些,宁可保留噪声也不要过度平滑。一个简单的判断方法是:去噪前后分别算一下关联维数,如果差异超过10%,说明去噪过度了。
function x_clean = preprocess(x) x = x(:); % 去均值 x_clean = x - mean(x); % 可选:小波去噪 % 使用wdenoise函数,阈值设保守 % x_clean = wdenoise(x_clean, 3, 'DenoisingMethod', 'UniversalThreshold'); end4.2 参数扫描与交叉验证
单独用某一种方法确定τ和m,有时候会得到矛盾的结果。更稳妥的做法是做参数扫描:在τ的合理范围内(比如1到50)和m的合理范围内(比如2到15),分别计算重构相空间的质量指标,比如关联维数的稳定性、Lyapunov指数的收敛性,然后选使指标最稳定的参数组合。
function [tau_opt, m_opt] = parameter_sweep(x, tau_range, m_range) best_score = inf; tau_opt = tau_range(1); m_opt = m_range(1); for tau = tau_range for m = m_range % 重构相空间 Y = reconstruct_phase_space(x, tau, m); % 计算质量指标:这里用关联维数的标准差 D2 = correlation_dimension(Y); score = std(D2); if score < best_score best_score = score; tau_opt = tau; m_opt = m; end end end end这个扫描过程计算量不小,但能有效避免单一方法的偏差。我一般先用互信息法和Cao方法各跑一遍,把结果作为扫描范围的中心,然后在这个中心附近做精细扫描。
4.3 重构相空间的可视化验证
参数选好之后,一定要画图验证。对于m=2或m=3的情况,可以直接画二维或三维相图。重构好的相空间应该呈现出清晰的几何结构——比如Lorenz吸引子的蝴蝶形状、Rossler吸引子的螺旋环。如果画出来是一团模糊的云,那说明参数没选对。
function plot_phase_space(x, tau, m) Y = reconstruct_phase_space(x, tau, m); if m == 2 plot(Y(:,1), Y(:,2), '.', 'MarkerSize', 1); xlabel('x(t)'); ylabel(['x(t+' num2str(tau) ')']); elseif m == 3 plot3(Y(:,1), Y(:,2), Y(:,3), '.', 'MarkerSize', 1); xlabel('x(t)'); ylabel(['x(t+' num2str(tau) ')']); zlabel(['x(t+' num2str(2*tau) ')']); grid on; end end对于m>3的情况,可以用延迟坐标的二维投影矩阵来间接验证:把任意两个延迟坐标画在一起,如果所有投影都显示出结构化的轨迹而不是随机云团,那说明重构是成功的。
5. 实操中那些文档不会告诉你的坑
5.1 数据长度不够时,所有方法都会骗你
相空间重构对数据长度有硬性要求。经验法则是N > 10^m,也就是说如果嵌入维数是5,至少需要10万个点。实际中很难拿到这么长的数据,所以通常放宽到N > 5000。但如果N < 2000,互信息曲线和FNN曲线都会非常毛糙,给出的τ和m可信度很低。
我遇到过一个案例:某传感器数据只有800个点,用FNN算出m=8,用Cao算出m=4,差了整整一倍。后来把数据延长到5000点重新算,两个方法都收敛到m=5。所以短序列的参数估计只能作为参考,不能作为最终依据。
5.2 时间延迟和嵌入维数的耦合关系不能忽略
虽然工程上习惯先定τ再定m,但这两个参数实际上是耦合的。不同的τ会导致不同的m估计。有研究表明,当τ增大时,最优m会略微减小。所以严格的做法是联合优化:在(τ, m)的二维网格上搜索使某个目标函数最小的组合。
一个实用的联合准则是最小化重构相空间中轨迹的预测误差:用重构的相空间做一步预测,预测误差最小时的(τ, m)就是最优的。这个方法计算量大,但结果最可靠。
5.3 噪声对FNN方法的致命影响
FNN方法对噪声极其敏感。噪声会制造大量虚假的邻近点对,导致FNN比例居高不下,从而严重高估m。我做过一个实验:在干净的Lorenz数据上叠加5%的高斯白噪声,FNN给出的m从3跳到了9,而Cao方法只从3变成了4。
所以如果你的数据噪声水平未知,优先用Cao方法。如果非要用FNN,先把数据做适度去噪,并且把R_tol从10提高到15甚至20,这样可以降低噪声引起的虚假近邻误判。
5.4 周期信号和混沌信号的区分
不是所有看起来复杂的时间序列都是混沌的。周期信号在高维嵌入下也会展开成闭合曲线,FNN方法可能会给出一个不小的m值。区分方法是看E2曲线(Cao方法里的)或者计算最大Lyapunov指数:混沌系统的最大Lyapunov指数为正,周期信号为零或负。
function lambda_max = largest_lyapunov(x, tau, m) % 用Rosenstein方法计算最大Lyapunov指数 Y = reconstruct_phase_space(x, tau, m); M = size(Y, 1); % 找最近邻并追踪距离演化 % ... 具体实现略 % 对log(d(t))做线性拟合,斜率就是lambda_max end如果算出来lambda_max接近零,那说明这个信号不是混沌的,相空间重构的意义就不大了。
5.5 参数选择的敏感性分析
最后分享一个实用技巧:对τ和m做敏感性分析。具体做法是固定m,让τ在最优值附近±20%范围内变化,看关联维数或Lyapunov指数的变化幅度。如果变化很小,说明参数选择是稳健的;如果变化剧烈,说明数据质量有问题或者方法不适用。
这个分析能帮你判断:当前的重构结果到底可不可信。我见过太多人算出τ和m之后直接往下做,从来不检查稳健性,结果后续分析全是空中楼阁。
function sensitivity_analysis(x, tau_opt, m_opt) tau_range = round(tau_opt*0.8) : round(tau_opt*1.2); D2_values = zeros(length(tau_range), 1); for i = 1:length(tau_range) Y = reconstruct_phase_space(x, tau_range(i), m_opt); D2_values(i) = correlation_dimension(Y); end fprintf('关联维数变化范围: %.3f ~ %.3f\n', min(D2_values), max(D2_values)); fprintf('相对变化: %.1f%%\n', (max(D2_values)-min(D2_values))/mean(D2_values)*100); end如果相对变化超过15%,我就建议重新检查数据质量,或者考虑用联合优化方法重新估计参数。
6. 把代码跑起来:一个完整的可复现示例
6.1 生成测试数据
为了让你能直接复现,我用Lorenz系统生成一组标准测试数据:
function x = generate_lorenz(N, dt) % 生成Lorenz系统的时间序列 % dx/dt = sigma*(y-x), dy/dt = x*(rho-z)-y, dz/dt = x*y - beta*z sigma = 10; rho = 28; beta = 8/3; x = zeros(N, 1); y = zeros(N, 1); z = zeros(N, 1); x(1) = 1; y(1) = 1; z(1) = 1; for i = 1:N-1 dx = sigma*(y(i)-x(i)); dy = x(i)*(rho-z(i))-y(i); dz = x(i)*y(i)-beta*z(i); x(i+1) = x(i) + dx*dt; y(i+1) = y(i) + dy*dt; z(i+1) = z(i) + dz*dt; end % 只取x分量作为标量时间序列 x = x(1001:end); % 去掉暂态 end取N=5000,dt=0.01,得到5000个点的x分量序列。这个序列的关联维数约为2.06,所以理论最小嵌入维数是5(2*2.06+1≈5.12,向上取整)。
6.2 完整流程脚本
% 主脚本:相空间重构完整流程 clear; clc; % 1. 生成数据 x = generate_lorenz(6000, 0.01); x = preprocess(x); % 2. 确定时间延迟 tau_acf = auto_correlation_tau(x, 100); tau_mi = mutual_information_tau(x, 100); fprintf('自相关法 tau = %d\n', tau_acf); fprintf('互信息法 tau = %d\n', tau_mi); tau = tau_mi; % 以互信息为准 % 3. 确定嵌入维数 [m_fnn, fnn_ratio] = false_nearest_neighbor(x, tau, 15); [m_cao, E1, E2] = cao_method(x, tau, 15); fprintf('FNN法 m = %d\n', m_fnn); fprintf('Cao法 m = %d\n', m_cao); m = max(m_fnn, m_cao); % 取较大值保守 % 4. 重构相空间并可视化 Y = reconstruct_phase_space(x, tau, m); plot_phase_space(x, tau, min(m, 3)); % 5. 敏感性分析 sensitivity_analysis(x, tau, m);跑完这个脚本,你应该能看到Lorenz吸引子的典型蝴蝶形状,τ大约在10-15之间,m在5左右。如果结果差很远,检查一下数据生成部分的参数是否正确。
6.3 常见报错与修复
报错1:Index exceeds matrix dimensions。通常是因为在构造延迟向量时,索引超出了序列长度。检查M = N - (m-1)*tau是否为正,如果为负说明m或tau太大了。
报错2:Matrix dimensions must agree。检查输入序列是否是列向量,很多函数要求x(:)转换。另外检查tau和m是否是标量。
报错3:互信息曲线全是零。这通常是因为分箱数太少,所有点都落在同一个箱子里。增加n_bins或者检查数据范围是否过小。
报错4:FNN比例始终为1。说明所有点都被判定为虚假近邻,可能是R_tol设得太小,或者数据噪声太大。先把R_tol调到20试试。
7. 参数确定之后:下一步该做什么
τ和m确定之后,相空间重构只是第一步。接下来通常要做的是:
关联维数计算:用Grassberger-Procaccia算法估计吸引子的分形维数,验证重构的合理性。如果算出来的D2和理论值差很远,说明τ或m没选对。
Lyapunov指数谱:用Wolf方法或Rosenstein方法计算最大Lyapunov指数,判断系统是否混沌。正的最大Lyapunov指数是混沌的充要条件。
非线性预测:用重构的相空间做短期预测,比如局域线性预测或神经网络预测。预测精度是检验重构质量的最终标准。
这些内容每一个都够单独写一篇,这里就不展开了。核心原则是:相空间重构的参数选择不是终点,而是起点。参数选得好,后续分析事半功倍;参数选得差,后面全是无用功。
我个人在实际项目中的体会是:不要迷信任何一种方法给出的单一结果。互信息法、自相关法、FNN、Cao方法,四个结果摆在一起看,取一个合理的交集。如果四个结果分散得很厉害,那说明数据本身可能不适合做相空间重构,或者需要更精细的预处理。宁可在这里多花两天时间把参数调稳,也不要带着错误的τ和m往下做一个月。