做超声仿真这些年,我一直觉得 Field II 是个绕不开的坎。不管你是刚开始接触超声换能器设计,还是想验证波束形成、图像重建算法,绕来绕去最后都会碰它。网上关于 Field II 的教程不少,但要么是给代码让人照抄,要么只讲理论原理,真正把它从安装到实战串起来、并讲清楚中间那些坑的中文资料其实不多。这篇学习笔记就是我自己踩坑之后整理出来的,内容包括原理背景、环境搭建、三次典型仿真实验的完整代码、参数选取思路以及常见报错排查,希望能给正在入门 Field II 的同行省点时间。
这篇内容适合三类读者:一是刚接触超声成像、想在仿真平台上练手的学生;二是要做探头设计或声场分析、需要快速验证方案的工程师;三是已经跑过 demo 但总被边界条件、散射体设置和计算速度困扰的开发者。读完你至少能理解 Field II 的计算思路,并直接拿去改出自己需要的那版仿真脚本。
1. 仿真的定位与整体思路拆解
1.1 为什么选 Field II 做超声仿真
超声成像系统从硬件到处理链路非常长,真机实验的重复性差、成本高,尤其在做新型探头验证的时候,machining 一次就得几百上千块,还得搭水槽、配运动平台,折腾一轮下来可能数据全是噪声。仿真平台这时候就成了合理的起点:参数可控、边界可调、所有误差都被“设定值”定义,适合算法和系统设计的快速迭代。
市场上做声场和超声系统仿真的工具并不少:有基于有限元法的 COMSOL、PZFlex,有基于射线声学的 k-Wave,也有速度更快但简化较多的 k-Wave——哦我重新组织一下,k-Wave 其实是基于 k-space 的伪谱法,不是纯射线近似。Field II 之所以在超声成像领域流行了几十年没被淘汰,主要得益于两件事:
- 它基于线性系统理论和空间冲激响应法,计算精度高,特别适合模拟瞬态声场和换能器阵列。
- 它跑在 Matlab 环境里,写脚本、处理数据、画图一条龙,和后续的图像重建、波束形成算法无缝衔接。
相比有限元法,Field II 不需要划分细密的三维网格,内存占用小得多;相比几何声学近似,它把衍射效应考虑进来了,精度更高。一句话总结:Field II 是你做超声成像相关研究时精度和效率之间最平衡的那个选项。
1.2 核心计算原理:空间冲激响应法
Field II 的核心理论最早由丹麦理工大学的 Jørgen Arendt Jensen 教授提出,全称是 Tupholme-Stepanishen 方法。它的基本思想非常直观:一个有限尺寸的超声换能器表面可以想象成无数个微小点源,每个点源都向空间中辐射球面波,而空间中任意一点的声压就是所有这些点源贡献的叠加。
用公式来表达就是,对于发射换能器,空间中一点 r 处的速度势可以写作:
[ h(\mathbf{r},t) = \int_{S} \frac{\delta(t - |\mathbf{r} - \mathbf{r}'| / c)}{2\pi |\mathbf{r} - \mathbf{r}'|} dS' ]
这个式子的意思是,换能器表面 S 上每一个面积元 dS' 都产生一个球面波,由于传播距离不同,到达观察点的时间不同,贡献的幅度也不同。这是一个纯粹的几何问题,而 Field II 就是把这个积分高效、稳定地计算出来的工具。计算核心是寻找不同时间延迟的叠加效应,因此它可以精确处理聚焦、偏转、阵元孔径切割等复杂情况。
散射建模则是发射和接收的全循环。Field II 在接收时把每个散射体当作新的“发射源”:发射声场到达散射体后,散射体向四周辐射次级波,这个次级波再被接收阵元拾取。因此整个接收信号可以通过发射响应、散射强度、接收响应的卷积得到。
实际使用中你不需要手动算这些积分,Field II 提供了一整套 API,比如xdc_focused_array定义聚焦探头,calc_scat计算多散射体的接收信号,calc_h计算空间冲激响应。但你理解了原理,才能正确设置这些 API 的参数,遇到诡异结果时也才排得了错。
1.3 这套工具解决了什么问题
Field II 的出现把“我想模拟一个合理超声信号,然后处理它”这件事的门槛大大降低了。具体来说,它主要帮我们做了这几件事:
第一,换能器建模。支持线阵、凸阵、相控阵,支持任意形状的阵元孔径,支持聚焦、偏转、大孔径。这些东西如果自己用解析公式推,一个简单的矩形活塞探头就得推半天,阵列加上延迟曲线后手算基本不可能。
第二,声场计算。给定探头参数,计算指定平面上的声压分布、焦点大小、旁瓣水平。这直接服务于探头设计的选型和参数验证。
第三,信号仿真。设置一组散射体,就能得到各个阵元上的射频RF信号,这条链路是后续一切图像重建、血流估计、弹性成像等算法验证的基础。
第四,参数扫描。由于每个参数都由变量控制,可以系统性地改一个变量看系统响应。比如固定孔径大小,改焦点位置看声场迁移规律,这类工作真机实验做起来极慢,但仿真可以批量出图。
我在实际使用中的一个体会是:Field II 的输出结果可以当“准真值”来用,因为它的物理模型比很多简化仿真要完整,但又比有限元法快得多。这就意味着你可以把 Field II 的结果当作基准,去验证你用简化模型或者机器学习做的快速算法是不是靠谱。这一点价值极大。
2. 环境搭建:安装、编译与第一个 Demo
2.1 Matlab 版本与 Field II 的兼容性
Field II 对 Matlab 版本的要求并不苛刻,我在 R2018b、R2020a、R2023a 上都跑通过。不过要注意一件事:Field II 是以 C 语言 MEX 函数形式提供的,所以在开始之前,你需要保证 Matlab 配置好了可用的 MEX 编译器。
在 Windows 上用老版本 Matlab 的人常常卡在编译器这里,因为 Matlab 只认受支持的特定 MinGW-w64 版本。比如 R2020a 需要 MinGW 6.3,而较新的 R2023a 反而内置了对 MinGW-w64 不同版本的支持。建议你打开 Matlab,执行:
mex -setup系统会提示你当前可用的编译器。如果显示没有编译器,去安装 TDM-GCC 或者 Matlab Add-On 里的 MinGW-w64 都可以,注意一下版本对应即可。
在 macOS 上一般使用 Apple LLVM Clang,Linux 上使用 GCC,这两个环境通常问题不大。真正要留意的是:在 Apple Silicon(M1/M2)上跑老版本 MEX 可能会因为架构不匹配报错,建议优先用 Rosetta 模式,或者直接选 R2023b 以上的版本配合新编译的 Field II。
2.2 安装与编译流程
Field II 的代码可以从其官网或者 MathWorks File Exchange 下载。拿到压缩包后解压,我习惯把整个文件夹放在一个固定位置,比如~/Field_II_Demo,然后把以下内容写进startup.m,避免每次手动设置路径:
% startup.m addpath(genpath('~/Field_II_Demo')); field_init;这里面的field_init函数会在内存中初始化 Field II 的所有全局状态和变量,每次开始仿真前务必运行。如果忘记执行,后续调用xdc_linear_array之类的函数时会报错提示 Field 未初始化。
第一次使用要编译 MEX 文件。在 Matlab 命令行进入 Field II 文件夹,执行:
field_init; cd /path/to/field_ii_folder; mex -O field_c.c mex -O field_p.c这个过程比较快,看到MEX completed successfully的提示就说明编译成功。如果出现关于undefined symbol之类的问题,基本是编译器不匹配或者 32/64 位混乱,换成 64 位 GCC 就好。
2.3 跑通第一个发射声场
安装完之后,我习惯跑一个最简单的矩形探头声场分布来验证环境没问题。代码如下:
% 初始化 field_init; % 定义探头参数 fs = 50e6; % 采样率 50 MHz f0 = 3.5e6; % 中心频率 3.5 MHz c = 1540; % 声速 1540 m/s width = 0.5e-3; % 阵元宽度 height = 6e-3; % 阵元高度 kerf = 0.05e-3; % 相邻阵元间隙 % 创建一个线性阵列响应 Th = xdc_linear_array(1, width, height, kerf, 1, 1, [0 0 0]); % 定义激励信号 t0 = 0; excitation = sin(2*pi*f0*(0:1/fs:1/f0*3)); xdc_excitation(Th, excitation); % 计算中轴线上声压分布 x = 0; y = 0; z = 0:0.1e-3:50e-3; [hp, start_t] = calc_h(Th, [x*ones(size(z)); y*ones(size(z)); z]);这里xdc_linear_array(1, ...)表示 1 个阵元,后面的[0 0 0]是阵列中心位置。calc_h返回的是空间冲激响应hp以及对应的时间起点start_t。跑完之后plot(z, max(hp, [], 2))就能看到声压沿轴向的衰减趋势,这叫“近场长度”附近的波动和远场的单调衰减。
我第一次跑的时候,什么都没有输出,后来发现是忘了field_init。这个低级错误出现的频率远比你想象的高,所以建议把初始化和路径设置合并到 startup.m 里,从此少一个烦恼。
3. 换能器建模的进阶操作
3.1 线阵、凸阵与相控阵的参数对比
Field II 对换能器建模的最小单位是“物理阵元”。一个物理阵元内部还可以划分成若干个“数学子元”,这是为了更精确地模拟矩形阵元的边缘效应。xdc_linear_array是最常用来做线阵的函数,它的签名中通过num_element控制阵元个数,通过width和height控制阵元物理尺寸,kerf是阵元之间的缝隙。对于凸阵,Field II 提供了xdc_convex_array,额外需要指定曲率半径;相控阵则可以用xdc_linear_array配合xdc_focus的延时参数实现电子偏转,效果等同于相控扫描。
阵列参数对声场的影响有非常直观的关系:
| 参数 | 影响 | 说明 |
|---|---|---|
| 阵元宽度(width) | 决定横向分辨率 | 宽度越大,指向性越强,但可能产生栅瓣 |
| 阵元间距(pitch) | 决定栅瓣位置 | pitch 应小于 λ/2 以避免栅瓣混叠 |
| 阵元高度(height) | 决定切片厚度方向的聚焦能力 | 通常常用声透镜做固定聚焦 |
| 孔径大小 | 决定焦点宽度 | 孔径越大,焦区横向斑越小 |
在 3.5 MHz、声速 1540 m/s 时,波长大约 0.44 mm。对于这种频率的线阵,pitch 一般取 0.3 mm 左右,这样可以保证在最大偏转角度 45 度时也不产生明显栅瓣。这是一个非常关键的参数选择:pitch 如果大于半波长,你在进行大角度偏转时会在图像两侧看到源于栅瓣的鬼影,这类伪像仿真时一目了然,真机上则极难排查。
3.2 聚焦与偏转设置:延时法则的核心意义
聚焦和偏转的本质是给每个阵元附加一个时间延迟。以 Concave 几何聚焦为例,每个阵元到焦点的距离不一样,Field II 会自动计算这些物理几何延迟;但如果要在线性阵列上实现电子聚焦,则需要你自己计算或者调用xdc_focus接口。
xdc_focus的核心语法是:
xdc_focus(Th, time, focus, index)time是聚焦发生的时刻,通常是 0,表示从激励开始就聚焦;focus是一个 1×3 的向量,表示焦点坐标;index是你要施加聚焦的阵元索引,填空矩阵就表示全部阵元。
举个例子,一个 64 阵元的线阵,想在深度 40 mm 处聚焦:
N = 64; Th = xdc_linear_array(N, 0.3e-3, 6e-3, 0.05e-3, 1, 1, [0 0 0]); xdc_focus(Th, 0, [0 0 40e-3]);如果你还想让焦点偏离中心轴线,直接改焦点坐标即可,比如[5e-3 0 40e-3]就代表焦点在横向偏移 5 mm 的位置。Field II 会自动把对应的发射延时拟合好。
偏转延时计算中常见的一个坑是:你给的焦点太近,导致某些阵元的延时为负值。Field II 不会报错,但结果会不对。我在做相控阵成像时,专门写过一个检查脚本:对每个阵元做几何距离求差,减到最小延迟后看有没有负值,有就说明焦点选得太近或者孔径太大,需要加一个预延时。
这段经历给我的教训是:不要只依赖 Field II 的鲁棒性,它默认不做太多物理合法性检查。数据合理性是使用者自己的责任。
3.3 阵元脉冲响应的设定
Field II 允许你用xdc_impulse给每个阵元定义一个脉冲响应,也就是阵元的带宽特性。通常用一个中心频率 3.5 MHz、60% 相对带宽的高斯包络正弦波就可以:
t_imp = -2/f0:1/fs:2/f0; impulse_response = gauspuls(t_imp, f0, 0.6); xdc_impulse(Th, impulse_response);设定xdc_impulse后,Field II 的发射信号实际上是“激励信号”和“阵元脉冲响应”以及“空间冲激响应”三者的卷积。这一点对理解仿真结果非常重要:你最终看到的射频波形不是简单的正弦波,而是经过阵列空间滤波之后的复杂调制波。
如果你只是关心声场分布而不是具体信号波形,可以省略这一步,但只要你后面要计算散射体的接收信号,阵元脉冲响应就必须设置。我通常的做法是始终设置,因为这可以让后续的仿真结果更接近真实硬件,而且所需的计算量变化不大。
4. 散射信号仿真与图像生成全流程
4.1 点散射体:RF 信号模拟
初始化接收探头和发射探头,然后设置点散射体,是 Field II 最经典的用法。下面给出一个最小可运行的例子:
field_init; fs = 100e6; c = 1540; f0 = 5e6; N = 64; pitch = 0.3e-3; % 发射探头 Tx = xdc_linear_array(N, 0.25e-3, 5e-3, 0.05e-3, 1, 1, [0 0 0]); xdc_excitation(Tx, sin(2*pi*f0*(0:1/fs:1/f0*2))); xdc_impulse(Tx, gauspuls(-2/f0:1/fs:2/f0, f0, 0.7)); % 接收探头 Rx = xdc_linear_array(N, 0.25e-3, 5e-3, 0.05e-3, 1, 1, [0 0 0]); xdc_impulse(Rx, gauspuls(-2/f0:1/fs:2/f0, f0, 0.7)); % 焦点设置为目标位置 focus = [0 0 30e-3]; xdc_focus(Tx, 0, focus); xdc_focus(Rx, 0, focus); % 散射体位置与散射强度 positions = [0 0 30e-3]'; amplitudes = 1; % 计算接收信号 [rf, t] = calc_scat(Tx, Rx, positions, amplitudes);calc_scat的返回值rf是一个二维矩阵,行数等于接收阵元数,每行是一个阵元收集到的时间序列。你可以把任意两列延迟相加模拟波束形成,也可以直接存下来做后续处理。比如,用plot(t, rf(32,:))看中心阵元的波形,你会看到明显的主波峰和拖尾振荡,主峰对应散射体深度处的回波。
这里最容易被忽略的是采样率。如果采样率低于中心频率的 4 倍,波形包络会被严重扭曲。我在做 5 MHz 探头仿真时常用 100 MHz 采样率,也就是 20 倍过采样,这样算出来的幅值和延迟足够精确,代价只是计算时间多一点。对绝大多数仿真任务,10 倍以上采样率是推荐的底线。
4.2 多散射体与体模构建
实际组织比单点散射体复杂得多。组织体模通常包含成千上万个散射体,Field II 的calc_scatter就支持这种批量输入。散射体的位置坐标用一个 3×N 的数组传入,散射强度可以固定值,也可以随机取值模拟不同组织的散射特性。
我自己常用的体模生成方法如下:
rng(2024); num_scat = 5000; x = (rand(1,num_scat) - 0.5) * 20e-3; z = rand(1,num_scat) * 40e-3 + 5e-3; y = (rand(1,num_scat) - 0.5) * 2e-3; positions = [x; y; z]; % 散射强度:瑞利分布模拟散斑 amplitudes = randn(1,num_scat) + 1i*randn(1,num_scat); amplitudes = abs(amplitudes);在某一块区域把散射体强度提高 5 倍,就能形成模拟囊肿或强反射体的区域。例如在[0 0 25e-3]附近半径为 2 mm 的圆柱内,把散射幅度设为 5:
mask = ((x.^2 + (z-25e-3).^2) < (2e-3)^2); amplitudes(mask) = amplitudes(mask) * 5;这样生成的体模可以模拟一个低回声背景中包含强反射小结的情况。
这种体模在图像上表现为带有散斑纹理的背景和局部亮斑。散斑本身不是真实的解剖结构,而是散射体干涉叠加产生的一种现象,但它和真实超声图像非常接近,所以成为非常有用的仿真工具。
4.3 从 RF 信号到 B 超图像
拿到每个阵元的 RF 信号后,下一步是波束形成。最常见的做法是延时叠加(Delay-and-Sum,DAS)。核心步骤是:对于图像中的每个像素点,计算它到每个阵元的往返距离,换算成采样点索引,把对应采样点的值累加起来。
function [img, z_axis, x_axis] = das_beamform(rf, t, element_pos, c, z_start, z_end, x_range, N_pix_z, N_pix_x) img = zeros(N_pix_z, N_pix_x); z_axis = linspace(z_start, z_end, N_pix_z); x_axis = linspace(-x_range, x_range, N_pix_x); fs = 1 / (t(2) - t(1)); for iz = 1:N_pix_z for ix = 1:N_pix_x xp = x_axis(ix); zp = z_axis(iz); acc = 0; for el = 1:size(rf,1) xel = element_pos(el); d = sqrt((xp - xel)^2 + zp^2); n = round(2*d/c * fs); if n >= 1 && n <= length(rf(el,:)) acc = acc + rf(el, n); end end img(iz, ix) = acc; end end end这个朴素 DAS 的复杂度是 O(像素数 × 阵元数),对于 64 阵元、400×200 的像素网格大约是 500 万次循环,Matlab 跑起来可能有点慢。实际使用中我会把内层循环向量化,计算距离矩阵再直接索引,速度能提升几十倍。
图像重建之后记得做包络检波和对数压缩。abs(hilbert(img))得到包络,20*log10(x/ max(x))转换到 dB 尺度。不这么做的话,动态范围太大,图像全是黑的,什么也看不到。
这一步做完,你就从 Field II 仿真的原始 RF 数据得到了最终的超声图像。一个完整的仿真验证链路就此打通,后续做波束形成优化、旁瓣抑制算法、图像质量评价指标计算,全都可以在这条链路上展开。
5. 计算性能优化:为什么你的仿真跑得慢
5.1 多线程与并行计算
Field II 的老版本是单线程的,计算大量散射体的回波信号时需要循环每个散射体逐个累加。到了较新版本,Jensen 教授加入了多线程支持,但前提是你编译 MEX 时指定了 OpenMP 参数。在 Linux 和 macOS 上分别用:
mex -O CFLAGS="-fopenmp" LDFLAGS="-fopenmp" field_c.cWindows 上则要在 MEX 配置中加入附加编译选项,具体可以参考 Matlab MEX 帮助文档。
就算有了多线程支持,也不代表每个算法都能线性加速。calc_scat的大部分计算是对每个接收阵元和每个散射体做延时插值,加速比受内存带宽限制较多。一个实用的优化方法是去掉无用的将全部 RF 数据存满的操作,而是按成像线逐线计算,这样就避免了一次性分配过大的内存空间。
5.2 合理降低计算精度的技巧
对于参数趋势分析,比如不同孔径下的焦点宽度变化,不需要极高精度的绝对声压值。此时可以通过减少子元数量来加速。Field II 允许在阵元内部设置子元数量,将每阵元划分为 1×1 可以极大减少计算量,代价是边缘衍射效应模拟得比较粗。
实测中,对于 3.5 MHz 的中心频率,一个 0.3 mm 宽、6 mm 高的矩形阵元,子元分为 3×7 之后,计算精度已经足够。如果分成更多子元,精度提升很小,但计算量显著上升。所以首选策略是:先用粗子元算大趋势,再对关键工况用细子元做精确校核。
还有一个常用的方法:分段仿真体模。将 5000 个散射体分成 10 组,每组 500 个,分别调用calc_scat再把结果相加。实测下来这样做法不仅便于并行,还可以避免大面积散射体分布不均导致的数值问题。
5.3 内存占用预警
散射体数量从 1000 增加到 5000,RF 矩阵的尺寸增长并不是线性,而是每个阵元都要分配一条完整时间线,时间线长度又由最大往返延迟决定。如果最大探测深度是 40 mm,声速 1540 m/s,对应最大时间约 52 µs,在 100 MHz 采样率下是 5200 个点。乘以 64 个阵元就是 33 万个点,本身不算大,但中间计算中的声场矩阵会成百倍放大,内存一旦不够系统就开始用 swap,速度直接掉入深渊。
我踩过最大的坑是在计算大阵列的声场分布时,忘了控制观察点数量。想画出细密的三维声场图,取了 1000×1000 个点,结果calc_h直接报内存崩溃。后来改成每次只算一条线上几百个点,分批处理,问题就解决了。Field II 的计算量跟观察点数量直接相关,所以在设计仿真时应严格控制观察点的总数。
经验:看中轴声场分布,取 200-500 个点足够;看二维截面,取 200×200 点就足够画矢量图了,再多就是浪费内存。
6. 常见报错与排查技巧
6.1 Field not initialized 类错误
这个错误几乎每个新手都会碰到。表现是调用任何xdc_*或calc_*函数时,Matlab 提示:
??? Error using ==> field_init Field II is not initialized解决方法非常直接:执行field_init。但要注意,field_init只能调用一次,如果重复调用,它会告诉你已经初始化了,实际上这并不影响计算,它会重建内部状态。更安全的做法是每次脚本开头调用field_init,末尾不必清理。
6.2 MEX 文件无法加载
有些用户编译完field_c.c后,Matlab 提示:
Invalid MEX-file ... The specified module could not be found.这在 Windows 上多半是缺少运行时库,或者编译器的 runtime DLL 不在系统 PATH 中。MinGW 环境下把mingw64/bin目录加入 PATH 再重启 Matlab 一般就能解决。macOS 上有时需要将编译结果重新符号链接,提示mexmaci64无法识别时重新用当前版本 Matlab 编译即可。
6.3 波形表现为纯延迟但无回波
如果散射体回波信号总是零,最常见的原因是位置设置错误。Field II 中所有坐标的单位都是米,如果不小心传入毫米的值,散射体可能跑到天边去,完全超出探头照射范围。另一个原因是散射强度为 0 或者复数模值处理错误。
排查办法很简单:先打印positions的数值范围,确认它和探头的焦点、孔径范围在同一量级。再用单散射体、中心正下方位置测试,如果这种最简单的情况都算不对,说明探头参数或者坐标基准有问题,与散射体列表无关。
6.4 计算速度慢到不可接受
如果单次calc_scat需要几个小时,通常是以下三种情况之一:
- 采样率过高,导致时间序列过长;
- 阵元子元数量过多;
- 散射体数量过大且没有分块处理。
我建议先做一个小规模测试:用 10 个散射体、1 个阵元跑一次,记录时间,再推算出整体耗时。如果推算结果不可接受,就尽早调整参数,而不是盲目等待。
针对采样率,可以在不影响延时精度的前提下适当降低,比如 50 MHz 对于 5 MHz 探头已经够用;子元数量可以按前一节的建议设置;散射体分组并行可以用parfor替代for,注意每个循环内部调用field_init可能导致状态冲突,所以要对 Field II 的部分做特殊处理,或者直接用batch方式提交多个独立任务。
7. 从仿真到论文级结果的经验补充
7.1 图像质量指标怎么算
如果你做的是算法验证,不能只看图像好看,还要量化指标。常用的包括对比度、空间分辨率、信噪比。计算横向分辨率可以直接在点散射体响应剖面图上量 −6 dB 宽度:对包络图像取下来一条横向剖面,找到最大值下降一半对应的宽度。对比度则可以计算强反射区域内部和外部平均幅度的比值。
Field II 仿真最大的好处是你可以把“点扩散函数”单独提出来分析,因为你在设置体模时知道每个散射体的准确位置。真实实验里很难提取点扩散函数,这在算法评估中是极大的便利。
7.2 参数扫描与敏感度分析
在做探头设计时,经常要回答“阵元间距取多少合适”“孔径多大才能让焦点宽度小于 1 mm”之类的问题。这些问题最适合用脚本循环扫参,每次改动一个参数、记录指标、最后画曲线。
我在做这类敏感度分析时,会刻意保持其他参数严格不变,并把随机种子固定,否则不同帧之间的散斑差异会淹没掉真正的参数影响。实验设计上建议用矩阵扫描,不要手动改参数跑几十次,不然容易改错某个数值导致结果不一致。
7.3 持续积累:把笔记做成可复用的模块
学习 Field II 最有价值的产出不是跑通了一个 demo,而是把你常用的功能封装成自己的函数库。比如把create_linear_array、default_excitation、add_scatterers、das_image这些步骤合成几个函数,下次做不同实验时只需要改配置参数,不用再从头写一遍。我在自己的项目里就是这么做的,后来的各种仿真需求基本都在现有框架上改改参数就能出结果,整个工作流变得非常顺滑。
如果你也是刚开始学 Field II,我的建议是从最简单的点散射体 RF 信号模拟入手,先把发射、接收、散射这条链路跑通,再逐步加上阵列、聚焦、延迟叠加成像。这个过程看起来慢,但每一步踩过的坑都会变成你后续快速排查问题的直觉。我自己走完这套流程之后,最深的一个感受是:Field II 的学习曲线不在函数调用上,而是在理解“声场、脉冲响应、散射与图像重建”这条物理链路上。一旦这条链路在心里清晰了,那些 API 和参数只是顺手的事。