简介:编码超表面作为人工电磁结构,在雷达散射截面(RCS)调控与天线设计中具有广泛前景。该源码包围绕“编码超表面求RCS远场”主题,提供MATLAB实现,面向电磁仿真、超表面设计及遗传算法优化方向的研究者与工程师。压缩包共5个文件,以m脚本为主,含far_field_control.m、ga_min.m、func.m、threeD_visual.m等,另有同名asv自动保存文件,涵盖远场控制、遗传算法优化、三维可视化等功能模块,整体仅6KB,轻量便于快速部署与二次开发。已有429人学习使用。通过这份源码,读者可理解基于遗传算法优化超表面单元并计算远场RCS的完整流程,学习远场求解模型的搭建方法,掌握利用MATLAB进行电磁参数控制与结果可视化的思路,对开展超表面RCS减缩、波束调控等研究具有直接参考价值。
1. 编码超表面求 RCS 远场:先想清楚要算的是哪一层
“编码超表面_求RCS远场_超表面_源码.rar”这个标题把三类需求压在一起:编码矩阵怎么生成、RCS 远场怎么求、源码拿过来怎么跑。做编码超表面设计的人最常卡在两个地方:一是 HFSS、CST 全波仿真里一架 16×16 编码超表面要跑很久,每改一次编码矩阵就得重算一遍;二是仿真器导出的远场数据里,并没有直接按编码矩阵统计出来的单站 RCS 方向图,还需要自己后处理。标题里说的“求 RCS 远场”,最可靠的落地做法是口径场法加阵列因子:把每个编码单元当成相位已知的次级辐射源,用一组求和直接算出任意观测方向的散射场,再折算成 RCS。这套方法不需要全波求解器,MATLAB 或 Python 几十分钟就能搭起来,适合编码设计、参数扫描和优化迭代。下面先把这套近似成立的条件讲清楚,再给一版可以直接改参数跑通的最小源码。
2. 编码超表面 RCS 远场计算原理:编码矩阵怎么变成方向图
2.1 1 bit 编码超表面:编码矩阵到复数相位的最短映射
编码超表面和普通超表面的核心区别,是单元状态被离散成了有限种相位。1 bit 编码只有 0° 和 180° 两种反射相位,对应的反射系数恰好是 +1 和 −1,这是全反射结构里最容易实现的两种状态,也是“编码”这个词落地的起点。
| 编码值 | 反射相位 | 反射系数 Γ | 物理含义 |
|---|---|---|---|
| 0 | 0° | +1 | 同相反射 |
| 1 | 180° | −1 | 反相反射 |
编码矩阵到复数相位分布的映射只有一行:Γ(m,n) = exp(j·π·code(m,n)) = (-1)^code(m,n)。在 MATLAB 里写phase = exp(1j * pi * code),整块编码矩阵就变成了复数分布。2 bit 编码(0/90/180/270)只是把 code 的取值从 {0,1} 扩成 {0,1,2,3},公式形式不变。很多人打开标题里那种源码包,第一个要找的就是这几行“编码变复数”的代码,而不是后面的远场积分。
2.2 口径场法:为什么 RCS 远场可以只用求和完成
口径场法把超表面口径上的每个单元当成一个二次辐射源:入射平面波照到单元上,单元按自己的反射系数重新辐射。远场方向图等于所有单元在某个观测方向的矢量叠加,公式写成:
F(θ,φ) = Σ_m Σ_n Γ(m,n) · exp(j·k·(x_m·u + y_n·v)) u = sinθ·cosφ − sinθi·cosφi v = sinθ·sinφ − sinθi·sinφi坐标写成x_m = (m − (Nx−1)/2)·dx,把零点放到口径中心,避免相位参考点选在角点导致主瓣方向出现额外线性相位。θi、φi 是入射方向,正入射时都取 0。这个式子就是阵列因子,也是口径场法里唯一真正要算的东西。它成立的前提有三个:每个单元的辐射方向图相同、单元间互耦可忽略、观察点处于远场。对编码超表面这种单元周期性很强的结构,前两条在多数工程场景都能成立,计算误差主要来自斜入射时单元反射相位偏离设计值。
2.2.1 口径场法的两个边界条件
一是远场条件,观察距离要满足r ≥ 2D²/λ,D 是口径最大尺寸。算出来的方向图要描述的是 RCS 意义上的远场,不满足这个条件时得到的是近场扫描图,不能用同一套公式去套。二是等幅近似,口径场法默认每个单元上的场幅度相等,实际超表面单元在接近掠入射时幅度会下降。常见做法是一开始先用等幅算,看到主瓣、栅瓣位置对了,再回头补单元方向图因子。这个顺序能省掉大量排错时间,否则单元因子和编码错位时根本分不清是谁的问题。
2.3 手推 1×4 编码:主瓣裂开前先建立直觉
拿 1×4 的编码矩阵 [0,0,1,1] 试算,dx = λ/2,正入射,只看 φ = 0° 切面。阵列因子展开是:
F(θ) = 1 + e^{jπ·sinθ} − e^{j2π·sinθ} − e^{j3π·sinθ}在 sinθ = 0 处,四项是 1 + 1 − 1 − 1 = 0,主瓣不在这里;在 sinθ = 0.5 处,四项变成 1 + j + 1 + j = 2 + 2j,幅度最大,对应 30° 方向。这个结果和相位梯度法给的一致:两个单元一个周期,在 2·dx = λ 的距离上完成 0 到 π 的相位跳变,偏转角正好 30°。这一段手推很有用,后面任何源码跑出来的方向图,都要先拿这个尺度核对一下主瓣位置。
方向图幅度平方乘上口径因子就是 RCS。单站 RCS 关注发射和接收在同一方向时的散射强度,口径场法下写作:
σ = (4π·A² / λ²) · |F(θ,φ)|²A 是超表面总口径面积,F 按峰值归一化。σ 单位是 m²,转成 dBsm 用10*log10(σ)。RCS 缩减量一般拿同尺寸金属平板做参照,金属板镜面反射的理论峰值为4πA²/λ²,两者相减就是缩减深度,这个量后面做带宽评估时还要用到。
3. 用 MATLAB 跑通 RCS 远场计算源码:从编码矩阵到方向图
3.1 生成编码矩阵与口径坐标网格
先写参数区和坐标网格。这套代码按 30 GHz、16×16、半波长单元间距组织,任何一个参数改了,后面公式里的 k、dx、A 会自动跟着变。
% rcs_farfield_main.m % 编码超表面 RCS 远场计算,口径场法 clear; clc; % ---------- 参数区 ---------- lambda = 10e-3; % 工作波长 10 mm,对应 30 GHz dx = lambda / 2; % 单元间距 5 mm dy = lambda / 2; Nx = 16; % 编码矩阵行数 Ny = 16; % 编码矩阵列数 % 1 bit 编码,0 对应 +1,1 对应 -1 code = randi([0 1], Nx, Ny); % 随机编码,仅演示用 phase = exp(1j * pi * code); % 反射系数 = (-1)^code % 观测方向:theta 切面,phi 固定为 0 度 theta_deg = -90:0.1:90; phi_deg = 0; theta_i = 0; % 入射俯仰角,正入射为 0 phi_i = 0; % 入射方位角 k = 2 * pi / lambda; % ---------- 口径坐标 ---------- % 坐标原点放在口径中心,避免相位参考点偏置 x = ((0:Nx-1) - (Nx-1)/2) * dx; y = ((0:Ny-1) - (Ny-1)/2) * dy; [X, Y] = meshgrid(x, y);参数区里lambda决定所有尺寸,dx、dy和Nx、Ny一起决定口径面积 A,也决定后面栅瓣出现的位置。code用randi生成只是为了演示,真实设计时应该是一段序列生成器或者优化算法的输出。meshgrid生成的X、Y尺寸是 Ny×Nx,和phase一致,后续所有逐元乘法都依赖这个匹配关系。
3.2 远场积分的主体循环与 RCS 换算
远场积分按观测角度逐点累加。每个观测角算一次相位偏移,乘上反射系数后求和,再归一化得到阵列因子 F。
% ---------- 阵列因子 ---------- u = sind(theta_deg) * cosd(phi_deg) - sind(theta_i) * cosd(phi_i); v = sind(theta_deg) * sind(phi_deg) - sind(theta_i) * sind(phi_i); F = zeros(size(theta_deg)); for idx = 1:numel(theta_deg) phase_shift = exp(1j * k * (X * u(idx) + Y * v(idx))); F(idx) = sum(phase(:) .* phase_shift(:)); end F = F / (Nx * Ny); % 按单元数归一化 % ---------- 单站 RCS ---------- A = (Nx * dx) * (Ny * dy); % 口径面积 sigma = 4 * pi * A^2 / lambda^2 * abs(F).^2; sigma_dBsm = 10 * log10(sigma); % 找主瓣位置和电平 [peak_dB, peak_idx] = max(sigma_dBsm); fprintf('主瓣方向 θ = %.2f°,单站 RCS = %.2f dBsm\n', ... theta_deg(peak_idx), peak_dB);phase_shift里X * u(idx) + Y * v(idx)是口径面上每个点到观测方向的投影距离,乘上 k 变成相位延迟。sum(phase(:) .* phase_shift(:))把整个口径的贡献叠加起来,(:)把二维矩阵展成一维,保证乘法顺序一致。归一化除以 Nx·Ny 后,F 的量纲变成“单元数归一化的方向图因子”,峰值接近 1。RCS 三个关键量都在这里:A 决定口径面积,λ 出现在相位项和系数里,F 决定方向选择。想改切面时,把theta_deg和phi_deg改成另一组角度向量即可。
3.2.1 向量化改写:把角度循环压进三维矩阵
上面的循环对 16×16 迅速跑完,但编码矩阵到 64×64、角度网格到 200×400 时,循环版本会明显变慢。MATLAB R2016b 之后可以直接用隐式扩展做三维向量化:
% 三维向量化版本:theta x phi 二维网格一次算完 theta_vec = -90:0.5:90; phi_vec = 0:1:360; [TH, PHI] = meshgrid(theta_vec, phi_vec); % 入射方向仍取正入射,展开成 1x1xN 的列维度 u_grid = reshape(sind(TH) - sind(theta_i)*cosd(phi_i), 1, 1, []); v_grid = reshape(sind(PHI) - sind(theta_i)*sind(phi_i), 1, 1, []); % X、Y:Ny×Nx,u/v:1×1×N,隐式扩展成 Ny×Nx×N F3 = sum(phase .* exp(1j * k * (X .* u_grid + Y .* v_grid)), [1 2]); F3 = reshape(F3, size(TH)) / (Nx * Ny); sigma3 = 4 * pi * A^2 / lambda^2 * abs(F3).^2; [~, idx_peak] = max(sigma3(:)); fprintf('三维扫描主瓣:θ = %.2f°,φ = %.2f°\n', TH(idx_peak), PHI(idx_peak));X .* u_grid会让 Ny×Nx 的矩阵和 1×1×N 的向量做广播,生成 Ny×Nx×N 的复数数组。这个写法把双层循环变成矩阵运算,但内存占用随 N 线性增长,64×64 口径配 200×400 角度网格时,中间数组接近 3 GB,一般机器会吃不消。工程上按需选择:切面扫描用循环,三维扫描用向量化,或者把角度网格拆成几批做分块计算。
3.3 方向图输出:一维切面和二维云图各看什么
计算完成后,建议同时看两种图:一维切面看副瓣电平和主瓣宽度,二维云图看栅瓣和不对称性。
% 一维切面:phi = 0 度 figure; plot(theta_deg, sigma_dBsm, 'LineWidth', 1.2); xlabel('θ (°)'); ylabel('单站 RCS (dBsm)'); grid on; ylim([-30 20]); % 二维云图:theta x phi 全景 figure; imagesc(theta_vec, phi_vec, 10*log10(sigma3)); axis xy; colorbar; xlabel('θ (°)'); ylabel('φ (°)'); title('编码超表面 RCS 远场方向图');一维图适合读主瓣位置、第一副瓣电平和零深,判断编码序列的偏转效果。二维图适合找栅瓣——方向图里除了主瓣外突然冒出来的等幅峰,通常对应编码序列的周期性或者单元间距过大。ylim([-30 20])是经验值,16×16 口径的金属板镜面峰值约 33 dBsm,缩减 20 dB 后还剩 13 dBsm 量级,具体上下限根据 A 和 λ 调。
3.4 用 Python 做同一套计算,两套源码互相纠错
MATLAB 跑通后,不建议只信一套代码。常见做法是把同一组参数用 numpy 复算一遍,直接对比主瓣角度和峰值 RCS。
import numpy as np # 与 MATLAB 版本保持相同参数 lam = 10e-3 dx = dy = lam / 2 Nx = Ny = 16 k = 2 * np.pi / lam code = np.random.randint(0, 2, (Nx, Ny)).astype(float) phase = np.exp(1j * np.pi * code) x = (np.arange(Nx) - (Nx - 1) / 2) * dx y = (np.arange(Ny) - (Ny - 1) / 2) * dy X, Y = np.meshgrid(x, y) theta = np.deg2rad(np.arange(-90, 90.01, 0.1)) u = np.sin(theta) # 正入射且 phi = 0 切面 v = 0 # 外积广播:cell 数量 x 角度数量 field = phase.ravel()[:, None] * np.exp(1j * k * (X.ravel()[:, None] * u[None, :])) F = field.sum(axis=0) / (Nx * Ny) A = (Nx * dx) * (Ny * dy) sigma = 4 * np.pi * A**2 / lam**2 * np.abs(F)**2 sigma_dBsm = 10 * np.log10(sigma) peak_idx = np.argmax(sigma_dBsm) print(f"theta_peak = {np.rad2deg(theta[peak_idx]):.2f} deg")phase.ravel()[:, None]把所有单元展成列向量,u[None, :]把角度展成行向量,两者做外积,每个单元对所有角度一次算完,这是 numpy 里替代双层循环的标准姿势。关键是X.ravel()、phase.ravel()用同一套展平顺序,行列数对不上时方向图会整个错位。和 MATLAB 结果对比时,固定同一组code,比峰值角度和sigma_dBsm的最大值,误差应在 1e-10 量级。能对上,说明编码矩阵、坐标网格、RCS 系数三个环节都没漏。
4. 求 RCS 远场的参数优化与典型坑:单元间距、频率与切面扫描
4.1 单元间距和工作频率:栅瓣是第一个要躲的坑
编码超表面的单元间距由工作频率决定,通常取 0.33λ 到 0.5λ。间距超过 0.5λ 后,方向图里可能出现与主瓣等幅的栅瓣,这是 RCS 计算里最容易被漏掉的问题。栅瓣出现的条件可以写成:
sinθ_g = sinθi ± p·λ/dx,p = 1, 2, ...只要 λ/dx 的数值让右侧落在 [−1, 1] 区间内,就存在真实的栅瓣方向。dx = 0.5λ 时 λ/dx = 2,正入射下 p=1 已经超出区间,安全;dx = 1λ 时 λ/dx = 1,±90° 方向会出现栅瓣边缘。改频率前先看 dx/λ,不要只盯着谐振频率和相位覆盖。另一个关联问题是编码序列的周期性:比如每隔 4 个单元重复一段编码,等效周期是 4·dx,会在更小的角度上引入高阶衍射峰。
4.2 扫描范围、角度步进与口径尺寸的关系
主瓣宽度由口径尺寸决定,16×16、dx = 0.5λ 时主瓣半宽约0.886·λ/(N·dx),算下来约 6.3°,因此扫描步进取 0.1° 到 0.5° 已经足够定位峰值。步进取 0.01° 只会增加计算量,不会带来新的物理信息。扫描范围建议直接取整个上半空间 ±90°,因为 RCS 缩减设计里栅瓣和副瓣可能出现在任意斜角,只看 ±30° 容易得出“缩减效果很好”的错误结论。如果编码矩阵存在对称性,可以只算 1/4 球面再镜像,但随机编码通常不对称,这个加速手段不要乱用。
| 参数 | 建议取值 | 对结果的影响 | 常见误区 |
|---|---|---|---|
| dx, dy | 0.33λ ~ 0.5λ | 决定栅瓣位置和口径单元数 | 超过 0.5λ 后方向图出现伪峰 |
| Nx, Ny | 16×16 ~ 64×64 | 决定主瓣宽度和计算量 | 阵列太大时循环版本明显变慢 |
| 入射角 θi | 0° 起步 | 决定主瓣相对位置 | 斜入射时单元反射相位会偏 |
| 切面扫描范围 | ±90° | 覆盖整个上半空间 | 只扫主瓣附近会漏掉栅瓣 |
| 角度步进 | 0.1° ~ 0.5° | 峰值定位精度 | 小于 0.05° 只是增加耗时 |
| 频率扫描 | 扫 3~5 个频点 | 评估 RCS 缩减带宽 | 单频结果不能代表宽带性能 |
4.3 边缘截断和幅度锥削:均匀编码的副瓣代价
均匀编码矩阵的方向图第一副瓣电平约 −13.3 dB,这是矩形口径傅里叶变换的固有特性。想压副瓣,常见手段是幅度锥削,比如给边缘单元乘上汉宁窗系数。但编码超表面做 RCS 缩减时,锥削会降低有效口径面积,反而削弱主瓣方向的缩减深度,而且编码单元本身只有相位可控,幅度锥削需要额外加载损耗结构。工程上更实用的做法是保持等幅,用优化算法调整编码序列把副瓣能量打散到多个方向,方向图从“单个高副瓣”变成“底噪抬升”,RCS 缩减效果用统计平均来评估。做参数扫描时,把编码矩阵固定好再单独扫 dx/λ 和入射角,三个变量一起动时出了问题很难定位。
5. 拿远场结果反推编码超表面设计:峰值验证、带宽评估与优化闭环
5.1 用方向图峰值反推偏转角,和相位梯度公式对表
方向图算完,第一件事是把主瓣角度和理论偏转角对表。1 bit 编码超表面的偏转角由相位梯度决定,公式是:
sinθ_peak = sinθi + (λ / 2π) · (dφ/dx)前面手推的 [0,0,1,1] 编码,两单元一个周期,相位差 π,梯度 π/(2·dx),dx = λ/2 时恰好给出 sinθ_peak = 0.5,即 30°。在 MATLAB 里峰值角度已经被theta_deg(peak_idx)打出来了,直接把 code 换成周期序列再算一次,看打印结果是不是 30°。这个验证步骤比看 RCS 缩减量更重要,主瓣方向对不上,后面所有优化都是在错误坐标系里做。
5.2 RCS 缩减带宽评估:多频点循环和金属板参考
单频 RCS 缩减只能说明谐振点附近的效果。带宽评估做法是循环 5 到 10 个频点,每个频点重新计算 k、dx/λ 和 RCS,再和同口径金属板比:
freqs = linspace(28e9, 32e9, 9); reduction = zeros(size(freqs)); for fi = 1:numel(freqs) kf = 2 * pi * (freqs(fi) / 3e8); % 重新算 F 和 sigma,代码同第 3 节 % reduction(fi) = 10*log10(sigma_peak / sigma_metal); end plot(freqs / 1e9, reduction); xlabel('频率 (GHz)'); ylabel('RCS 缩减量 (dB)');注意频率变化时 dx/λ 也在变,单元间距固定为物理尺寸 5 mm,28 GHz 下是 0.47λ,32 GHz 下是 0.53λ,栅瓣风险随之变化。RCS 缩减量低于 −10 dB 的频带才是有效带宽,评估时务必把金属板参考峰值按当前频点重算,不能用一个固定值。
5.3 把方向图函数接进优化循环,编码矩阵是唯一的自变量
远场计算函数化之后,整个设计可以变成标准的整数优化问题:输入 Nx×Ny 的 0/1 矩阵,输出主瓣方向 RCS 缩减量。每次迭代只改编码矩阵,不需要全波重算,一次方向图评估在普通笔记本上是毫秒级,遗传算法跑几千代完全可行。函数签名建议写成sigma_dB = rcs_eval(code, lambda, dx, dy, theta_obs, phi_obs),优化器每次调用时传入新的 code,把缩减量取负作为适应度。优化前先用手推的 1×4 编码验证rcs_eval输出的峰值角度,再放开随机矩阵,最后把每个候选结果的编码矩阵、dx/λ、入射角一起存进文件名,否则 20 组参数扫完,峰值对不上是哪一组算出来的。
本文还有配套的精品资源,点击获取