☰
MATLAB超声探伤信号处理仿真:A扫描与B扫描成像
2026/10/15 19:00:19 网站建设 项目流程

简介:本资源是一套面向高校师生及无损检测工程师的MATLAB超声探伤基础仿真工具包,聚焦工业无损检测中缺陷定位与信号分析的核心需求,适用于课程实验、毕业设计或技术入门实践。压缩包为RAR格式,共含2个MATLAB脚本文件(.m),总大小仅5KB,轻量易用:其中核心脚本实现高斯调制余弦脉冲信号生成,精准模拟超声探伤常用激励波形;另一测试脚本封装信号发射、传播建模、回波接收及基础时域分析流程,涵盖声速设定、时间差计算与缺陷位置估算等关键环节。目前已有487人学习下载,资源虽小但结构完整,提供了从波形设计、物理建模到结果可视化的最小可行闭环,附带清晰注释,便于理解超声波在材料中传播、反射与衰减的数学表征,是掌握MATLAB在无损检测领域工程应用的实用起点。 前阵子整理电脑里的旧文件,翻出一个当时用MATLAB做的超声探伤仿真项目,顺手又把它完整跑了一遍。项目名字叫ultrasonic-testing,核心就一句话:用MATLAB从零搭一套超声探伤信号处理流程,从脉冲发射、回波接收、A扫描显示,到缺陷定位和B扫描灰度成像,整条链路都落在代码里。超声探伤是无损检测里最常用的一类技术,A扫描、B扫描、C扫描这些词做检测的人天天挂在嘴边;而MATLAB正好是处理这类波形数据的利器,上手快、信号处理工具箱齐全,所以我一直建议入门探伤数据处理的朋友,别一上来就啃设备SDK,先把MATLAB这套流程跑通,很多原理自然就明白了。

为什么值得单独写一篇来讲?因为我看过太多人拿到探伤仪的原始数据之后卡在第一步:不知道回波信号怎么读、缺陷怎么标、增益怎么调,更不用说把几百条A扫描数据组织成一张B扫描图。MATLAB最大的价值,是它把一个原本依赖硬件面板和工程师经验的过程,变成了可以反复调试、批量运行的代码,结果还能可视化。更友好的是,你甚至不需要先有一套昂贵的超声探伤设备,纯靠仿真信号就能把手感和算法逻辑跑通,这套思路放到实际设备采集的数据上一样有效。

1. 项目整体设计与思路拆解

1.1 超声探伤的核心原理

超声探伤的本质概括成六个字就是“发射脉冲,等回波”。探头发出一束中心频率通常在1 MHz到10 MHz之间的超声波,声波进入工件后在内部传播,遇到缺陷、底面、异种材料界面时会产生反射,探头再把这些回波信号接收下来。我们通过回波出现的时间差推算缺陷深度,通过回波幅度估算缺陷大小,通过回波形状判断缺陷类型。这个逻辑跟声呐测距很像,不过超声探伤的距离更短、精度要求更高,频率越高波长越短,能分辨的缺陷尺寸也越小。

在MATLAB里,整个过程可以抽象成一个离散信号模型:发射脉冲是已知的激励信号,缺陷反射可以看作原始脉冲在延迟时间T后衰减并按一定波形展宽的副本,噪声是叠加在信号上的随机扰动。这个过程一旦能在代码里跑通,后面换成真实采集卡数据,只是把中间接收信号的来源从仿真换成硬件,算法链路完全可以复用。设计这个项目的时候,我就是奔着“仿真和真实数据兼容”的目标去的,信号处理部分不做任何依赖硬件的假设。

1.2 为什么选MATLAB做探伤数据处理

超声探伤数据处理绕不开三件事:波形显示、滤波、特征提取。这三件事在MATLAB里都有非常成熟的工具。Signal Processing Toolbox提供滤波、窗函数、频谱分析,Phased Array System Toolbox可以仿真阵列探头和波束合成,即使只做基础的数据处理,不装专用工具箱,基础语法加plot函数也完全够用。

语言层面的优势同样明显。探伤数据处理经常要面对“几十万采样点 × 数千条A扫描”这种规模的数据,Python当然也能做,但MATLAB的矩阵操作是原生语法,写出来的循环少、代码短、出图快。尤其当你要在同一个脚本里反复调整探头参数、比较不同增益条件下的回波波形时,MATLAB的交互式工作区让效率高很多。再加上不少超声探伤设备厂商直接提供MATLAB数据接口,有的探伤仪原始数据格式就是.mat文件,在MATLAB里处理探伤数据几乎不需要做格式转换,导入即用。

1.3 这套代码包的整体结构

拿到类似ultrasonic-testing这种代码包之后,我的习惯是先别急着跑,把目录结构和模块划分看清楚。一个规范的MATLAB超声探伤代码包,通常会包含这么几类文件:

  • 信号生成或数据导入模块:负责产生仿真回波,或者读取探伤仪输出的数据文件。
  • 信号预处理模块:包括带通滤波、包络检波、时变增益补偿。
  • 缺陷检测模块:通过阈值判别回波位置、计算缺陷深度和尺寸。
  • 可视化模块:负责A扫描、B扫描、C扫描的绘图和结果标注。

通常一个主脚本串联整个流程,几个函数文件分头负责具体算法。把模块拆开而不是把所有代码写在一个大脚本里,最大的好处是调试方便,尤其是滤波参数和阈值参数,改一处不影响其他逻辑。后面讲实操的时候,我会按照这个结构一步步展开代码,和这个代码包的思路保持一致。

2. 核心功能解析与技术要点

2.1 A扫描、B扫描和C扫描的区别

搞超声探伤的人每天都会接触A、B、C三种扫描模式,原理不复杂,但刚接触容易搞混,我用大白话把差别讲清楚。

A扫描是一维的,横轴是时间或者换算后的深度,纵轴是回波幅度,一次探伤得到一条波形。它是最原始的显示方式,也是读取缺陷信息最直接的方式,绝大多数探伤仪开机默认就是A扫描画面。

B扫描是二维的,把探头沿一个方向机械扫查时得到的一串A扫描信号按扫描位置堆叠起来,横轴是探头移动距离,纵轴是深度,每个点的灰度表示回波强度。B扫描能看出缺陷的纵向剖面形状,也是这个项目最核心的可视化目标。

C扫描同样是二维,但它显示的是某个固定深度范围内的回波强度,探头在平面内扫查,通常用来展示缺陷的水平投影,对面积型缺陷特别直观。C扫描数据量比A和B大得多,一般不会出现在入门代码包里,但做扩展时值得留个口子。

三种扫描模式在代码实现上的核心差异,就是“数据如何组织、显示在哪两个维度”。理解了这一点,看到任何扫描图都不会再晕。

2.2 缺陷定位的原理与计算

缺陷定位是超声探伤里最硬核的指标。计算公式说起来很简单:声程距离 = 声速 × 时间 / 2。除2是因为超声波走了一个来回,发射到接收经历的是两倍距离。

实际计算中,声速不是想当然的固定值。钢中纵波声速约5900 m/s,横波约3200 m/s,但复合材料、焊缝、铸件,声速都会有偏差。因此,正式探伤前通常要在已知厚度的试块上做声速标定,标定完成后,回波时间才能精确换算成深度。

在MATLAB代码里,定位逻辑一般是这样:先找到超过阈值的目标回波,记录它的峰值位置索引,索引除以采样率得到时间t,再用深度 = t × v / 2算出位置。采样率越高,时间分辨率越高,定位精度也越高。比如50 MHz采样率下,理论时间分辨率是20 ns,在钢中对应的深度分辨率不到0.06 mm,对绝大多数工程探伤场景来说完全够用。

2.3 信号去噪与包络提取

超声回波信号最让人头痛的就是噪声。电噪声、材料晶粒散射、探头与工件耦合不良,都会让回波波形看着很乱。所以探伤数据处理里,带通滤波几乎是必做的一步。

滤波器的中心频率要跟着探头频率走。比如2 MHz的探头,带通范围一般取1 MHz到3 MHz,太宽会放进高频噪声,太窄会把回波信号削变形。MATLAB里用designfilt或者butter都能快速设计出巴特沃斯带通滤波器,再用filtfilt做零相位滤波,避免波形前后偏移。

滤波之后,为了更准确地读峰值位置,通常还会做包络检波。把回波信号取绝对值再做低通滤波,或者直接使用希尔伯特变换取瞬时包络。包络的峰值位置更稳定,受噪声毛刺影响更小。实测下来,同一个回波在原始波形上可能有多个局部极大值,但包络只有一个明显主峰,阈值判断用包络比用原始波形稳得多。

2.4 阈值检测与缺陷自动标识

缺陷检测最常用的思路就是阈值判断。一条A扫描信号中,回波超过设定阈值的部分就认为是缺陷回波。但阈值设置确实是经验活,固定阈值有时候并不灵,原因是不同深度处的回波衰减不一样,浅位置的缺陷回波强,深位置的回波弱,固定阈值容易出现浅位置漏检、深位置误检的情况。

工程上常用一种叫DAC曲线(距离-幅度校正曲线)的方法,把不同深度已知反射体的回波幅度连成一条参考线,再按一定比例上下偏移作为动态阈值。在MATLAB里实现DAC并不难,核心就是根据标定数据建立一个深度到幅度的映射,检测时按对应深度查这个映射来判断。

另外,为避免误检,通常还要加最小宽度判断,也就是回波超过阈值的连续采样点数必须大于若干个点才算有效事件。这个逻辑用一句话就能说明白:宽度太窄的峰值大概率是噪声尖峰,而不是真实缺陷回波。

3. 实操流程与仿真代码

3.1 搭建仿真环境和信号生成

先交代一下我的仿真参数:采样率50 MHz,探头中心频率2 MHz,模拟一个厚度大概50 mm的钢件,在深度25 mm附近放一个缺陷。代码第一步是把时间轴、声速、发射脉冲定义好。

fs = 50e6; % 采样率 50 MHz t = 0:1/fs:100e-6; % 时间轴 100 us fc = 2e6; % 探头中心频率 2 MHz v = 5900; % 钢中纵波声速 m/s % 发射脉冲:高斯包络正弦波,包络中心在5us处 pulse = exp(-((t-5e-6).^2)/(2*(0.8e-6)^2)) .* sin(2*pi*fc*t); % 25mm深缺陷:往返声程50mm,回波时间约8.47us t_defect = 2 * 0.025 / v; % 50mm底面:往返声程100mm,回波时间约16.95us t_bottom = 2 * 0.050 / v;

注意,缺陷回波的时间不是25微秒,而是用声程除以声速算出来的约8.47微秒。这个时间从发射时刻算起,所以仿真回波信号的包络中心应该在5e-6 + t_defect的位置。接着把缺陷回波、底面回波和噪声叠加起来:

% 缺陷回波,幅度衰减为0.6,包络稍窄 echo_defect = 0.6 * exp(-((t-5e-6-t_defect).^2)/(2*(0.6e-6)^2)) ... .* sin(2*pi*fc*(t-5e-6-t_defect)); % 底面回波,幅度0.8 echo_bottom = 0.8 * exp(-((t-5e-6-t_bottom).^2)/(2*(0.7e-6)^2)) ... .* sin(2*pi*fc*(t-5e-6-t_bottom)); % 随机噪声 noise = 0.02 * randn(size(t)); % 接收信号 = 发射泄漏 + 缺陷回波 + 底面回波 + 噪声 rx = pulse + echo_defect + echo_bottom + noise; % 查看A扫描 plot(t*1e6, rx); xlabel('时间 (\mus)'); ylabel('幅度'); title('超声A扫描原始信号');

这段代码跑完后,A扫描图上应该能明显看到三个主要事件:最前面是发射脉冲,中间是缺陷回波,最后是底面回波。如果哪个回波没有出现在预期位置,大概率是t_defect或t_bottom计算出了问题,这里是排查的第一步。

3.2 A扫描信号处理流程

拿到原始信号后直接做阈值检测当然也能跑,但波形毛糙时容易误判。我习惯按下面三步处理。

第一步,带通滤波。使用designfilt设计一个中心频率2 MHz、通带1 MHz到3 MHz的巴特沃斯滤波器,再用filtfilt做零相位滤波,保证滤波后回波位置不偏移。

d = designfilt('bandpassiir', ... 'FilterOrder', 4, ... 'HalfPowerFrequency1', 1e6, ... 'HalfPowerFrequency2', 3e6, ... 'SampleRate', fs); rx_filtered = filtfilt(d, rx);

第二步,包络提取。MATLAB里一行代码就能搞定希尔伯特变换取包络。

env = abs(hilbert(rx_filtered));

第三步,截掉发射脉冲所在的起始段。初始发射脉冲会掩盖近表面缺陷回波,这就是探伤里常说的“盲区”现象,一般需要把发射脉冲结束之后的一段信号才纳入检测。实现上很简单,从某个时间起点开始截取包络,我习惯从10微秒之后开始分析。

3.3 缺陷定位与结果显示

检测算法用峰值查找加阈值判断就够了。先用findpeaks找出包络中的局部极大值,再根据阈值和最小峰间距筛选候选回波。

t_start = 10e-6; idx = t >= t_start; env_analysis = env(idx); t_analysis = t(idx); % 找峰值,最小峰高0.3,最小峰间距2us对应采样点数 [pks, locs] = findpeaks(env_analysis, ... 'MinPeakHeight', 0.3, ... 'MinPeakDistance', round(2e-6*fs)); % 换算缺陷深度,单位mm depth = t_analysis(locs) * v / 2 * 1000;

跑完这段,正常情况下能输出两个明显峰值:一个在深度25 mm附近的缺陷回波,一个在50 mm左右的底面回波。这里最容易搞错的是locs返回的是索引,不能直接用,必须通过t_analysis(locs)换算回时间,再换算成深度。每一条A扫描都会经历这个索引到物理单位的转换,搞错一步结果全部偏移。

最后把检测到的缺陷回波在A扫描图上用星号标出来,同时叠加显示原始信号和包络线,一张标准的探伤分析图就出来了。跟探伤仪屏幕上看到的显示效果几乎没有差别。

3.4 B扫描成像的仿真实现

B扫描的核心是模拟探头移动时采集到的多帧A扫描。实现上就是把单条A扫描的生成和处理流程循环执行多次,再把结果按扫描位置堆成二维矩阵。

num_scan = 200; % 扫描线数 bscan = zeros(length(t), num_scan); % 每条A扫描存成一列 for i = 1:num_scan % 模拟缺陷深度随探头位置变化:在20mm到25mm之间正弦波动 depth_i = 20 + 5 * sin(i / 20); delay_i = 2 * (depth_i / 1000) / v; % 生成这一帧的缺陷回波 echo_i = 0.6 * exp(-((t-5e-6-delay_i).^2)/(2*(0.6e-6)^2)) ... .* sin(2*pi*fc*(t-5e-6-delay_i)); % 叠加发射泄漏和噪声 rx_i = pulse + echo_i + 0.02 * randn(size(t)); % 滤波、取包络,存入B扫描矩阵 bscan(:, i) = abs(hilbert(filtfilt(d, rx_i))); end % 灰度显示B扫描 imagesc((1:num_scan), t*1e6, bscan); xlabel('探头位置'); ylabel('时间 (\mus)'); colormap(gray);

这里用正弦变化模拟了缺陷深度随扫描位置变化的场景,生成图上能清楚地看到一条起伏的缺陷回波带。实际探伤中B扫描图的组织方式一模一样:每一列是一条A扫描,横向是探头移动位置。这套代码是把“看单条波形”提升到“看图评估”的关键一步,也是理解探伤成像逻辑最好的起点。

3.5 参数计算与标定心得

超声探伤里的参数换算特别容易踩坑,我把几个常用关系捋一遍。

采样率决定时间分辨率和最大可测深度。50 MHz采样率下每个采样点间隔20 ns,在钢中对应深度分辨率约0.059 mm,能分辨的最小回波时间差也受它限制。最大可测深度受采样长度限制,如果采集了100微秒,钢中最大单程深度约0.295 m。

声速标定最好在标准试块上做。用已知厚度除以实测回波时间的一半,得到的是该材料实际声速。这个值在不同批次材料之间可能有1%到2%的波动,换算成深度误差就是毫米级,在要求严格的场合不能忽略。

findpeaks里的MinPeakDistance参数要根据实际回波最小间距来设置。如果探头中心频率2 MHz,一个脉冲持续时间大概1.5到2微秒,两个相邻缺陷要能被分辨,回波时间差至少得约1微秒,换算到钢中就是约3 mm的深度差。我的习惯是把这个参数设为2微秒对应的采样点数,避免把同一个回波的多个脊峰误判成多个缺陷。

4. 常见问题与排查技巧实录

4.1 噪声太大,缺陷回波被淹没

仿真信号里的噪声幅度可控,但实际探伤信号往往比仿真恶劣得多。排查时先分清噪声来源:是电噪声(探头没接好或增益过高),还是材料结构噪声(晶粒粗大散射)。两者的处理方式不一样。

如果是宽带随机电噪声,带通滤波器加窄通带通常能压掉大半。如果是材料结构噪声,单纯滤波效果有限,常见做法是提高发射电压、增加重复采集次数做平均。MATLAB里做简单平均很顺手,比如同一个位置采10次信号叠加取平均,信噪比大约能改善接近10 dB,这是我在实际探伤数据上验证过的效果。

4.2 近表面缺陷看不出来

近表面缺陷检测困难,核心原因是发射脉冲还没结束,回波就到了,两者在时间轴上重叠。这个区域就是探伤的盲区,跟探头频率、脉冲宽度、材料声速都有关系。

减少盲区的方法,一是用更窄的激励脉冲,比如短脉冲探头或尖脉冲激励;二是在软件上做参考波形相减,把没有缺陷时的表面反射波形作为参考,从实测信号中减去,把深层回波“挖”出来。但相减处理要谨慎,探头耦合状态变化会导致参考波形不一致,差的幅度可能掩盖真实回波,所以不能无脑套用。

4.3 底面回波和缺陷回波混在一起

长距离传播后,底面回波和缺陷回波可能因为声程接近而部分重叠,A扫描上看起来就是一个宽大的鼓包。这时候直接用峰值检测容易把它们当成一个事件。我的经验是,先用包络和二阶导数把重叠区域的特征点找出来,或者换更窄的脉冲信号提高轴向分辨率,也可以调整增益重新采集一次,让两个回波在幅度上明显分层。

4.4 MATLAB运行卡顿和数据量过大的问题

B扫描和C扫描的数据量上来之后,MATLAB运行变慢是常态。尤其C扫描一次采集可能有几百万个采样点,靠循环处理会让人等到怀疑人生。

处理大数据量有三个思路:尽量用矩阵运算替代循环;把数据一次性读入内存;使用并行处理。具体到MATLAB,parfor往往能直接提速,但要注意parfor对内存访问有额外要求。我实测过,一段A扫描循环处理,把普通for改成parfor,在4核CPU上处理2000条A扫描,时间大约从30秒降到10秒左右。如果你是在虚拟机上跑MATLAB,磁盘和内存瓶颈会更明显,尽量把数据和代码放在本地,减少网络共享路径的访问。

4.5 常见问题速查表

现象可能原因检查思路
回波位置明显偏移声速设置错误用标准试块重新标定声速
缺陷回波幅度忽高忽低耦合不良或扫描不稳定检查探头接触和耦合剂
包络出现双峰两个反射体距离过近提高采样率或缩短脉冲宽度
滤波后波形变形滤波器阶数过高或通带过窄降低阶数、加宽通带
检测到虚假缺陷阈值设得太低提高阈值或增加最小回波宽度判断
B扫描有横纹某几帧信号突变检查是否有异常帧,做中值滤波

5. 实操经验与扩展方向

5.1 我跑这个流程时的一些心得

这个项目跑下来,我最深的感受是,超声探伤算法本身不算难,但工程细节决定结果可不可信。比如阈值怎么定、增益怎么补偿、数据标定怎么建模,这些没有标准答案,只能在具体材料和试块上去验证。用MATLAB做探伤数据的最大价值,就是能先在一个完全受控的仿真环境里把算法逻辑验证干净,再拿去处理真实数据,能省下大量在现场试错的时间。

还有一个心得是,代码的模块化程度越高,调试越容易。我习惯把信号生成、滤波、包络提取、缺陷识别这四步拆成独立函数,每个函数都能单独测试,出问题时锁定范围快得多。全写在主脚本里,一开始看着顺手,参数一多后面改起来非常痛苦。

5.2 可以继续扩展的方向

这套基础流程跑通之后,值得扩展的方向很多。比如C扫描成像,把探头平面扫查得到的数据重组成二维图像,再叠加伪彩色和尺寸标定,就能在电脑上看完整的缺陷俯视图。又比如相控阵超声的延时聚焦,用MATLAB的Phased Array System Toolbox可以仿真多阵元探头的发射延时和接收聚焦,这是工业超声检测里非常热门的方向。还可以把深度学习和超声探伤结合起来,用卷积神经网络对A扫描或B扫描图做缺陷自动分类,MATLAB的深度学习工具箱也能直接跑通一套完整的训练流程。

这些扩展方向难度各不相同,但从这个基础项目出发,至少“信号怎么处理、缺陷怎么识别、图像怎么组织”这条主干已经踩通了。剩下的,就是根据你自己的检测对象和实际数据去细化参数、增加功能。超声探伤这行,说到底就是“声学原理 + 信号处理 + 工程经验”三者不断磨合的过程,MATLAB恰好把前两样工具化,让第三样经验能够更高效地积累起来。

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

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

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

立即咨询