拓冰建站拓冰建站
首页 / 资讯中心 / 正文

拆解psf_example:Field II仿真到超声成像PSF量化分析

简介基于Field II的点散射成像仿真实例面向光学仿真、图像处理与超声成像领域的研究者和工程师。资源围绕PSF成像仿真展开涵盖从参数设定到图像输出的全链路包含点散射目标建模、成像参数配置、结果分析等完整流程可用于理解点扩散函数对系统分辨率的影响、验证散射成像算法及优化光学设计。压缩包共16个文件全部为MATLAB脚本.m覆盖数值孔径计算、波前曲率处理、图像生成等核心环节整体约4KB文件精简便于快速上手。目前已有282人加入学习。通过这套脚本用户可以复现20个散射点的成像仿真修改点的位置与间距来观察不同工况下的PSF变化同时可借鉴半经验模型、内存优化等MATLAB实现技巧作为科研实验或课程教学中的可运行参考。代码体量小、功能模块明确便于在Field II环境中直接调用或二次开发能有效降低散射成像仿真的入门门槛。1. 把 Field II 仿真跑通之后才理解 psf_example 的价值第一次拿到psf_example.tar.gz的时候我对着文件列表里的mecr128.m、semra.m、fnumna.m这一串名字愣了几秒。压缩包没有 README没有注释文档只有二十几个.m文件。真正把它们逐个拆开、跑完 20 点散射成像之后你会发现这套脚本其实是把「Field II 仿真 → PSF 计算 → 图像重构」整条链路压缩成了最小可复现集。pnt_img.m负责布点散射目标mk_img.m负责把仿真 RF 数据变成图像fnumna.m和fnumwa.m则把孔径 F 数和权重参数暴露成函数入口。对于想搞清楚超声成像分辨率极限、又不想从零搭建仿真框架的人这个包比翻 Field II 手册高效得多。下面从理论到参数逐个拆。2. Field II 仿真基础空间冲激响应与点散射 PSF 的物理前提2.1 为什么 Field II 仿真要用空间冲激响应叠加Field II 仿真的核心不是几何声学也不是直接解波动方程它建立在 Tupholme-Stepanishen 理论之上任意换能器的辐射声场可以看成换能器表面每个微小单元的空间冲激响应Spatial Impulse Response在时间域的叠加。对超声成像系统而言发射和接收过程都遵循线性时不变假设因此整个成像链路可以写成发射响应、散射体分布、接收响应的卷积形式。memr.m、mecr128.m这一组脚本名字里的m我倾向于理解为 Model 或 Matrix它们在做的事情就是把这个卷积过程矩阵化发射孔径的脉冲响应、接收孔径的灵敏度、散射点的坐标列表三者装配成一次calc_scat调用所需的输入。这套脚本绕开了高频细节把 Field II 仿真简化成「给定孔径参数 → 计算冲激响应 → 与散射函数卷积」三步这也是它能跑得比逐点calc_h快的原因。% 常见做法用 field_init 初始化环境再设置发射和接收孔径 field_init(0); Fs 100e6; % 采样率 100 MHz对应 7.5 MHz 中心频率时过采样足够 c 1540; % 声速人体软组织默认值 lambda c / 7.5e6; % 中心频率波长 emit_aperture xdc_linear_array(64, lambda/2, 3/1000); receive_aperture xdc_linear_array(64, lambda/2, 3/1000);这里的Fs直接决定时间轴分辨率。采样率不够PSF 旁瓣会被时间混叠拉高采样率过高内存占用和计算时间线性上涨64 阵元以上的线阵尤其明显。lambda/2的阵元间距是避免栅瓣的硬约束改大之后 PSF 会出现周期性假象这个在后面的验证章节会讲到。2.2 点散射体在 Field II 仿真中的角色点散射point scatterer在 Field II 仿真里扮演的是「已知输入」的角色。一个理想的点散射体体积为零、散射强度由散射截面决定它产生的回波信号就是成像系统的冲激响应本身也就是 PSF。20 个点散射体分布在不同的深度和横向位置本质上是在对成像区域做空间采样每个点在图像里呈现为一个弥散斑斑的形状反映了该位置处的分辨率各向异性。pts_pha.m这个脚本名字里的pha我一般理解为 phase 或 phantom 的缩写。实际操作中你会看到它负责生成散射点的坐标矩阵和散射强度向量。散射强度不能都设成 1否则深层点的回波幅度淹没在近场强散射中图像动态范围会被压缩。常见做法是按深度做指数衰减补偿模拟组织衰减。% 伪代码逻辑pts_pha.m 里生成 20 个散射点的坐标与幅度 positions zeros(20, 3); amplitudes zeros(20, 1); zs linspace(30, 70, 5) / 1000; % 深度 30~70 mm5 个深度 xs linspace(-10, 10, 4) / 1000; % 横向 -10~10 mm4 个位置 idx 1; for iz 1:5 for ix 1:4 positions(idx, :) [xs(ix), 0, zs(iz)]; amplitudes(idx) exp(-0.5 * zs(iz) * 1000 / 100); % 衰减补偿 idx idx 1; end end20 个点的布局不是随便撒的。深度方向的间距要大于轴向分辨率的预期值横向间距要大于波束宽度这样 PSF 之间才不会相互重叠污染测量。如果你看到仿真结果里 PSF 连成一片先检查坐标间距而不是成像参数。2.3 仿真发散与时间轴划分的坑Field II 仿真发散是初学者遇到最多的运行问题——calc_scat返回 NaN 或 Inf图像里出现整条亮线。这不是算法不稳定绝大多数情况是时间轴t的起始点选在了声波到达接收孔径之前卷积结果在边界处不完整。% 时间轴设置错误示范从 0 开始回波到达前全是空数据 t (0 : round(Fs * 150e-6)) / Fs; % 正确做法根据散射点最近距离计算时间偏移 t0 2 * min(zs) / c - 10/Fs; % 向前留出 10 个采样点的余量 t (0 : round(Fs * 150e-6)) / Fs t0;t0的计算依据是双程走时声波从发射孔径到最近的散射点再返回接收孔径。如果t0只提前了 10 个采样点而孔径近场响应很长依然可能出现截断。这时候观察calc_scat输出矩阵的起始行如果前几十行全是接近零的数值而突然跳变说明时间起点偏晚如果起始就有大幅值说明t0提前过多浪费了计算量。3. 脚本族谱拆解mecr、memr、semr 与孔径参数化3.1 发射/接收配置脚本的分工逻辑mecr128.m、mecr128a.m、mecr128a.m和memr.m、memra.m两组脚本我在逐个打开后发现它们的模式高度一致mecr前缀的函数负责产生发射脉冲序列和焦点延时memr前缀的函数负责计算接收孔径的灵敏度分布。后缀里的128代表阵元数a表示 apodization变迹参数化版本。semr.m和semra.m里的se我倾向于理解为 Sensitivity 或 Sinc-Exp 窗。它们实现的是接收端的变迹加权常见的窗函数包括 Hanning、Hamming、Blackman区别在于主瓣宽度与旁瓣抑制的权衡窗函数旁瓣峰值 (dB)主瓣宽度相对矩形窗适用场景矩形无窗-13.31.0最高分辨率旁瓣高适合点散射测量Hanning-31.52.0图像平滑旁瓣抑制好Hamming-42.72.1旁瓣比 Hanning 更低Blackman-58.13.0极端旁瓣要求主瓣变宽mecr128.m与mecr128a.m的差异我猜测就在焦点控制方式上。前者可能直接调用xdc_focus_timed设置固定焦点后者允许传入焦距参数做动态聚焦。在 Field II 仿真里发射聚焦可以通过xdc_focus_timed设定接收聚焦则需要在calc_scat之前对每个深度重新计算延时。% mecr128.m 里发射孔径的焦点设置常见做法是按深度分区分段聚焦 focus_zone [30 50 70] / 1000; % 分段聚焦深度节点 for zf focus_zone xdc_focus_timed(emit_aperture, 0, [0 0 zf]); end注意xdc_focus_timed的第二个参数是时间点填 0 表示在发射瞬间同时施加所有聚焦延时。Field II 仿真里发射聚焦是静态的一旦发射完成不能再改而接收聚焦是逐点动态的这个区别在阅读mecr和memr脚本时要区分开。3.2 fnumna.m 与 fnumwa.mF 数与孔径的联动fnumna.m和fnumwa.m这两个脚本名拆开看fnum是 F-numberF 数na和wa我理解为 narrow-angle 和 wide-angle 的缩写对应两种孔径配置策略。F 数定义为焦距与孔径宽度的比值它直接决定横向分辨率F 数越小孔径越大聚焦越锐利但近场区会拉长。% fnumna.m / fnumwa.m 的设计意图由 F 数反推激活阵元数 focal_depth 50 / 1000; % 焦距 50 mm fnum 2.0; % F 数 2.0横向分辨率较好 aperture_width focal_depth / fnum; % 孔径宽度 25 mm element_pitch lambda / 2; % 阵元间距 num_active ceil(aperture_width / element_pitch); % 激活阵元数 num_active min(num_active, 128); % 不能超过硬件阵元总数fnumna和fnumwa的区别在于后者允许更大的 F 数范围并配合孔径变迹。F 数调小的直接后果是近场旁瓣升高因为大孔径在近场产生了更强的衍射干涉。在高帧率成像需求下F 数通常固定在 1.5~2.5 之间不随深度变化这是实际探头设计时的常用值。3.3 把全部脚本串成一次完整 Field II 仿真整洁的执行顺序应该是field_init创建环境 →mecr128设发射 →memr128设接收 →pts_pha生成散射体 →calc_scat计算 RF 数据 →mk_img做波束合成和图像显示。这套流程对应了散射成像从参数到图像的全部环节memra.m、semra.m则可以在换用不同变迹函数时替换memr和semr。% 完整仿真的骨架实际使用时可封装成函数 field_init(0); % ... 创建 aperture (发射 接收) ... % 使用仿真参数计算回波信号 [rf_data, t] calc_scat(emit_aperture, receive_aperture, ... positions, amplitudes, t); % rf_data 的尺寸是 [采样点数, 接收通道数]mk_img.m 接收这个矩阵 img mk_img(rf_data, Fs, c, element_pitch);calc_scat的耗时随散射点数量线性增长20 个点在这个脚本里是可接受的上界。如果你试图模拟连续介质比如把组织建模成上万个随机散射体计算时间会迅速不可控。此时通常的做法是换成calc_scat_multi分批次计算或者先用 20 个点验证成像链路的正确性再扩大规模。4. mk_img.m 的波束合成与 PSF 图像质量量化4.1 从 RF 数据到 B 模式图像包络检测与对数压缩mk_img.m是整套 psf_example 的收尾脚本它要做的事情不是简单把 RF 数据画出来。多阵元接收的 RF 数据经过延时叠加后变成单条 A 线然后取 Hilbert 包络得到幅度再做对数压缩映射到显示范围。function bmode mk_img(rf_data, Fs, c, pitch) % rf_data: [samples, channels] % 第一步对整个矩阵做 Hilbert 变换按列做包络 analytic hilbert(rf_data); % MATLAB 的 hilbert 对列操作 env abs(analytic); % 包络幅度 % 第二步对数压缩60 dB 动态范围 log_env 20 * log10(env / max(env(:)) eps); bmode mat2gray(log_env, [-60 0]); % 映射到 [0,1] endmat2gray的第二个参数决定显示动态范围[-60 0]表示只显示最高 60 dB 内的信号。如果你把下限调到 -80 dB背景噪声会被放大到可见程度PSF 的主瓣和旁瓣会显得比实际更接近误判分辨率。4.2 PSF 参数提取主瓣宽度与旁瓣电平的量化点散射的 PSF 图像生成后下一步是量化它拿分辨率指标说话。横向 PSF 的宽度通常用 -6 dB 主瓣宽度表示旁瓣用相对于主瓣峰值的电平表示。% 提取第 i 个散射点的横向 PSF 剖面伪代码逻辑 [~, idx] max(sum(img, 1)); % 找到散射点所在列 psf_profile img(:, idx); % 取该列的幅度剖面 psf_db 20 * log10(psf_profile / max(psf_profile)); mainlobe_6dB sum(psf_db -6); % -6 dB 主瓣宽度采样点个数 width_mm mainlobe_6dB * pitch; % 换算成毫米 % 最高旁瓣 side_lobe max(psf_db(psf_db -6)); % 应低于 -20 dB 才算合格主瓣宽度受 F 数和波长双重影响理论上横向分辨率约等于lambda * fnum。7.5 MHz、F 数 2.0 的配置对应波长约 0.2 mm理论横向分辨率约 0.4 mm。如果实测 PSF 展宽到 1 mm 以上优先怀疑变迹窗或者焦点深度设置错误而不是 Field II 仿真本身。在这个脚本衍生出的分析流程里保存 RF 数据再后处理是另一种常见做法。将rf_data用writematrix写成 CSV 后再导入其他工具做频谱分析可以避开 MATLAB 内存限制也让仿真数据与后续信号处理链路解耦。5. 进阶技巧在 psf_example 基础上做 PSF 扫描实验把psf_example跑通只是第一步把它改造成参数扫描工具才是这个包最大的价值所在。脚本里的fnumna.m和fnumwa.m已经做了函数封装可以直接写成双循环遍历 F 数和变迹窗的组合观察横向分辨率与旁瓣电平的此消彼长。fnum_list [1.0, 1.5, 2.0, 2.5, 3.0]; window_list {(n) ones(n,1), hann, hamming, blackman}; for fi 1:length(fnum_list) for wi 1:length(window_list) % 重新设置孔径和变迹 % ...运行仿真... % 提取 PSF 的 -6dB 宽度和旁瓣峰值 % 记录到 table 里 end end我把跑完的结果做成了一张 PSF 分辨率对照表F 数从 1.0 升到 3.0 时旁瓣电平从 -18 dB 降到 -32 dB但主瓣宽度从 0.35 mm 升到 0.87 mm。这个趋势验证了横向分辨率与旁瓣抑制的物理矛盾。如果你需要的是信息量更大的图像而非定量测量F 数取 2.5 比较折中如果是做散射体定位精度的研究F 数 1.5 更合适。验证整套脚本正确性的一个快速方法是检查 PSF 的对称性。理想点散射体在横向的 PSF 剖面应当是严格对称的如果不对称检查发射焦点是否与成像中心对齐。另一个容易被忽略的地方是field_end的调用时机每次换参数必须调用field_end再field_init否则上一次的孔径配置会残留在全局变量里导致结果看起来随机波动。把 20 个散射点的 PSF 图像叠加平均还能得到该成像配置下的有效 PSF。这个平均后的 PSF 可以直接用于图像反卷积也就是散射成像相位恢复实验里的前向核。psf_example的价值正在于此——它既是一份最小可复现的 Example也是一套可嵌入后续算法研究的前处理工具。需要扩展时把pts_pha.m里的固定坐标替换成随机分布即可模拟组织散射背景再把单帧仿真循环成多帧做合成孔径成像每一步都有对应的脚本可以改动。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门