☰
多尺度排列熵参数优化:GA与PSO联合寻优的完整MATLAB实践
2026/10/26 15:46:48 网站建设 项目流程

简介:这是一份面向信号处理与故障诊断研究者的MATLAB资源包,围绕多尺度排列熵(MPE)的参数优化问题展开。作者系统考察了时间序列长度N、嵌入维数m、延迟时间t与尺度因子s对算法的影响,并以多尺度排列熵的偏度构造目标函数,分别采用遗传算法(GA)和粒子群优化算法(PSO)实现参数寻优。资源共25个文件,以14个m脚本为主,涵盖GA-MPE与PSO-MPE两套完整流程,包括主程序、适应度函数以及遗传算法的编码、选择、交叉、变异等模块;另含3个mat数据文件和8幅实验结果bmp图,便于复现参数影响分析及优化对比。压缩包内PSO-MPE与GA-MPE两个模块目录清晰,主程序可直接运行,适合对比两类智能算法的优化效果。整包仅6.03MB,轻量易用。已有4332人学习下载,适合需要理解MPE参数敏感性或借助智能算法自动寻优的研究者、研究生作为参考。

1. 多尺度排列熵的参数优化:这份压缩包里装的是 GA 与 PSO 两套寻优完整流程

多尺度排列熵(MPE)本身不复杂,复杂的是一开始就要面对的四个参数:时间序列长度 N、嵌入维数 m、延迟时间 t、尺度因子 s。它们之间互相牵制,任何一个拍脑袋定下来,后面算出来的熵值都可能带偏结论。这份参数优化多尺度排列熵压缩包,最大的价值不是给你一个 MPE 函数,而是把“参数影响分析 + 遗传算法寻优 + 粒子群寻优 + 画图程序”四件事串成了一条完整链路,打开就能复现。里面有可直接运行的 GA-MPE 与 PSO-MPE 两套源码,还带示例数据 Bp.mat 和一组生成图 2、图 3、图 4 的脚本。适合做故障诊断、生理信号分析、非线性时间序列特征提取的研究生和工程师,尤其是那些已经试过网格搜索、被组合爆炸折磨过的人。

2. 参数影响可视化:N、m、t、s 四个变量到底怎么支配结果

多尺度排列熵的正确用法,不是拿到数据就直接跑,而是先搞清楚每个参数对熵值曲线的作用方向。这份压缩包里专门有一个“参数对多尺度排列熵的影响(画图程序)”目录,里面是 MPE_main.m 和一批输出图片,目的就是让你在优化之前,先把参数的“脾气”摸清楚。

2.1 先跑通 MPE_main.m:六张子图加两张总图的复现路径

解压后进入“参数对多尺度排列熵的影响(画图程序)”目录,里面能看到 Bp.mat、MultiscalePermutationEntropy.m、MPE_main.m,以及图 2a~2f、图 3、图 4 的 bmp。这些 bmp 是作者跑好的结果,你可以直接用,但更推荐自己运行一遍 MPE_main.m,把整套图重新生成一次。因为只有自己跑通,后面改参数时才不会抓瞎。

打开 MATLAB,先把当前路径切到该目录,然后做三步检查:

% 检查关键文件是否都在当前路径 which Bp.mat which MultiscalePermutationEntropy.m which MPE_main.m

如果三条命令都返回了路径,说明文件齐了。接着直接运行:

run('MPE_main.m')

运行逻辑很简单:MPE_main.m 会载入 Bp.mat 里的示例时间序列,然后调用 MultiscalePermutationEntropy.m 在不同参数组合下计算多尺度排列熵,最后把结果画成图 2a~2f、图 3、图 4。我建议你跑完后按图号对应检查一遍:图 2a~2f 通常是固定其他三个参数、只变化某一个参数时,熵值随尺度因子 s 的变化曲线;图 3、图 4 大概率是熵值随某个参数变化的趋势图或者目标函数曲面。具体每一张图对应哪一组参数,看 MPE_main.m 里的注释即可,不同版本的画法略有差异,但整体思路是一致的。

这里有一个常见做法值得学习:他用 Bp.mat 这个固定信号做敏感性分析。你拿到手之后,也可以把自己的信号替换成这个 mat 里的变量,或者直接改 MPE_main.m 里的数据加载部分。

% 替换成自己的数据 % load('Bp.mat'); % 原始示例数据 load('your_signal.mat'); % 你的信号,变量名改为 x

参数说明:替换数据后,后面所有画图和优化都会基于你的信号进行,这才是这份资源真正能“落地”到你自己场景里的关键一步。否则你只是复现了一个别人的案例。

2.2 怎么读参数影响:从曲线趋势反推优化必要性

四个参数对 MPE 的影响,不能只靠感觉,要用曲线说话。跑完 MPE_main.m 你会看到:当嵌入维数 m 增大时,排列模式数会以 m 的阶乘速度增长,熵值曲线的波动会明显变大;当延迟时间 t 增大时,曲线会变得平滑,但也可能丢掉信号里的高频细节;当尺度因子 s 取到接近数据长度的一半时,末尾的熵值往往开始失真,因为粗粒化后的有效数据点太少。

时间序列长度 N 是更隐蔽的变量。多数人以为 N 只是数据量,取大一点就行,实际上 N 直接影响 MPE 在最大尺度因子下的可用样本数。粗粒化会把原序列分段求平均,尺度 s 越大,每段长度越长,能形成的粗粒化序列就越短。如果 N 不够,后面的熵值就是黑匣子,根本不反映真实信号特征。

下面这张表是我跑这类程序时用来对照的快速参考:

参数作用方向取值偏小取值偏大
N决定基础样本量统计不稳,熵值抖动大计算耗时增加,但曲线平滑
m决定排列模式数量模式太少,区分度低要求 N 必须远超 m 阶乘,否则欠采样
t决定采样间隔容易漏掉结构信息曲线过度平滑,丢失细节
s决定尺度范围只能看到短期结构尾部熵值失真,且计算量线性增长

表格里最值得记住的是 m 与 N 的关系。多尺度排列熵在计算中要枚举 m 个符号的全排列,模式数上限是 m 的阶乘。若 N 小于或接近 m 的阶乘,许多模式根本不会出现,得到的熵值分布是残缺的。这就是为什么后面做 GA 和 PSO 优化时,不能把 m 的搜索范围设得太随意。

读图时你还会发现,很多参数组合下 MPE 曲线明显偏向某一侧,也就是多尺度熵向量分布不对称。这种不对称既是信号特征,也会成为优化目标的基础。原作者就是用偏度把它量化,构造了一个标量目标函数。这一步理解到位了,后面看 GA-MPE 和 PSO-MPE 的适应度函数就能一眼看穿。

3. 遗传算法寻优:GA-MPE 的编码、适应度与主循环

压缩包里的 GA-MPE 目录,是我个人认为整个资源里最值得细读的部分。它把遗传算法和 MPE 结合得比较完整:有编码、解码、初始化、选择、交叉、变异,再加上目标函数,一共十个文件。目录里的 Coding.m、Incoding.m、InitPop.m、Select.m、crossover.m、Variation.m 各管一段,Main_GA_MPE.m 负责把整条流水线串起来。

3.1 为什么用偏度构造目标函数

MPE 的输出本身是一个随尺度变化的向量,遗传算法没法直接拿向量做适应度比较,必须压缩成一个标量。原作者选择了偏度,这是很聪明的折中。偏度描述的是数据分布的不对称性,多尺度排列熵在多尺度上算完后,熵值向量越不对称,说明信号在不同尺度上的复杂度差异越大。用它的绝对值作为适应度,等于让优化器去找一个让各个尺度熵值分布尽量均衡的参数组合。

常见做法是这样写适应度函数,伪代码如下:

function obj = Fitness(params, x) % params 是遗传算法传进来的个体,被解码成 m, t, s, N m = round(params(1)); % 嵌入维数必须是整数 t = round(params(2)); % 延迟时间也必须是整数 s = round(params(3)); % 尺度因子最大值 N = round(params(4)); % 时间序列长度,可能参与优化也可能固定 % 计算多尺度排列熵,接口形式以压缩包内函数为准 MPE = MultiscalePermutationEntropy(x(1:N), m, t, s); % 目标函数:让偏度的绝对值尽量小 obj = abs(skewness(MPE)); end

逻辑说明:第 6 行到第 9 行把遗传算法给出的连续值圆整成整数,因为 m、t、s 不可能是小数。第 12 行调用 MPE 主函数得到熵值向量。第 15 行是关键,用 MATLAB 自带的skewness函数算出偏度,取绝对值作为适应度。数值越小,代表该组参数下熵值分布越对称,也就是参数组合越稳定。

参数说明:round是必须的,否则解码出来的 m 可能是 4.7,MPE 内部会出问题。x(1:N) 表示只取前 N 个点参与计算,这样 N 也可以作为一个优化变量。不过大多数场景下 N 先固定为 1024 或 2048,只让 m、t、s 三个参数进优化器,否则搜索空间会变大很多。

3.2 十个文件怎么配合:遗传算法的主循环拆解

打开 Main_GA_MPE.m,核心循环一般长这样:

% Main_GA_MPE.m 骨架逻辑 pop = InitPop(popsize, dim, lb, ub); % 1. 初始化种群 for gen = 1:maxgen fitness = zeros(popsize, 1); for i = 1:popsize params = Incoding(pop(i,:), lb, ub); % 2. 二进制解码 fitness(i) = Fitness(params, x); % 3. 计算适应度 end [pop, best] = Select(pop, fitness); % 4. 选择 pop = crossover(pop, pc); % 5. 交叉 pop = Variation(pop, pm, lb, ub); % 6. 变异 disp(['gen=', num2str(gen), ' best=', num2str(min(fitness))]); end

各个文件的职责很清晰:InitPop.m 负责生成初始二进制种群;Coding.m 和 Incoding.m 是一对逆操作,前者把十进制参数编码成二进制串,后者把二进制串解码回参数;Fitness.m 就是我们上面写的目标函数;Select.m 做选择,筛选出适应度好的个体;crossover.m 做交叉重组;Variation.m 做变异。整个流程是标准遗传算法框架,没有花哨改动,好处是容易读懂、容易改。

一定不要跳过 BetterBest 这类查看收敛的环节。我一般会在循环里每隔五代打印一次最优适应度:如果连续 20 代没有任何下降,说明种群可能早熟。此时可以干预,提高变异率或者重新初始化部分个体。

3.3 GA 参数怎么设:种群规模、交叉率、变异率的经验区间

这一节不是玄学,但有经验成分。遗传算法跑得好不好,一半看目标函数,另一半看这四个超参。常见区间如下:

超参数建议范围说明
popsize30~80维度不高时 50 足够,过大反而慢
maxgen50~200观察收敛曲线,不要盲目加大
pc 交叉率0.7~0.9太低则搜索慢,太高则破坏好模式
pm 变异率0.01~0.10.05 起步,早熟时往上调

需要留意的是这段伪代码里的 Genetic Algorithm 最终会返回一组十进制参数,但返回前必须再做一次解码,否则拿到的还是二进制串。很多新手在这里翻车:明明看到最优适应度很漂亮,最后输出参数却是一串 0 和 1。处理方式是在主循环最后加一行bestParams = Incoding(bestChrom, lb, ub),把最优染色体转成可用的 m、t、s。

4. 粒子群寻优:PSO-MPE 的速度更新与参数边界

PSO-MPE 目录比 GA-MPE 清爽一些,核心文件只有 Main_PSO_MPE.m、MultiscalePermutationEntropy.m、fitness.m,外加 Bp.mat。粒子群算法不需要编码解码,也不需要交叉变异,整个流程围绕速度和位置更新展开,代码量天然更少。

4.1 PSO 主循环:速度更新公式与边界钳制

写 PSO 最核心的就是速度更新那条公式。Main_PSO_MPE.m 里的骨架逻辑通常是这样的:

% Main_PSO_MPE.m 骨架逻辑 v = zeros(nParticles, dim); % 速度初始化 particles = lb + rand(nParticles, dim) .* (ub - lb); % 位置初始化 pbest = particles; % 个体历史最优 gbest = particles(1,:); % 群体全局最优 for iter = 1:maxIter w = 0.9 - 0.5 * iter / maxIter; % 惯性权重线性递减 for i = 1:nParticles r1 = rand(size(v(i,:))); r2 = rand(size(v(i,:))); v(i,:) = w * v(i,:) + ... c1 * r1 .* (pbest(i,:) - particles(i,:)) + ... c2 * r2 .* (gbest - particles(i,:)); particles(i,:) = particles(i,:) + v(i,:); end % 边界钳制:防止粒子飞出搜索范围 particles = max(particles, lb); particles = min(particles, ub); end

逻辑说明:第一行把速度矩阵初始化为零。第二行在参数上下界之间随机撒粒子。第六行是惯性权重线性递减,迭代前期 w 大、全局搜索能力强,后期 w 小、局部精细搜索。第九行到第十一行是 PSO 的灵魂,将上一轮速度、朝个体历史最优方向修正、朝全局最优方向修正三部分加权相加。第十二行更新位置。第十五、十六行把越界粒子拉回边界。

参数说明:c1 和 c2 是学习因子,常见取值都是 2.0。w 的递减范围 0.9 到 0.4 是最常用的一组设定。nParticles 一般取 20~40,dim 在这里是参与优化的参数个数,如果你只优化 m、t、s,dim 就是 3,如果带上 N,dim 就是 4。

边界钳制这块要特别强调:直接把越界粒子拉回边界是最简单的方法,但会导致大量粒子贴在边界上,丧失多样性。我一般会改成如果粒子越界,就给该维速度重新赋予一个随机小值,让粒子继续探索。

4.2 fitness.m 与 GA 的 Fitness.m 有什么不一样

PSO-MPE 里的 fitness.m 做的事情和 GA-MPE 里的 Fitness.m 几乎一样,都是调用 MultiscalePermutationEntropy.m 计算熵值向量,然后取偏度绝对值。差别只在接口形式:PSO 传进来的粒子位置是连续实数,而 GA 那边要经过 Incoding.m 先解码。

function obj = fitness(position, x) m = round(position(1)); t = round(position(2)); s = round(position(3)); MPE = MultiscalePermutationEntropy(x, m, t, s); obj = abs(skewness(MPE)); end

注意这里没有 N,因为我把 N 固定在内部了。实际工程中,N 的确可以通过量化的方式加入 PSO,但不推荐:PSO 对连续变量友好,对整数变量反而容易出现在小数点附近来回震荡。m、t、s 用round圆整后,速度更新仍在连续域进行,美国粒子群公式不受影响,这样是没问题的。

4.3 GA 还是 PSO:离散编码与连续搜索的取舍

同一个资源里同时给了两套优化器,很多人会纠结用哪套。我的判断依据很简单:看你的搜索空间是离散型还是连续型。

嵌入维数 m、延迟时间 t、尺度因子 s 本质都是整数,理论上更适合 GA 的二进制编码。但 PSO 也可以跑,只需要在计算适应度时圆整。实际测试下来,两者收敛效果差别不大,主要差异在实现复杂度上:GA-MPE 多了六个文件,调试成本更高;PSO-MPE 只有两个主文件加一个 fitness,改起来更快。

如果你的目标是做参数敏感性分析,建议先用 PSO 快速摸一遍可行域;如果要做严格的参数寻优对比实验,就两套都跑,把两者最优解互相验证。这也是原作者把 GA 和 PSO 放在一起的最大意义。

5. 避坑与常见问题:MPE 参数优化的五个翻车现场

这部分是血泪经验。我在用自己的信号替换 Bp.mat 跑这套程序时,几乎把每个坑都踩了一遍,写下来希望你不用再踩。

5.1 报错“索引超出数组边界”

现象:运行 Main_GA_MPE.m 或 Main_PSO_MPE.m 时,中途报错,提示索引超出数组边界,位置在 MultiscalePermutationEntropy.m 内部。

原因:遗传算法或粒子群在搜索过程中产生了一个很大的 m 值,而时间序列长度 N 不够,导致排列模式数超过实际可用窗口数。尤其是二进制编码,解码后可能会出现 m=9、m=10 这种离谱值。

解决:在 Fitness.m 或 fitness.m 开头加一道约束,不满足条件的直接给一个很大的适应度值,排除该个体。

if m >= 7 || N < factorial(m) || t > N / 2 || s > N obj = 1e10; return; end

核心是让优化器永远不要走到非法参数上。m 的上限设到 7,一般工程已经够用;N 必须远大于 m 的阶乘才能保证每个排列模式都被充分采样。

5.2 MPE 曲线尾部剧烈波动

现象:尺度因子 s 越大,熵值曲线尾部抖动越明显,重复测两次结果不完全一样。

原因:粗粒化后序列变短,尾部尺度的有效数据点太少,统计不稳定。这是 MPE 本身的结构性限制,不是代码 bug。

解决:对序列做延拓,比如镜像反射延拓,或者限制 s 的最大值不超过 N 的十分之一。也可以在计算尾部尺度时跳过第一个点,因为第一个点的粗粒化序列等于原序列,包含不了多尺度信息。

5.3 GA 最优适应度长期不更新

现象:打印出的最优适应度连续 30 代不变,但种群还在继续跑。

原因:选择压力过大或变异率太低,种群多样性丧失。尤其是二进制编码的 GA,在后期很容易所有个体收敛到同一个模式。

解决:把变异率 pm 从 0.01 调到 0.08 左右;或在每次迭代后随机重置 5% 的较差个体,重新初始化它们的染色体。另一个土办法是保存每一代的最优个体,整个循环结束后再局部微调一把。

5.4 PSO 粒子全部贴在边界上

现象:运行完看最优参数,发现 m、s 正好等于设定的上界或下界,且适应度值不太理想。

原因:粒子越界后被简单地拉回边界,导致边界处积累大量粒子,速度向量朝边界外侧不断修正,形成死锁。

解决:不要直接 clamp 到边界,改成越界后随机重置该维速度的方向和大小。常见写法如下:

for d = 1:dim if particles(i,d) < lb(d) || particles(i,d) > ub(d) particles(i,d) = lb(d) + rand * (ub(d) - lb(d)); v(i,d) = 0; % 速度归零,重新积累 end end

这样粒子在边界处不会一窝蜂停下,而是重新开始探索。

5.5 优化结果差异很大,换一段数据就不灵

现象:用 Bp.mat 优化出的参数效果好,换成自己的信号后熵值曲线乱成一团,分类精度也下降。

原因:用单段数据做目标函数,偏度只反映这一段序列的分布特性,缺乏代表性。

解决:我一般会在 Fitness 里加载多段数据,计算每一段 MPE 的偏度,然后取平均或取加权和。最终优化出来的参数会更有泛化能力,而不是过拟合到一段信号上。

6. 验证与进阶:用自造信号检验最优参数,再跑批量实验

拿到最优参数后,不要急着上业务数据,先做一个快速验证:用一段你能预测理论结果的自造信号,对比默认参数和优化参数的差别。这一步能帮你迅速判断优化器是不是跑偏了。

% 构造一段正弦加噪声信号 fs = 1000; t = 0:1/fs:1; x = sin(2*pi*50*t) + 0.2*randn(size(t)); % 默认参数 MPE_default = MultiscalePermutationEntropy(x, 3, 1, 10); % 优化参数,m_opt、t_opt、s_opt 来自 GA 或 PSO 输出 MPE_opt = MultiscalePermutationEntropy(x, m_opt, t_opt, s_opt); % 对比偏度与曲线形状 disp(['default skewness: ', num2str(abs(skewness(MPE_default)))]); disp(['opt skewness: ', num2str(abs(skewness(MPE_opt)))]); figure; plot(1:10, MPE_default, 'o-'); hold on; plot(1:length(MPE_opt), MPE_opt, 's-'); legend('默认参数', '优化参数');

如果优化后的偏度绝对值明显小于默认参数,且曲线没有出现尾部剧烈抖动,说明寻优过程有效。如果两个结果几乎一样,也不要急着认为优化没用,很可能是你的信号本身对参数不敏感,换一段更复杂的信号再试。

进阶用法是把整个寻优过程封装成一个函数,输入是一段信号,输出是最优参数。然后对多段不同工况的信号批量运行,统计参数分布范围。这样你能知道该场景下 m、t、s 应该固定在哪个区间,而不是每段信号单独跑一次优化。批量实验时记得把每一轮的种群规模减小到 20,最大迭代次数降到 30,速度会快很多。

从那以后我每次跑 MPE 参数优化,都会强制先跑一遍参数影响画图程序,再决定搜索边界,而不是直接把 m 设成 3 到 7、s 设成 1 到 20 就扔进优化器。搜索边界定得越合理,后续 GA 和 PSO 收敛越快,翻车概率也越低。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询