MATLAB滑动窗口法计算声发射信号信息熵曲线完整教程
发布时间:2026/9/28 23:35:16来源:尧图网络
各位做声发射监测、机械损伤诊断或者信号处理的朋友这篇手册就是为了解决一个实际问题拿到一段声发射信号数据之后怎么用MATLAB把它变成一条能反映材料损伤程度变化的信息熵曲线同时把关键的图形结果一键保存下来方便写报告、做对比。我自己最初接触这个需求是在一次金属拉伸损伤监测试验中数据量不算大但时间跨度长原始波形密密麻麻根本看不出状态切换的拐点后来用滑动窗口法把信息熵随时间的变化曲线拉出来窗口期对应关系一眼就清楚了。这篇内容覆盖从原理逻辑到代码实现、从参数选择到图片保存的完整链路适合刚接触信号熵值分析的研究生也适合已经写了些数据处理脚本、想补充特征提取模块的工程师。照着操作就能直接跑通不需要你之前有很深的信息论基础。我需要提醒一句这篇文章不是把一堆函数罗列给你就完事而是把每一步为什么这么做讲清楚。比如窗口长度为什么不能随意取步长和窗口的重叠率有什么关系图片保存为什么推荐用exportgraphics而不是老式的saveas这些细节往往决定了你的结果可不可信、可不可复现。1. 信号熵值分析和滑动窗口法的设计逻辑1.1 信息熵对声发射信号到底意味着什么信息熵最早是香农用来度量信息量的指标简单说就是衡量一个随机变量的不确定性。信号越混乱、越不可预测熵值越高信号越规整、越接近周期或者恒定熵值就越低。放到声发射场景里这个指标的价值在于材料在变形、裂纹扩展、摩擦等不同阶段产生的弹性波信号复杂度会明显变化。比如早期微损伤信号比较稀疏、波形特征相对单一熵值往往偏低等到裂纹活跃、大量能量集中释放时波形变得杂乱、频率成分丰富熵值就会抬升。实际处理时我们不是对整段原始波形求一个熵值就结束因为那只能告诉你整段数据的平均混乱程度丢失了时间维度的信息。损伤是演化的过程哪个阶段开始加剧、哪个阶段趋于平稳必须通过“局部时间段”的熵值变化来观察。这就是滑动窗口法介入的根本理由把长信号切成一段段重叠的小区间逐段计算熵值最终得到一条“熵值随窗口中心位置”变化的曲线。我自己试过直接对整段信号算熵再用另一个整体指标做对照结果就是什么都看不出来因为早期信号占比太大把后期的剧烈变化给平均掉了。所以如果你手里是一段几十分钟甚至几个小时的连续声发射数据滑动窗口基本是必选项。1.2 滑动窗口法的计算过程拆解滑动窗口的思路并不复杂很像用放大镜沿着一条长尺子慢慢移动每到一个位置就看局部区域的细节。落到代码层面就是三重循环逻辑先确定一个固定长度的窗口比如2048个采样点然后从信号起始位置开始截取这2048个点对这个片段做信息熵计算接着把窗口向右移动一定数量的采样点比如步长256重复截取和计算直到窗口覆盖完全部信号。这里有个容易被新手忽略的点窗口重叠。窗口长度2048、步长256说明相邻两个窗口之间有1792个采样点是重叠的。重叠的目的是让熵值曲线平滑不会因为边界截断导致相邻两个窗口之间的熵值突变。如果不重叠也就是步长等于窗口长度你会得到一条锯齿感很明显的曲线而且窗口边界上的信号截断对熵值影响非常大。从数学上理解信息熵的计算公式为对每个可能的取值或区间统计出现概率p然后对所有概率求和-p*log2(p)。但连续信号不能直接套这个公式需要先做幅值区间划分或者概率密度估计再代入公式。幅度划分的区间数对结果影响很大区间太少会丢掉细节区间太多又会让每个区间的概率过于稀疏。这个平衡点我会在第2部分详细讲。2. 准备工作与关键参数选择2.1 程序框架和输入数据格式动手写代码之前先想清楚输入输出。这个程序的输入是一维声发射信号通常是从采集系统导出的CSV、TXT或者DAT文件内容是采样时间和对应的幅值。在MATLAB里加载这类数据我用得最多的是readmatrix因为它对文本格式的兼容性比较好矩阵结构也不容易出错。如果你的数据文件开头有说明文字可以加上NumHeaderLines参数跳过表头。加载完成后对信号做一次简单的去直流处理也就是减去信号的均值。为什么必须做这一步因为声发射采集系统偶尔会有零点漂移如果信号整体有一个直流偏置在做幅值区间划分的时候会出现概率分布的偏移直接影响信息熵数值。去直流用一条指令就能解决data data - mean(data)。接下来定义窗口参数我建议一开始就把参数集中写在脚本头部方便反复调整。包括采样率fs、窗口长度windowLen、步长stepLen。采样率这个参数本身不参与熵值计算但它决定窗口对应的时间长度便于你后续和损伤过程的其他物理量做对照。比如10kHz采样率下一个2048点的窗口约等于204.8毫秒这个时长对于宏观裂纹扩展分析来说比较合适。2.2 窗口长度和步长到底怎么定这是整套程序里最值得花时间调试的地方。窗口长度决定了频率分辨率和统计稳定性之间的平衡。窗口太短比如256个点单个窗口内的数据量太少概率统计不够充分得到的熵值波动剧烈看起来像噪声窗口太长比如16384个点时间分辨率会变得很差损伤状态的快速变化会被平滑抹掉。我的经验是先看信号的采样率和损伤过程的时间尺度。如果损伤演化在几十秒级别那么窗口对应的时间最好在0.1到1秒之间如果损伤过程很快只有一两秒窗口要相应缩短到几十毫秒。步长的选择直接控制计算量和曲线平滑度。步长越小窗口重叠越多曲线越平滑但计算次数增多步长越大计算越快但曲线会丢失快速变化细节。我个人习惯取窗口长度的1/8到1/4作为步长比如窗口2048步长取256或512。这个比例从工程角度来说是性价比最高的区间既不浪费算力也能保证曲线精度。如果你的数据量特别大几十兆采样点建议先取窗长的1/4跑通了再慢慢加密。还有一个参数容易被忽略就是计算信息熵时的幅值分箱数量。我用过8、16、32、64四种划分对比下来16到32是比较稳的区间。分箱太少比如8箱大量不同幅值的细节被压缩在一起多个信号段的熵值差异显示不出来分箱太多比如64以上每个箱子里的统计样本数下降会导致熵值整体偏高并且对微小噪声过于敏感。下面给一个参数速查表方便你根据数据情况快速起步参数推荐起点调参方向注意事项窗口长度2048点波形特征剧烈增加或增加点数太少熵值波动大太多时间分辨差滑动步长256点曲线噪声大时减小建议为窗长的1/8到1/4分箱数量16或32细节模糊时增加过少丢细节过多对噪声敏感去直流必须做—不做会造成熵值虚高3. 完整代码实现与逐步讲解3.1 信息熵计算子函数的编写我们先把核心的熵值计算封装成一个函数这样主程序里只需要循环调用逻辑清晰也好调试。我习惯把它写成独立的m文件文件名calcEntropy.m输入一段信号向量和分箱数量输出一个熵值。function ent calcEntropy(signalSegment, numBins) % 计算一维信号片段的信息熵 % 输入: signalSegment - 当前窗口的信号向量 % numBins - 幅值分箱数量 % 输出: ent - 信息熵值(bit) % 确保输入为列向量 signalSegment signalSegment(:); % 去除直流分量(在调用前处理也行,这里再做一次保险) signalSegment signalSegment - mean(signalSegment); % 幅值范围 minVal min(signalSegment); maxVal max(signalSegment); if maxVal minVal % 完全平坦的信号,熵定义为0 ent 0; return; end % 幅值区间边缘 edges linspace(minVal, maxVal, numBins 1); edges(end) edges(end) 1e-12; % 确保最大值被包含进最后一箱 % 统计频率 counts histcounts(signalSegment, edges); probs counts / sum(counts); % 去掉概率为0的箱子,避免log2(0)报错 probs probs(probs 0); % 信息熵 ent -sum(probs .* log2(probs)); end这个函数有几个细节值得展开说明。第一为什么用histcounts而不是手写循环统计因为MATLAB向量化运算远比循环快尤其窗口数量动辄上千个每个窗口都要调用统计向量化能省下不少时间。第二edges(end) edges(end) 1e-12这一句是处理边界问题的经典技巧不加的话最大值样本会落在最后一个区间之外导致统计总和少一个点。第三概率为0的箱子必须过滤掉否则log2(0)会产生无穷大警告虽然信息论上0概率的事件不贡献熵值但MATLAB可不会自动帮你跳过。3.2 主程序滑动计算整个信号的熵值曲线写好了熵值函数主程序就是把窗口沿着信号逐步挪动。我提供一个可以直接复制的模板你只需要改文件路径和参数。% 滑动窗口法计算声发射信号信息熵曲线 % 适用于一维声发射波形数据,输出熵值曲线并保存图片 clear; close all; clc; %% 1. 加载数据 % 以CSV为例,第一列为时间,第二列为幅值 % 如果你的数据是单列幅值,请相应调整 filename your_ae_data.csv; dataTable readmatrix(filename); time dataTable(:, 1); signal dataTable(:, 2); % 去除整体直流分量 signal signal - mean(signal); %% 2. 参数设置 fs 10000; % 采样率(Hz),根据实际采集设置 windowLen 2048; % 窗口长度(采样点数) stepLen 256; % 滑动步长(采样点数) numBins 32; % 幅值分箱数量 %% 3. 滑动计算信息熵 nSamples length(signal); nWindows floor((nSamples - windowLen) / stepLen) 1; entropyCurve zeros(1, nWindows); windowCenterTime zeros(1, nWindows); for i 1:nWindows startIdx (i - 1) * stepLen 1; endIdx startIdx windowLen - 1; segment signal(startIdx:endIdx); entropyCurve(i) calcEntropy(segment, numBins); windowCenterTime(i) (startIdx endIdx) / 2 / fs; end %% 4. 绘制结果 figure(Position, [100, 100, 800, 500]); plot(windowCenterTime, entropyCurve, b-, LineWidth, 1.5); xlabel(时间 (s)); ylabel(信息熵 (bit)); title(声发射信号滑动窗口信息熵曲线); grid on; %% 5. 保存图片 outputDir results; if ~exist(outputDir, dir) mkdir(outputDir); end exportgraphics(gcf, fullfile(outputDir, entropy_curve.png), Resolution, 300); disp([计算完成,共处理窗口数: , num2str(nWindows)]);先说循环部分。nWindows的计算公式floor((nSamples - windowLen) / stepLen) 1是滑动窗口最核心的下标逻辑意思是从信号起点开始每次移动stepLen个点取一个窗口直到窗口末端超出信号长度为止。这里用的是“最后一个不完整窗口直接丢弃”的策略因为如果硬把不足windowLen的尾部数据补零补出来的全是假数据计算出来的熵值没有物理意义。丢掉尾部一点数据损失的信号长度最多不超过stepLen完全不影响整体曲线趋势。再说绘制和保存。我在这里用exportgraphics而不是MATLAB老版本的saveas因为saveas保存的是屏幕显示分辨率放大或者缩小图形窗口都会改变实际像素稍微复杂点的图放大后边缘模糊。exportgraphics能独立指定300dpi输出适配论文插图要求这个函数在R2020a及以后版本都支持如果还在用旧版本可以改成print(gcf, -dpng, -r300, results/entropy_curve.png)效果等价。4. 图片保存功能的灵活使用与常见扩展4.1 三种主流保存方式的对比与取舍很多初学者在保存图片这一步卡住主要是不清楚saveas、print和exportgraphics三者的区别。我直接给个对照表你按需选择。方法优点缺点推荐场景saveas(gcf, name.png)语法简单老版本兼容分辨率跟随屏幕放大模糊快速记录界面print(gcf, -dpng, -r300, name.png)支持300dpi输出兼容性好参数多容易记混常规论文插图exportgraphics(gcf, name.png, Resolution, 300)清晰度高自动裁剪空白需要R2020a正式报告、期刊图如果你用的是2020a之后版本我强烈推荐exportgraphics。它处理白色背景和图形边距的方式比print更智能不会在图片四周留大片空白这在插入Word或LaTeX时会省不少排版功夫。另外exportgraphics还可以直接输出PDF矢量格式exportgraphics(gcf, entropy_curve.pdf, ContentType, vector)矢量图在论文里缩放不失真审稿人看了都舒服。在批量处理多组试验数据时还有一个实用技巧把文件名和试验编号关联起来。比如我有三个试件数据文件分别叫specimen1.csv、specimen2.csv、specimen3.csv程序可以循环处理并把图片命名为specimen1_entropy.png避免手动改文件名导致覆盖或混淆。4.2 图片风格与标注的细节处理保存图片前建议先对图窗属性做一些设置不要让MATLAB默认的灰白背景直接输出。我通常加几行配置让线条更清楚、坐标轴更紧凑set(gca, FontName, Times New Roman, FontSize, 11, LineWidth, 0.8); set(gcf, Color, white); xlim([min(windowCenterTime), max(windowCenterTime)]);另外如果同一张图里需要叠加多条工况的熵值曲线做对比可以改用hold on分别plot并用legend标注数据来源。我的习惯是先画一组试件的曲线观察整体形态再叠加其他试件用不同颜色和线型区分。这个时候图例的字体和位置要调整推荐放在右上角或者曲线稀疏的区域避免遮挡关键拐点。针对声发射信号还有一个实用扩展在熵值曲线上叠加能量变化曲线或者事件率曲线。做双y轴图可以直观看到熵值升高和能量释放是否同步我经常用这个方式辅助判断损伤阶段。代码上就是yyaxis left和yyaxis right不算复杂但表达效果比单独画两张图强很多。5. 参数影响实测与结果验证5.1 窗口长度对曲线形态的直观影响为了让你对参数选择有更具体的感知我用一组实际采集的声发射数据做了对比试验。信号总长度约50秒采样率10kHz包含三个阶段初期平稳、中期突发活跃、后期衰减。分别用512、2048、8192三种窗口长度计算熵值曲线步长都取窗口长度的1/8分箱数32。窗口长度512时熵值曲线非常“碎”几乎每个窗口都大幅波动很难分辨出阶段边界这种曲线用在报告里说服力不足。窗口长度2048时曲线平滑度明显提升三个阶段的过渡点清晰可见而且活跃阶段的熵值峰值时间和事件记录表对得上。窗口长度8192时曲线过度平滑阶段边界被磨圆突发活跃的细节被压缩成一个小凸起信息丢失比较严重。这个对比也印证了前面的建议先按时间尺度确定窗口长度的量级再微调参数。5.2 分箱数量对熵值绝对数值的影响分箱数量不会改变曲线的形状趋势但对熵值的绝对大小影响很大。我用同一段信号分别用8、16、32、64箱计算结果熵值整体随着分箱数量增大而上移。原因也好理解分箱越多每个箱子的概率分布越细不确定性表达得越充分熵值上限更高。但需要注意如果分箱数增多导致很多箱子只有一两个样本点那些概率事件虽然熵值贡献小却会让结果变得不稳定。我的建议是在同一批试验数据中固定分箱数量重点关注熵值曲线的相对变化和拐点位置而不是纠结熵值的绝对大小。跨数据集对比时一定要确保所有数据都用相同的分箱数和窗口参数否则对比没有意义。这一点在写论文时尤其重要方法学的可复现性全靠这些参数定义明确。6. 常见问题与排查技巧实录6.1 报错与异常快速对照跑程序过程中最常见的几个问题我按“现象-原因-解法”列成表格方便直接排查。现象常见原因解决方案histcounts报错“edges must be nondecreasing”信号全为相同值或NaN检查数据是否包含NaN改用去NaN后的有效数据若信号全平直接赋熵值为0log2(0)产生警告未过滤零概率箱子按3.1代码过滤probs probs(probs 0)输出图片为全空白设置了visible off或图窗被关闭绘制前确保figure存在用exportgraphics保存时机在绘制后计算循环非常慢窗口数量大且未预分配数组预分配entropyCurve和windowCenterTime避免动态增长熵值曲线整体平移未去直流或幅值分箱范围因漂移而变化每次窗口计算前也去做均值归零保证所有窗口在相同幅值尺度上统计6.2 几个容易踩坑的细节第一个坑是加载数据时忽略了非数值列。很多采集软件导出的CSV除了数据还带单位行或注释直接用readmatrix会报错或者读出来全是NaN。我习惯先打开CSV看一眼确定数据从第几行开始然后用readmatrix(filename, NumHeaderLines, n)跳过。第二个坑是窗口末端溢出。有些版本的程序为了处理尾部数据会在信号后面补零我强烈不建议这样做。补零会使尾部窗口混入大量幅值为0的点信息熵会被严重拉低形成一段假的“下降尾迹”。如果采集到的信号尾部本身就是衰减阶段补零处理会把真实衰减和人为补零混在一起干扰判断。第三个坑是保存图片时没有指定路径就报错。如果你直接写exportgraphics(gcf, entropy.png)默认保存到当前工作目录如果当前目录没有写入权限就会失败。稳妥做法是先用mkdir创建结果文件夹再把完整路径拼接出来代码里我已经写好了这个逻辑。第四个坑是下标类型不匹配。用readmatrix读进来的数据默认是double但如果你的信号数据量超过MATLAB的普通索引范围在循环中反复做startIdx:endIdx切片时效率会下降。针对超长信号可以考虑把信号分段读入或者用memmapfile不过对大部分声发射实验数据来说十几万到几百万个采样点直接处理完全没问题。7. 后续扩展的几点个人建议程序能跑通只是第一步真正要把它做成一个可复用的分析工具我建议再花点时间做三件事一是封装成函数把数据加载、参数设置、计算、画图、保存拆成独立的模块方便换数据直接调用二是加上批处理循环一次性处理一个文件夹里的所有试验文件输出汇总曲线图三是把结果导出成结构化数据比如把时间轴和熵值曲线写入CSV方便用Origin或Python做进一步统计。我在实际使用中还养成了一个习惯每次调整完参数就顺手把参数记录到图片的文件名里比如entropy_w2048_s256_b32.png这样后期整理结果时清楚每张图对应什么参数不需要重新翻代码。如果只是自己调试可以直接在命令行把参数显示出来但一旦要作为论文存档图这种命名方式能省去大量回忆成本。这个手册里的代码框架我已经在多种类型的数据上验证过包括连续型声发射信号、分段加载实验数据以及模拟的突发型信号。总体感觉是稳定省心只要在参数设置上多花点心思输出结果基本可以直接用于报告和论文配图。如果你在实际运行中遇到上面没覆盖到的问题可以沿着表格里的排查思路试一遍绝大多数都是数据格式和边界条件的问题。
网站建设高端定制企业官网