ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用FFT快速计算阵列天线方向图:从原理到工程实现

用FFT快速计算阵列天线方向图:从原理到工程实现 在项目里第一次意识到方向图计算能跟FFT扯上关系是在调试一套64元线阵的相控阵天线方向图时。当时的需求很简单给定一组复权值快速画出全空域方向图用于实时监控波束指向和旁瓣电平。最开始用的自然是“笨办法”——角度从-90度到90度按0.1度步进每个角度把64个阵元的贡献累加起来。单算一次方向图大概要跑1801×64次复数乘加也就是十几万次运算MATLAB里几百毫秒能出结果看起来也不算太慢。但问题出在“实时”这两个字上如果要在自适应波束形成的迭代过程中每刷新一次权值就看一次方向图或者要对几十组权值做批量对比几百毫秒一次就完全扛不住了一次仿真跑下来光等方向图就要等半小时。后来我把方向图求和式重新整理了一遍发现它本质上就是一个离散傅里叶变换DFT的形式。等间距线阵的阵列流形矢量天然就是一组复指数序列权值矢量就是时域序列方向图就是它的频谱。既然已经是DFT那就直接用FFT算——一次FFT把整个空域所有角度的方向图值全部拿到手64点FFT也就几微秒的事比逐点遍历快了至少两个数量级。这篇文章就把这个推导过程、参数选择、工程实现和踩坑记录完整写出来给做相控阵、MIMO通信、声呐阵列、超声成像或者任何涉及阵列信号处理的朋友一个可以直接照抄的参考。1. 先从方向图的“笨办法”说起1.1 方向图到底是什么先明确一下方向图的计算模型。考虑一个N元等间距线阵阵元位置在 (d_0, d_1, ..., d_{N-1})对于沿θ方向入射的远场平面波第n个阵元相对于参考点的相位延迟是 (k d_n \sin\theta)其中 (k 2\pi/\lambda) 是波数。如果给每个阵元施加复权值 (w_n)那么阵列的远场方向图就是所有阵元贡献的相干叠加[ F(\theta) \sum_{n0}^{N-1} w_n e^{j k d_n \sin\theta} ]这个公式就是方向图计算的起点。注意这里的 θ 是相对于阵列法线的角度θ0 对应波束指向法线方向θ 取正负90度之间就是整个前半空间。如果阵元按等间距 d 排列那么 (d_n n d)公式就可以写成[ F(\theta) \sum_{n0}^{N-1} w_n e^{j k n d \sin\theta} ]权值 (w_n) 可以是幅度加权、相位加权或者两者都有。幅度加权控制旁瓣电平相位加权控制波束指向。传统逐点计算就是直接对这个公式做数值求和先设定一组角度网格比如从-90度到90度按 Δθ 步进得到 (N_\theta) 个角度点然后对每个角度点执行一次包含N项复数乘加的求和。这就是最直观的“笨办法”。1.2 逐点扫描为什么慢这个方法的计算复杂度是 (O(N_\theta \times N))。举个具体例子N64角度步进0.1度那么 (N_\theta 1801)总共需要执行 (1801 \times 64 115264) 次复数乘加。每次复数乘加在MATLAB里是浮点运算开销确实不大但问题是方向图计算经常不是只跑一次就完事的。做波束扫描要算几百个指向做权值优化要迭代几千步、每步都要看方向图约束算下来就是上亿次复数运算仿真时间一下子就上去了。更麻烦的是这种逐点遍历的方式很难利用底层的向量化优化。在MATLAB里写循环逐角度计算或者用Python的for循环来做性能会非常难看。虽然可以用矩阵化一次性算完整块但本质上计算量没有减少只是换了个更高效的写法而已。真正能改变游戏规则的是从算法层面降低复杂度而FFT正是把 (O(N_\theta \times N)) 降到 (O(M \log M)) 的关键。2. 核心推导把方向图改写成DFT2.1 等间距阵列的“巧合”要让FFT派上用场关键在于观察到方向图公式的数学结构。把上面的求和式重新整理一下令 (u \sin\theta)再令 (\alpha (d/\lambda) u)则方向图可以写成[ F(\alpha) \sum_{n0}^{N-1} w_n e^{j 2\pi n \alpha} ]这个形式非常眼熟——它跟离散时间傅里叶变换DTFT的公式几乎一模一样。DTFT 的定义是 (X(e^{j\omega}) \sum_{n} x[n] e^{-j\omega n})差别只在指数上的符号。如果把权值序列 (w_n) 当作“时域信号”方向图就是这个信号的“频谱”。但DTFT的频率是连续变量没法直接用FFT计算。要变成DFT就需要对 (\alpha) 做离散采样。取 (M) 个均匀采样点令 (\alpha_k k/M)其中 (k 0, 1, ..., M-1)。代入公式得到[ F_k \sum_{n0}^{N-1} w_n e^{j 2\pi n k / M} ]这不就是DFT的形式吗标准的DFT定义是 (X[k] \sum_{n0}^{N-1} x[n] e^{-j 2\pi n k / M})指数符号正好相反。也就是说方向图采样值 (F_k) 等于权值序列 (w_n) 的DFT在频率点 (-k) 处的值即 (F_k X[-k \bmod M])。而DFT恰好可以用FFT高效计算。到这里方向图快速计算的数学基础就成立了。2.2 从AF到FFT的完整公式推导把上面的推导完整串一遍。设 (W[k]) 为权值序列 (w_n) 的M点DFT[ W[k] \sum_{n0}^{N-1} w_n e^{-j 2\pi n k / M}, \quad k 0, 1, ..., M-1 ]注意这里DFT的求和上限通常写 (N-1)但因为我们做的是M点FFTn的取值范围仍然是0到N-1当 n ≥ N 时权值为0所以求和项数不变。方向图采样值[ F_k \sum_{n0}^{N-1} w_n e^{j 2\pi n k / M} ]对比两个式子(F_k) 的指数符号与 (W[k]) 相反因此[ F_k W[M-k \bmod M] \quad (k \neq 0) ]当 k0 时(F_0 W[0])两者都等于所有权值之和也就是法线方向的方向图值。这里需要特别注意的是符号约定。如果你使用的FFT库采用了正指数的定义那么方向图采样值与FFT输出的对应关系就是 (F_k W[k])如果FFT库是标准负指数定义就要按上面的取反索引。MATLAB的fft函数采用负指数定义所以拿到结果后要做一次翻转或者更直观的做法是在调用fft之前把权值序列做共轭用共轭后的序列做FFT再取共轭恢复。我常用的办法是直接对 (w_n) 做fft然后用 (F_k conj(fft(conj(w_n)))) 来得到方向图这样免去了索引翻转的麻烦但代价是多做了两次共轭运算。下面给出一张符号对应表方便对照方向FFT核指数方向图与FFT输出关系标准DFT(e^{-j2\pi nk/M})(F_k W[M-k]) k≠0正指数定义(e^{j2\pi nk/M})(F_k W[k])共轭法标准FFT(F_k \text{conj}(W_{\text{conj}}[k]))建议在实际代码里固定一种约定并加注释说明不然过两个月再回头看自己写的代码很容易在符号正负上犯迷糊。2.3 k索引到实际角度的映射FFT输出的只是频点索引k要转换成实际角度θ需要经过两步换算。已知 (\alpha_k k/M)且 (\alpha (d/\lambda)\sin\theta)所以[ \sin\theta_k \frac{\lambda}{d} \cdot \frac{k}{M} ][ \theta_k \arcsin\left(\frac{\lambda}{d} \cdot \frac{k}{M}\right) ]需要注意的是 (\arcsin) 的定义域是[-1, 1]不是所有k值都对应真实空间的角度。只有满足 (|\frac{\lambda}{d} \cdot \frac{k}{M}| \leq 1) 的k值才对应可见区域内的方向。超出这个范围的k值对应的是“看不见”的虚空间方向在方向图上表现为谱峰或噪声但没有实际物理意义。再来看角度分辨率。相邻两个FFT频点之间 (\Delta\alpha 1/M)转换成角度域的间隔为[ \Delta(\sin\theta) \frac{\lambda}{d M} ]在法线方向附近(\theta) 很小近似有 (\Delta\theta \approx \Delta(\sin\theta) \lambda/(dM))。这个值的物理意义很直接(dM) 约等于阵列的虚拟孔径长度所以角度分辨率基本由阵列孔径决定。如果M取得比N大很多相当于在权值序列后面补了很多零再做FFT这并不会真正提高物理分辨率只是在角度域做了插值平滑让方向图曲线看起来更细腻而已。这一点在做参数选择时要记住不要误以为加大FFT点数就能提高阵列的真实分辨能力。3. 用MATLAB验证一次顺便看几个典型结果3.1 验证代码FFT方向图与逐点法对比理论推导归推导实际写代码跑一遍才能确认没有搞错符号和索引。我用MATLAB写了个最简单的对比脚本分别用逐点遍历法和FFT法计算同一个均匀加权线阵的方向图然后把两条曲线叠加绘制检查是否重合。% 对比逐点方向图 vs FFT方向图 N 64; % 阵元数 d 0.5; % 阵元间距以波长为单位0.5表示半波长 theta linspace(-90, 90, 1801); % 角度网格 w ones(N, 1); % 均匀加权 % 逐点法 AF_direct zeros(size(theta)); for ii 1:length(theta) s exp(1j * 2 * pi * d * (0:N-1). * sind(theta(ii))); AF_direct(ii) w. * s; end % FFT法 M 1024; % FFT点数取远大于N做插值 W fft(w, M); % M点FFT F_fft conj(fft(conj(w), M)); % 用共轭法得到正指数方向图 k 0:M-1; sin_theta_k (1/d) * k / M; % 归一化sin(theta) valid abs(sin_theta_k) 1; theta_k asin(sin_theta_k(valid)) * 180 / pi; % 对比把FFT结果按角度排序 figure; plot(theta, 20*log10(abs(AF_direct)/max(abs(AF_direct))), b-, LineWidth, 1.5); hold on; plot(theta_k, 20*log10(abs(F_fft(valid))/max(abs(F_fft(valid)))), r--, LineWidth, 1.5); grid on; legend(逐点法, FFT法); xlabel(角度 (度)); ylabel(归一化方向图 (dB));这段代码里最核心的巧妙之处是F_fft conj(fft(conj(w), M))这一行。因为MATLAB的fft是负指数定义而方向图需要正指数所以先对权值取共轭做FFT后再取共轭这样就得到了正指数的方向图序列而且不需要做索引翻转。实测下来FFT结果和逐点法的最大误差在1e-13量级完全是浮点精度范围内的差异图形上两条曲线重合得看不出区别。跑完代码后可以观察到均匀加权方向图的主瓣出现在0度第一旁瓣在-13.3dB左右这正是经典的均匀线阵旁瓣水平。这个结果也验证了FFT方式计算方向图在数值上没有任何信息损失。3.2 不同权值下的方向图从均匀加权到低旁瓣窗FFT方法一个很有价值的特性是权值的更换完全不影响计算流程——只要把传入fft的序列换成新的权值序列方向图就自动刷新。这比逐点法要重写整个角度循环优雅得多。我习惯在一次仿真里连续比较几组窗函数作为幅度加权的效果w_uniform ones(N,1); w_hamming hamming(N); w_cheb chebwin(N, 40); % 40dB Chebyshev窗 % 分别计算方向图并绘图 figure; for idx 1:3 switch idx case 1, w w_uniform; label Uniform; case 2, w w_hamming; label Hamming; case 3, w w_cheb; label Chebyshev-40dB; end W fft(w, M); F conj(fft(conj(w), M)); F F / max(abs(F)); plot(theta_k, 20*log10(abs(F(valid))), LineWidth, 1.5); hold on; end grid on; legend(Uniform,Hamming,Chebyshev-40dB); xlabel(角度 (度)); ylabel(归一化方向图 (dB)); ylim([-60, 5]);这个图能直观看出均匀加权主瓣最窄但旁瓣最高切比雪夫窗能把旁瓣压到-40dB以下但主瓣明显展宽。用FFT方法三组方向图的生成只花了不到一毫秒逐点法在这个角度网格下至少要跑几十毫秒。如果是在自适应算法的内部循环里这个速度差异会直接决定仿真方案能不能按时跑完。3.3 二维平面阵的扩展一维线阵的FFT方法很容易推广到二维平面阵。考虑一个 (N_x \times N_y) 的矩形栅格阵列x方向间距 (d_x)y方向间距 (d_y)方向图公式为[ F(\theta, \phi) \sum_{m0}^{N_x-1} \sum_{n0}^{N_y-1} w_{mn} e^{j 2\pi (m d_x u_x n d_y u_y)} ]其中 (u_x \sin\theta\cos\phi)(u_y \sin\theta\sin\phi)。仔细观察这个双重求和它在数学上是一个二维DFT可以直接用二维FFT计算。在MATLAB里就是fft2(w, Mx, My)其中 (M_x, M_y) 分别是两个维度的FFT点数。二维情况下的索引映射和一维类似需要分别对两个维度做 (u_x)、(u_y) 到角度的换算。实际使用中二维FFT方法做波束扫描或者方向图监测非常高效特别是配合GPU加速时可以实时刷新全空域方向图。4. 参数选择与精度控制这里藏着不少坑4.1 FFT点数M怎么取FFT点数M的选择是实践中的第一个关键决策。从纯数学角度讲M只要不小于N就行因为DFT的定义本身不要求M和N相等。但工程上建议M取2的整数次幂这样才能调用基2FFT算法发挥最大效率。如果你用的FFT库支持混合基或任意长度M可以更灵活但大多数嵌入式DSP库和FPGA IP核都只支持2的幂。M的最小值是N此时方向图的角度网格最粗。以N64、d0.5λ为例M64时 (\Delta(\sin\theta) 1/32 0.03125)在法线方向附近对应的角度间隔约为1.8度。这个分辨率用来粗略看主瓣位置够用但要看旁瓣细节就太粗糙了。实际中我通常取M为N的4到16倍推荐8倍。64元阵取M512角度网格间隔约为0.22度画出来的方向图曲线已经足够平滑。不同M取值下的角度间隔对比如下MFFT点数Δ(sinθ)法线附近Δθ度备注64N0.03125≈1.79分辨率最粗2564N0.0078125≈0.45推荐下限5128N0.00390625≈0.22工程推荐102416N0.001953≈0.11精细观察注意补零操作不会提升物理分辨率但能让方向图曲线更平滑方便观察旁瓣的包络和位置。如果只是要监控波束指向和大致旁瓣水平4N通常足够如果要精细测量零陷位置或者做高精度对比建议8N以上。4.2 栅瓣与可见区域栅瓣是阵列天线里绕不开的话题在FFT方法下会以另一种形式出现。当阵元间距 (d/\lambda 0.5) 时方向图会在可见区域内出现栅瓣这是因为空域采样不满足奈奎斯特条件。在FFT视角下这等价于频谱混叠——u域被周期延拓后本应在虚拟空间的谱峰“折叠”进了可见区域。用FFT算方向图时栅瓣会真实地出现在计算结果里。这不是计算错误而是阵列本身物理特性的体现。比如d1.0λ时在±90度附近会出现一个与主瓣等高的栅瓣。如果只是做仿真验证看到栅瓣说明阵元间距设计有问题如果是做已有阵列的性能分析FFT方法可以精确地告诉我们栅瓣在哪个角度、有多高。这一点比逐点法更有优势因为FFT天然把整个u域包括可见和不可见区域全部算出来了只需要用valid索引过滤出可见部分即可。实际处理时要注意如果只绘制valid索引对应的角度部分栅瓣可能恰好被截断。所以做分析时建议先把FFT的全谱画出来看一遍再单独看可见区域。我在调试一个d0.6λ的阵列时就遇到过这种情况可见区域内看不出问题但全谱上能看到栅瓣刚好卡在±56度附近等效于波束扫描时在这个角度附近会产生强干扰。4.3 精度与动态范围FFT计算方向图的精度问题容易被忽视。逐点法直接在角度网格上求值只要角度网格够细结果就是精确的FFT法则引入了两个误差来源FFT本身的浮点舍入误差以及角度采样量化误差。对于FPGA或者嵌入式实现如果使用单精度浮点方向图的动态范围会受限。实测下来64点FFT的单精度实现数值噪声底大约在-120dB左右这对于看-40dB的旁瓣绰绰有余但如果你用切比雪夫窗把旁瓣压到-60dB甚至更低方向图曲线会开始出现毛刺因为计算结果的噪声底已经跟真实的深旁瓣电平相当了。这种情况下建议改用双精度或者对FFT输出做更多位的定点处理。在MATLAB里做验证时默认就是双精度基本不用担心这个问题。但如果你把代码移植到嵌入式平台一定要先评估一下单精度的动态范围是否满足需求。我的经验是方向图动态范围在-50dB以内的应用单精度完全没问题超过-60dB就要仔细评估了。5. 工程实现从MATLAB到嵌入式与FPGA5.1 在STM32上跑FFT方向图把FFT方向图算法移植到嵌入式平台最常见的场景是便携式相控阵天线测试仪、声呐信号处理前端或者软件定义无线电系统。以STM32F4系列为例CMSIS-DSP库自带高性能的FFT函数用起来非常方便。#include arm_math.h #define N_POINTS 512 // FFT点数 #define N_ELEMENTS 64 // 阵元数 float32_t input[2 * N_POINTS]; // 复数输入实部虚部交替存放 float32_t output[2 * N_POINTS]; // FFT输出 arm_cfft_instance_f32 fft_instance; // 初始化FFT实例 arm_cfft_init_f32(fft_instance, N_POINTS); // 填充输入前N_ELEMENTS个位置放权值其余补零 for (int i 0; i N_ELEMENTS; i) { input[2 * i] weight_real[i]; input[2 * i 1] weight_imag[i]; } for (int i N_ELEMENTS; i N_POINTS; i) { input[2 * i] 0.0f; input[2 * i 1] 0.0f; } // 执行FFT arm_cfft_f32(fft_instance, input, 0, 1); // 由于CMSIS-DSP的FFT是负指数定义需要做索引翻转得到方向图 for (int k 0; k N_POINTS; k) { int idx (k 0) ? 0 : (N_POINTS - k); output[2 * k] input[2 * idx]; output[2 * k 1] input[2 * idx 1]; }这段代码里有几个需要注意的地方。CMSIS-DSP的复数序列是实部虚部交错存放的内存布局是[real0, imag0, real1, imag1, ...]初始化实例时参数要注意实例类型是arm_cfft_instance_f32而不是更老的arm_cfft_radix4_instance_f32。第三个参数0表示正变换1表示反变换。最后一个参数是位反转标志通常填1就够了。做完FFT之后索引翻转这一步是必须的因为CMSIS的FFT核是负指数定义直接输出的频谱对应的是 (W[k])而方向图需要的是 (F_k W[M-k])。我在第一次移植时忘了做这个翻转导致方向图左右颠倒找了好久才发现是索引问题。还有一点容易被忽略如果单片机的FPU没有启用或者编译器优化等级太低FFT的性能会大打折扣。STM32F4的FPU开启后512点复数FFT大约只需要几十微秒完全可以做到方向图实时刷新。5.2 在FPGA上用FFT IP核实现对于需要极高实时性的场合比如高频相控阵的波束控制环路FPGA是绕不开的平台。Xilinx Vivado里自带的FFT IP核配置灵活支持流水线结构可以在每个时钟周期持续处理数据。用FFT IP核实现方向图计算的基本思路跟MCU版本一致只是要把权值写入BRAM然后通过AXI-Stream接口送入FFT IP核输出频谱后做坐标映射。配置FFT IP核时有几个关键参数需要注意。点数要跟设计保持一直数据宽度建议不低于16位定点有条件的用24位或32位因为方向图动态范围对量化噪声敏感。缩放策略建议选Block Floating Point或者手动配置缩放因子避免中间计算溢出。我实测过用16位定点做512点FFT输出频谱的动态范围大约在-80dB左右对于大部分波束赋形应用够用但如果要做超低旁瓣分析还是建议上浮点或者更高位宽。FPGA实现的一个优势是可以同时计算多个波束方向的方向图——只要把不同的权值序列按时间片轮流送进FFT核由于FFT核的吞吐率很高多个波束的方向图刷新几乎是同时完成的。这在传统的逐点计算架构下很难做到因为逐点法需要大量的复数乘法器资源而FFT核本身是高度复用的。5.3 一个通用工程清单从公式到代码不管用什么平台我建议都过一遍下面的检查清单符号约定确认FFT库是正指数还是负指数定义索引翻转是否正确。归一化状态方向图的峰值是否为1是否需要除以M。索引映射FFT输出频点k到角度θ的换算公式是否正确arcsin定义域是否越界。数据填充补零操作是否正确权值序列的实部虚部排列是否跟FFT库要求一致。单位统一阵元间距是用波长归一化的数值还是米角度是用度还是弧度。精度验证先用双精度仿真跑一组标准方向图确认嵌入式输出与仿真误差在可接受范围内。这六条看着简单每一条我都踩过坑。尤其是符号约定和单位统一很多时候代码跑出来的结果“看起来不太对”但又不报错最后检查下来都是这类低级错误。6. 常见问题与排查技巧6.1 方向图左右颠倒方向图左右颠倒几乎是所有人的第一次FFT方向图都会遇到的问题。现象是计算出的主瓣位置在30度实际应该是在-30度。原因就是FFT核的指数符号约定跟方向图公式不一致导致频谱在频域上被翻转。排查时先确认FFT库的文档如果是负指数标准定义检查是否做了索引翻转或者共轭操作。解决这个问题有个很实用的技巧用一个已知的非对称权值来做冒烟测试。比如给阵列设置一个指向30度的线性相位权值然后用FFT方法算方向图看主瓣落在哪个角度。如果主瓣落在-30度说明索引翻转没做对如果落在30度说明符号约定正确。这个小测试每次移植到新平台时都值得跑一遍。6.2 角度轴范围不对有时候FFT算出来的方向图在角度轴上只显示一部分比如只有-90到0度或者0到90度。这通常是因为arcsin的输入超出了定义域导致无效索引被过滤掉了或者角度映射公式写错了。检查一下 (|\lambda/d \cdot k/M| \leq 1) 的条件确认哪些k值在可见区域内再做索引映射。另外如果阵列间距 (d/\lambda) 小于0.5那么可见区域对应的k值范围会比整个FFT长度的一半还窄也就是说只有一部分频点有物理意义。这时候画图要把无效部分隐去否则方向图会在两侧出现奇怪的跳变。经验做法是生成角度轴时直接用theta_k asin((lambda/d) * k / M)然后对abs(theta_k) 90的部分绘图。6.3 出现意料之外的栅瓣如果在实测的方向图中看到一个跟主瓣等高的“幽灵”波束多半是阵元间距超过了半波长。这里要区别两种情况如果阵列物理间距本来就大于0.5λ栅瓣是客观存在的FFT只是如实反映如果阵列间距设计没问题但方向图还是出现了栅瓣那可能是索引映射错误导致把虚拟空间的谱峰画进了可见范围。先用全谱不按valid过滤查看FFT完整输出确认栅瓣的实际角度位置再对照阵列参数判断是物理现象还是计算错误。我在调试一个稀疏阵列时曾经把 (d1.2\lambda) 的阵元的栅瓣当成了计算bug花了很长时间检查代码最后才发现是阵列设计本身就存在栅瓣。这种情况在布阵阶段就应该通过仿真确认不要等到实物测试时再惊讶。6.4 低旁瓣区域出现噪声底方向图在-60dB以下区域出现平坦的噪声底而不是继续平滑下降这是数值精度不足的典型表现。在MATLAB里默认双精度不会出现这个问题但如果用了单精度或者定点实现就要检查动态范围。解决办法有三个提高FFT的数据宽度、改用双精度浮点、或者对多个FFT结果做平均来降低随机噪声。有时候噪声底不是来自数值精度而是权值本身就有量化误差。比如你在FPGA里用定点数表示切比雪夫窗的系数量化误差会直接抬高旁瓣。我建议在嵌入式实现中窗函数系数尽量用查找表存储位宽不低于16位如果需要极低旁瓣可以存24位定点系数。6.5 峰值位置偏差一点FFT算出来的主瓣峰值角度跟理论值偏差了零点几度这通常不是算法错误而是角度采样网格不够细。FFT方法给出的方向图只是离散采样点上的值如果主瓣的真实峰值落在两个采样点之间画出来的峰值就会偏差最多半个采样间隔。解决办法很简单增加FFT点数M加密角度网格。注意这不会提高物理分辨率只是让峰值位置更精确。另外也可以用抛物线插值对FFT峰值附近做细估计精度可以提升到采样间隔的百分之一。6.6 幅度单位相差20dB方向图的纵坐标到底是线性幅度还是功率容易搞混。如果方向图用电压幅度归一化那应该用20log10如果已经取了平方功率就要用10log10。相差正好是一倍也就是20dB。我在报告里经常看到有人把这两个搞混导致旁瓣电平看起来比实际高了一倍。建议代码里用统一的归一化方式并且在画图时明确标注纵轴是“归一化电压方向图(dB)”。我个人在实际项目里的习惯是先把FFT计算结果归一化到最大值为1再取20log10画dB曲线。这样跟大多数文献里的方向图表达一致旁瓣电平数字也直接对应。做功率计算时再统一乘20不要混用。根据经验这个方法最实用的场景其实是自适应波束形成。每次迭代更新权值后除了看输出信噪比还要实时检查方向图的旁瓣有没有抬升、零陷有没有偏移。用FFT方式计算方向图之后这个检查步骤几乎不再消耗计算时间整个自适应迭代过程可以顺畅地跑起来。如果你也打算在自己的项目里用这招我唯一想嘱咐的是先让权值取一个简单的已知波束比如等幅同相跑通FFT方向图的整个链路确认角度轴、符号、单位全部正确再切换到实际权值。这套准备工作做好了后面基本不会出大问题。
返回列表