3.5 定义传感器
最终的输入结构传感器定义了用于记录模拟过程中每个时间步的声场的传感器点的属性和位置。计算域内传感器点的位置是使用sensor.mask 设置的。这可以用三种不同的方式定义:
(1)作为直接指定记录数据的网格点的二元矩阵(由1或0组成);(大型GPU模拟中此定义方法最常用)
(2)以两个对角的网格点坐标定义,定义结果(在一维中为线,在二维中为矩形,三维中为长方体);(网格点坐标指在matlab定义的计算网格中,一个网格点在整个网格中的位置,同时也是matlab的下标)
(3)作为一组笛卡尔坐标(就是你平常知道的那个坐标,长度单位为m的坐标)。
(1)二元方法
二元传感器掩码是通过将与计算网格大小相同的二进制矩阵分配给sensor.mask来定义的,其中1代表构成传感器一部分的域内的网格点。下面给出了在 2D 中创建二进制传感器掩模的两个示例:
% 定义一条线形的 2D 二元传感器掩模
x_offset = 25; % 网格点坐标
width = 50; % 网格点坐标
sensor.mask = zeros(Nx, Ny);
sensor.mask(x_offset, Ny/2 - width/2 + 1:Ny/2 + width/2) = 1;
% define a 2D binary sensor mask in the shape of an arc using makeCircle
x_pos = Nx/2; % 网格点坐标
y_pos = Ny/2; %网格点坐标
radius = 20; % 网格点坐标
arc_angle = pi/2; %网格点坐标
sensor.mask = makeCircle(Nx, Ny, x_pos, y_pos, radius, arc_angle);
(2)对角方法
对于规则形状的二元传感器掩模(由均匀棱柱多面体定义),指定传感器点位置的另一种方法是定义传感器区域的两个相对角。对角由以下列向量定义:
一维:[X1; X2]
二维:[X1; Y1; X2; Y2]
三维: [X1; Y1; Z1; X2; Y2; Z2]
坐标以网格点为单位给出,其中 2D 中的 (1, 1) 定义网格的左上角(对于其他维度也类似)。可以通过向sensor.mask添加额外的列向量来指定多个传感器区域,如下所示。对于使用 C++ 代码(手册第 4 节中描述,三维仿真需要)的模拟,使用对角可以显着减小input文件的尺寸(不过我感觉这个减小的很鸡肋,我自己用不到)。
% 通过指定矩形对角 x、y 位置定义二维矩形传感器区域的
rect1_start = [25, 31];
rect1_end = [30, 50];
% 定义第二个矩形传感器区域
rect2_start = [71, 81];
rect2_end = [80, 90];
% 将对角列表分配给传感器掩码
sensor.mask = [rect1_start, rect1_end; rect2_start, rect2_end]’;
(注意!最后一行代码的最后还有一个“’”转置符号,大家运行一下就知道怎么回事了)
(3)笛卡尔方法
笛卡尔传感器掩码是通过将笛卡尔坐标的 N ×M 矩阵分配给sensor.mask 来定义的,其中 N 是维度数(1、2 或 3),M 是传感器点的数量。下面给出了在对角线上创建具有 11 个传感器点的 2D 笛卡尔传感器掩模的示例:
% 定义二维笛卡尔传感器掩码
x = -10:2:10; % [m]
y = -10:2:10; % [m]
sensor.mask = [x; y];
笛卡尔传感器点必须始终位于计算域的维度内。网格原点位于计算域中心,如果网格点数为偶数,则向行和列的末端偏移(注意!因为每个方向的点数如Nx = 128是偶数,所以计算域并不完全对称,所以这个时候x = Nx/2+1=65才是原点0,大家运行试试就知道了)。网格点的笛卡尔坐标可以使用 kgrid.x 和 kgrid.x_vec (等)返回。下面显示了显示每个网格点距原点的笛卡尔距离的示例(我感觉这没什么用,不如在matlab变量查看kgrid.x_vec方便):
kgrid = makegrid(6, 1, 6, 1); sqrt(kgrid.x.^2 + kgrid.y.^2)
ans =
4.2426 3.6056 3.1623 3.0000 3.1623 3.6056
3.6056 2.8284 2.2361 2.0000 2.2361 2.8284
3.1623 2.2361 1.4142 1.0000 1.4142 2.2361
3.0000 2.0000 1.0000 0 1.0000 2.0000
3.1623 2.2361 1.4142 1.0000 1.4142 2.2361
3.6056 2.8284 2.2361 2.0000 2.2361 2.8284
如果使用笛卡尔传感器掩模,则使用插值在每个时间步长获得传感器点处的声场值(三维仿真时,C++代码就不能这样插值用了,应该是这样,大家可以试试)。默认情况下,使用线性插值(这可以使用可选输入参数“CartInterp”进行更改;请参阅第 3.6 节中的讨论)。在仿真过程中,使用笛卡尔和二进制传感器掩模之间只有很小的性能差异。然而,使用笛卡尔掩模时插值所需的三角测量点的计算会显着延长预计算时间,特别是对于 3D 模拟而言。使用函数 cart2grid 和 grid2cart 可以将笛卡尔传感器掩码转换为二进制传感器掩码(反之亦然)。这些函数对于使用imagesc绘制笛卡尔传感器掩模也很有用。例如:
%使用 imagesc 绘制 二元源掩模和笛卡尔传感器掩模
imagesc(double(source.mask | cart2grid(kgrid, sensor.mask)));
定义了四个输入结构后,就可以调用仿真函数了。一维、二维和三维仿真的语法是类似的的。例如:
sensor_data = kspaceFirstOrder3D(kgrid, medium, source, sensor);
仿真后的输出数据
在仿真过程中的每个时间步,都会存储sensor.mask 中给定的传感器点处的声压值。这些值在模拟完成后返回。如果使用二进制或笛卡尔传感器掩码,则输出索引为sensor_data(sensor_point_index, time_index)。如果传感器掩码以二进制矩阵形式给出,则传感器数据将使用 MATLAB 的按列线性索引排序进行排序。这在第 3.2 节中进行了描述。 3.4 与二进制源掩码内点的排序有关。如果传感器掩码作为一组笛卡尔坐标给出,则计算出的sensor_data将以与定义坐标相同的顺序返回。
如果使用对角列表来定义传感器掩模,则在 1D、2D 和 3D记录的数据索引分别为为:
sensor_data(region_index).p(x_index, time_index)
sensor_data(region_index).p(x_index, y_index, time_index)
sensor_data(region_index).p(x_index, y_index, z_index, time_index)
这里 x_index、y_index 和 z_index 对应于传感器区域内的网格索引(例如,1D 中的线、2D 中的矩形、3D 中的长方体),如果指定了多个,则region_index 对应于该区域的编号。记录的数据在数值上与使用覆盖相同区域的二进制传感器掩模记录的数据相同(数据结果一样,所以本人还是觉得全用二元方法比较方便)。
可选记录参数
可以通过设置sensor.record这个结构体变量的值来控制传感器掩模记录的声学变量。所需的字段参数在元胞数组中以字符串形式列出。例如,要记录声压和粒子速度,sensor.record 应设置为 {‘p’, ‘u’}。如果设置了sensor.record的值,则从模拟返回的输出sensor_data被定义为结构,并且记录的声学变量作为结构字段附加。例如,如果sensor.record = {‘p’, ‘p_max’, ‘u’},则各个输出变量将作为sensor_data.p、sensor_data.p_max、sensor_data.ux、sensor_data.uy(等)进行访问。文末的表格给出了传感器选项的完整列表。
大多数声学参数在由sensor.mask定义的传感器点的每个时间步记录。这些参数的输出以与上述声压相同的方式索引为(sensor_point_index, time_index)。例外情况是平均数量('p_max'、'p_rms'、'u_max、'p_rms、'I_avg')和域内所有网格点记录的数量('p_max_all'、'p_min_all'、'p_final'、 'u_max_all'、'u_min_all'、'u_final')。平均量返回完整模拟的每个传感器点的最大值、平均值或均方根值,并索引为 (sensor_point_index)。 _final 和 _all 表示的量返回整个计算网格上最终、最大或最小压力或粒子速度场,无论传感器点由sensor.mask 定义,并在一维中索引为 (nx, 1),在2D 中(nx, ny ),在 3D 中(nx, ny, nz)。
在定义和使用模拟输入和输出时,记住 k-Wave 使用的交错网格方案的效果非常重要(请参阅第 2.4 节和表 2.1 以供参考)。特别是,与压力的输出相比,粒子速度的输出在空间和时间上都是交错的。例如,sensor_data.ux 是在 x 方向上交错 +kgrid.dx/2 和时间方向上交错 -kgrid.dt/2 的网格点处获得的。如果sensor.record包含“u_non_staggered”或强度参数“I”或“I_avg”之一,则使用傅里叶插值在模拟函数中自动计算非交错网格点处的粒子速度值。(这一段我也看不懂)
由sensor.mask定义的传感器点不会以任何方式修改波场。相反,它们充当透明观察者,记录域内压力和粒子速度的数值。任何给定传感器点的响应也是全向的,这意味着它对来自任何方向的波同样敏感。对于使用二元传感器掩模进行 2D 模拟,可以使用sensor.directivity_angle 和sensor.directivity_size设置各个传感器点的方向性。方向角对应于最大响应的方向。它以与计算网格大小相同的二维矩阵形式给出,每个传感器点的值在sensor.mask中指定。角度以弧度指定,其中 0 对应于 x 方向的最大灵敏度,pi/2 或 -pi/2 对应于 y 方向的最大灵敏度。方向性大小设置等效元件大小(以米为单位)。单元尺寸越大,响应的方向性越强。
字段名称 | 描述 |
sensor.mask | 二元网格、一组笛卡尔点或一组对角,指定在每个时间步记录压力的位置 |
sensor.record | 可选记录的声学参数的数据;有效输入为: 'p'(声压) 'p_max'(最大压力) 'p_min'(最小压力) 'p_rms'(RMS 压力) 'p_final'(最终压力场) 'p_max_all'(所有网格点的最大压力) 'p_min_all'(所有网格点的最小压力) 'u'(粒子速度) 'u_max'(最大粒子速度) 'u_min'(最小粒子速度) 'u_rms'(RMS 粒子速度) 'u_final'(最终粒子速度场) 'u_max_all' (所有网格点的最大速度) 'u_min_all' (所有网格点的最小速度) 'u_non_staggered' (非交错网格点上的粒子速度) 'I_avg' (随时间变化的声强) 'I_avg' (平均声强) |
sensor.record_start_index | 传感器应开始记录的时间索引(默认 = 1) |
sensor. time_reversal_boundary_data | 随时间变化的压力以时间相反的顺序强制执行,作为sensor.mask上的狄利克雷边界条件 |
sensor.frequency_response | 指定应用于sensor_data的频域高斯滤波器的中心频率和百分比带宽的二元数组 |
sensor.directivity_angle | sensor.mask 中定义的每个传感器元件的方向角矩阵(最大响应方向)。角度以弧度指定,其中 0 对应于 x 方向的最大灵敏度,pi/2 或 -pi/2 对应于 y 方向的最大灵敏度 |
sensor.directivity_size | 等效单元尺寸 [m](单元尺寸越大,响应的方向性越强) |