本教程的大纲包括:理论讲解、历史部分、应用、Python代码、HFSS中的自动化结构、HFSS仿真,最后将讨论仿真结果。

在本教程的第一部分“理论讲解”中,我们将讨论超表面设计的不同理论方面。首先,我们将介绍超表面的一些背景知识;接着,我们将解释如何计算超表面每个单元的相位;然后,我们将展示不同超表面配置的公式;最后,我们将展示一些不同超表面配置的实例。
为了更熟悉超表面的概念,让我们先解释一些背景信息。超表面是人工设计的结构材料,用于控制电磁波。它由一系列单元(通常称为“超原子”)组成,这些单元可以独立操控入射波的幅度、相位和偏振。操控和控制波的能力来自于在超表面的每个单元上引入特定的相移。
我们尝试解释如何获得超表面每个单元所需相位的公式。本幻灯片展示的公式用于计算反射阵列(超表面的一种,设计用于将波反射并导向指定方向)中每个单元所需的相移。

让我们将公式分解成几个易于理解的部分:
这是一个关于阵列天线波束成形与轨道角动量(OAM)调制的相位综合公式。我们将整个相位函数记为 ,它是空间坐标
的标量场。
设自由空间波数为 :
其中 为波长,
为角频率。
定义第 个辐射单元的位置矢量为
:
定义参考点(或馈源相位中心)的位置矢量为 :
定义目标波束指向的单位方向矢量 。在球坐标系中,该矢量由俯仰角
和方位角
确定:
原公式可以重写为矢量形式以便于分析:
其中 为拓扑荷数。
我们将后两项合并,考察其矢量结构。令扫描相位项为 。
展开括号内的项:
观察系数,这正是位置矢量 与目标方向单位矢量
的点积(内积):
因此,扫描项可以紧凑地写为:
我们可以把位置矢量 与目标方向单位矢量
的点积(内积)
拆分为两部分之和。首先,我们需要明确什么是“横向”和“纵向”分量:
原点积公式为:
根据矢量点积的性质,不同轴向的单位矢量点积为0(例如 ),只有同轴的点积为1(例如
)。因此,我们可以把
拆分为两部分之和:
A. 纵向分量 (Vertical Component),直接对应 轴:
物理意义: 这就是图片中提到的 Conformality Adjustment。如果天线阵元有高度差(),这一项就不为零,必须补偿。
B. 横向分量 (Horizontal Component),这是 平面内的点积运算:
展开计算():
提取公因式 :
物理意义: 这就是图片中提到的 Elevation Adjustment。它描述了波束在水平面上的投影关系。当 (垂直向上看)时,
,这一项消失,符合物理直觉。
普通平面波的波前是平整的,相位在横截面上均匀分布;而OAM涡旋波的波前则呈螺旋状,如同旋转楼梯一般,绕轴一周相位会累积 的整数倍变化。正是这种独特的螺旋波前结构,使得其相位必须随方位角线性变化。
平面波之所以没有角度项,是因为它是角向模式数 的特例。它的相位只随传播距离(
轴)变化,而在横截面(
平面)上是均匀分布的,不存在随方位角旋转而产生的相位延迟。
为了从数学上严格描述这一物理图像并导出角向分量 这一核心关系,我们需要回到波动方程本身进行求解。
在柱坐标系 下求解标量亥姆霍兹方程(即波动方程的频域形式)时,我们采用分离变量法,假设电场分布
可以分解为径向、角向和纵向三个独立函数的乘积。为了保证物理场的单值性——即绕着传播轴旋转
(
) 回到原点时,电磁场必须重合且连续——角向分量
必须满足严格的周期性边界条件。满足这一条件的唯一数学解是复指数形式:
其中,
必须是整数。当我们把这个解写成标准的幅度-相位形式
时,可以直接从指数部分提取出相位项
。这就是 OAM 相位随方位角
线性变化的根本物理来源。
在柱坐标系 中,标量亥姆霍兹方程为:
其中拉普拉斯算子在柱坐标下的表达式为:
采用分离变量法,假设电场分布 。将其代入亥姆霍兹方程,并除以
,可得:
由于 方向的传播通常具有平移不变性(或为行波形式),我们设纵向部分为
,则
。方程简化为:
令 (横向波数平方),并将含
的项分离出来:
由于第一项只与 有关,第二项只与
有关,它们必须分别等于常数。我们令角向部分的分离常数为
(通常取负值以保证振荡解),即:
上述二阶常微分方程的通解可以写为三角函数形式或复指数形式:
根据物理场的单值性要求,绕传播轴( 轴)旋转
(即
弧度)回到原点时,场必须重合且连续。这意味着角向分量必须满足:
我们将通解代入该条件进行分析。以复指数基函数 为例:
为了满足 ,必须有:
根据欧拉公式 ,要使
,必须满足:
这说明 必须是
的整数倍,即:
必须为整数(称为角向模数)。
当 为整数时,
和
都是满足周期性条件的独立解(对于
,两者重合为常数)。
在电磁场理论中,为了方便表示旋转方向(如左旋/右旋)以及进行傅里叶级数展开,我们通常选取复指数形式作为基函数。对于给定的整数 ,最简洁且完备的角向函数就是:
由于任何满足周期的实函数(如 )都可以由
和
线性组合而成,因此复指数形式
是满足单值性周期性边界条件的最基础、唯一的数学本征解形式。
基于上述理论推导,在设计反射阵或超表面以产生 OAM 波束时,我们需要为第 个单元(或空间中任意一点)赋予特定的附加相移。该相位项
仅依赖于该点在横截面(
平面)上的方位角
,其核心定义公式为:
在这个公式中,包含两个关键参数:
为了将上述理论公式应用于计算机仿真或实际的阵列排布,必须建立方位角 与直角坐标
之间的数值计算关系。这里存在一个从理想数学到工程计算的细节处理。最直观的数学表达是使用标准的反正切函数
:
然而,标准的 函数值域被限制在
之间(仅覆盖第一、四象限)。当单元位于第二或第三象限(即
)时,
的符号会导致计算出的角度发生
的错误跳变。这种不连续性会破坏 OAM 波束螺旋相位的完整性,导致相位奇点错误。
因此,为了在数学上严格处理全平面 的角度连续性,必须使用四象限反正切函数 atan2。最终的工程计算公式为:
该函数能够根据 和
的正负号自动判断象限,从而确保生成的相位分布在
范围内是严格连续且平滑的。
直角坐标 、极径
与方位角
之间遵循标准的柱坐标变换关系:
这一组关系式确保了我们可以灵活地在直角网格(用于加工制造)和柱坐标相位分布(用于物理原理)之间进行转换。
注记(分支割线): 在负
轴(射线
)上引入了分支割线,
跨线时跳变
。但物理场中只出现单值因子
,故割线的选取不影响任何物理量;同时,下文将看到
在
上是光滑、单值的矢量场,与分支选取无关。多值性恰恰是该场拓扑非平庸的表现。
在波动光学中,场的复振幅通常包含因子 。对于 OAM 项,我们有:
利用欧拉公式 ,我们可以将其重写为直角坐标形式:
引入复坐标 ,上式即
。这个表达式
揭示了 OAM 波束在复平面上的解析性质:它在原点
处有一个
阶零点(若
)或极点(若
)。
在原点处 ,方位角
无定义(所有角度射线在此交汇),故
在该点不能连续取值,称为相位奇点(Phase Singularity)。为保证场在物理上连续且有限,振幅必须在奇点处趋于零(物理光束中振幅在原点附近通常满足
,恰好抵消极点发散),即
因此波束中心光强为零,形成著名的暗核(Dark Core)现象。
为了量化波束波前在绕 轴旋转一周时的相位累积总量,我们通过计算相位梯度沿闭合回路的线积分来进行分析。
考虑一个以 轴为中心、半径为
(
)的圆形闭合路径
。路径参数化为:
对参数求微分,得切向路径微元:
其中 为柱坐标系方位角单位矢量。
柱坐标系下梯度算子为 。作用于
(仅
方向有变化),得在
处:
该矢量场在 上处处光滑、单值,且局部无旋:
。在路径
上
为常数,代入并利用
:
于是:
路径无关性。 设 为任意两条包围原点的闭合路径,二者围成一个不含原点的环形区域
。在
上
,由斯托克斯定理
,故积分值与路径形状无关,只取决于路径是否包围奇点(不包围原点时积分为
)。因此
是拓扑不变量,而非某条特殊圆路径的巧合。
结论:
这意味着,当围绕 轴旋转一周时,相位增加了
的整数倍
。
为了理解波是如何传播的,我们需要分析总相位的梯度。总相位 包含扫描项和 OAM 项。这里我们专注于 OAM 项产生的局部波矢量分量。
在柱坐标系 中,梯度算子为:
对 应用梯度算子:
因此,OAM 项贡献的相位梯度为:
局部波矢量 :
根据几何光学近似,局部波矢量定义为总相位的梯度:
其中 是一个纯粹沿方位角方向的分量。
这表明,除了主要的传播方向(由 决定,通常沿
轴或扫描方向
)外,波矢量还有一个横向的旋转分量。
波矢量的大小(模)应满足色散关系 。
设主传播方向为 轴,则
。
(注:这仅在 时成立,即在暗核之外。在暗核内部,傍轴近似失效,需使用严格的衍射理论)。
这个横向分量 意味着光线不是直线向前传播,而是沿着螺旋线路径传播。
坡印廷矢量与能量流
坡印廷矢量 描述了电磁能量的流动方向。在无耗散介质中,
的方向与局部波矢量
平行(对于各向同性介质)。
由于 包含方位角分量
,能量流密度
也具有方位角分量:
其中 。
能量不仅沿 轴向前传输,还绕着
轴旋转。能流线(Streamlines)呈螺旋状。这种旋转的能量流正是轨道角动量的宏观表现。
轨道角动量 (OAM) 的量子化与经典对应
经典电磁学视角:
电磁场的角动量密度 定义为:
其中 是线性动量密度,
(在真空中)。
我们要计算的是沿传播方向( 轴)的角动量分量
。
在柱坐标下,。
由于 ,则:
可以看到, 被消去了。这意味着角动量密度与能量密度
成正比,比例系数为
。总角动量
与总能量
的关系为:
其中 是角频率。
量子力学视角:
如果我们把电磁波看作光子流,每个光子的能量为 。设光子通量为
(每秒光子数),则总功率
,总能量流对应的时间平均角动量流率(扭矩)为
。
由经典关系 ,我们可以推导出单个光子携带的角动量:
令其等于 :
结论:每个光子携带的 OAM 为 。




本幻灯片展示了不同配置下超表面的单元相位分布实例:
平面超表面法向波束、

凹面超表面法向波束、

凸面超表面法向波束、

凸面超表面波束指向60°、

凸面超表面OAM模式3/10/20的法向波束、

凹面超表面OAM模式3/10/20的法向波束、
凸面/凹面超表面OAM模式3且波束指向60°的情形。

在本部分中,我们解释用于在HFSS环境中自动化创建结构的三个Python代码部分,包括:json_data_creator.py(代码讲解)、generate_hfss_script.py(代码讲解)、plotter.py(代码讲解)。


所需软件包:
安装所需软件包:打开命令提示符或终端,运行 pip install numpy pandas scipy matplotlib
这段代码是超表面(反射阵列)设计流程中的“相位综合与贴片尺寸预计算”脚本。它本身不做任何电磁仿真,而是完成纯数学计算:根据反射阵列的经典相位公式,算出口径面上每个超原子单元需要提供多少相位补偿,再通过查找表把这个相位“翻译”成贴片的物理尺寸,输出两个数据文件,供后续脚本在 HFSS 中自动建模和绘图。
它在自动化流程中的位置是:
代码块
PlainText
自动换行
复制代码
1234567
HFSS 单元仿真(Floquet 端口 + 贴片尺寸参数扫描)
│ 导出 phase_vs_size.csv(相位-尺寸查找表)
▼
★ 本脚本:相位综合 + 尺寸映射
│
├──> patch_data.json ──> generate_hfss_script.py(HFSS 自动建模)
└──> phase_data.csv ──> plotter.py(绘制相位分布图)
复制成功
查找表来自前期 HFSS 中对单元的 Floquet 端口仿真与贴片尺寸参数扫描,记录了“贴片边长 → 反射相位”的单调对应关系,例如贴片从 增大到
时,反射相位从
单调降至
。它是连接理论与工程的桥梁:理论告诉每个单元“需要多少相位”,查找表告诉工程师“多大的贴片能提供这个相位”。
① `load_unit_cell_data()` — 加载查找表。用 pandas 读取 CSV,把相位列 和尺寸列
分别转成 numpy 数组返回。
② `calculate_patch_size()` — 相位到尺寸的最近邻匹配。查找表只含有限个离散尺寸点(步长由 HFSS 参数扫描决定),算出的目标相位一般不会精确命中表中的某个值,因此采用最近邻匹配:
即在全表中找相位差绝对值最小的条目并返回其尺寸。这种处理天然带有量化误差,误差上界就是查找表的步长,属于反射阵列设计的固有近似。
③ `pre_calculate_data()` — 主函数,封装全部设计逻辑,下面逐步展开。
1. 基本电磁参数
工作频率取 (必须与 HFSS 单元仿真同频点,否则查找表失效),由此计算波长与波数:
其中 是把光速从
换算到
的单位换算。
2. 设计参数
期望波束指向取 ,即法向 broadside 辐射;馈源(喇叭天线相位中心)坐标取
;口径直径
,真实半径为
;单元间距
,满足亚波长周期、抑制栅瓣的要求;OAM 模式指数
(普通波束,
时产生涡旋波束);焦径比
。参考相位
的作用是把取模后落在
的相位平移到工程范围
,与 HFSS 导出的 S 参数相位范围对齐:
3. 共形面(抛物面)参数
焦距与矢高按以下公式计算:
本例 使
,几乎可以忽略——实质上把共形面近似成了平面口径。而馈源实际位于
处的偏离由相位公式中的路径项独立补偿,两者并不矛盾。每个单元的高度服从旋转抛物面方程:
符号由 sign_z 控制( 为凸面,
为凹面),中心处
,边缘处(
)
。
4. 网格生成与 OAM 相位
以单元间距 为步长生成覆盖
的
方形网格(rad % uedim 项保证口径直径非单元间距整数倍时网格仍对称居中),并在每个网格点上计算 OAM 螺旋相位项:
当 时该项恒为零;当
时,形成绕中心旋转
的螺旋相位面,产生涡旋波束。
5. 核心:反射阵列相位公式
对每个通过圆形口径筛选 的单元(最终约 305 个有效单元),先计算馈源到它的空间距离:
再套入全脚本的相位公式:
三项各有分工:
这个公式本质上是标准反射阵列综合条件的代码化。设期望波束方向的单位矢量为:
单元位置矢量为 ,则综合条件为:
展开内积即得上面的三项式,完全等价。
6. 相位合成与取模
空间相位与 OAM 相位相加后,对 取模(利用相位周期性,相差
整数倍的波前完全等价),再转成度数并加上参考相位:
7. 尺寸映射与结果
最终相位 一方面存入二维相位矩阵(口径外保持 NaN,绘图时自然显示空白),另一方面送入最近邻匹配得到贴片边长
,连同坐标一起记录为一条单元数据
。循环结束后输出两个文件:






















脚本末尾的 if __name__ == "__main__" 保证它被直接运行时才执行主函数,被 import 时不产生副作用。
代码块
PlainText
自动换行
复制代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
import numpy as np
import pandas as pd
from scipy.constants import speed_of_light
# 导入科学计算库:numpy用于数值计算,pandas用于数据读写,speed_of_light为光速常量(299792458 m/s)
# ===================== 函数1:加载单元胞数据 =====================
def load_unit_cell_data(file_path):
"""
从CSV文件中加载预仿真的单元胞(phase vs size)数据。
CSV文件应包含两列:'Phase'(反射相位,单位度) 和 'Size'(patch尺寸,单位mm)。
这是超表面设计的基础查找表(Look-Up Table)。
"""
df = pd.read_csv(file_path)
# 读取CSV文件,假设列名为 'Phase' 和 'Size'
phases = df['Phase'].to_numpy() # 提取相位列,转为numpy数组
sizes = df['Size'].to_numpy() # 提取尺寸列,转为numpy数组
return phases, sizes
# ===================== 函数2:根据目标相位查找patch尺寸 =====================
def calculate_patch_size(target_phase, phases, sizes):
"""
给定一个目标相位值,在查找表中找到最接近的相位对应的patch尺寸。
这是超表面设计的核心映射:相位 → 几何尺寸。
"""
idx = (np.abs(phases - target_phase)).argmin()
# 计算目标相位与所有预仿真相位的绝对差,取最小值的索引
return sizes[idx]
# 返回该索引对应的patch尺寸
# ===================== 函数3:预计算所有patch数据(主函数) =====================
def pre_calculate_data(output_file="patch_data.json", phase_data_file="phase_data.csv"):
"""
主计算函数:根据超表面设计参数,计算每个单元胞的位置、高度、所需相位和对应patch尺寸,
最终输出两个文件:
- patch_data.json:每个patch的坐标和尺寸(供HFSS脚本读取建模)
- phase_data.csv:2D相位分布图数据(供Plotter.py绘图)
"""
# ---------- 1. 加载单元胞查找表 ----------
phases, sizes = load_unit_cell_data("phase_vs_size.csv")
# 从 "phase_vs_size.csv" 加载预仿真的 相位-尺寸 对应关系
# ---------- 2. 用户自定义参数 ----------
freq = 30e9 # 工作频率:30 GHz
wavelength = (speed_of_light * 1000) / freq
# 计算自由空间波长(mm):λ = c / f,乘以1000将m转换为mm
k = 2 * np.pi / wavelength # 自由空间波数(rad/mm)
the_dir = 0 # 波束指向:theta方向(度),0表示法线方向
phi_dir = 0 # 波束指向:phi方向(度),0表示x-z平面
pha_zer = -180 # 参考相位偏移(度),用于调整整体相位基准
x_cor, y_cor, z_cor = 0, 0, 55 # 馈源位置坐标(mm):位于z=55mm处,即焦点附近
rad = 100 # 超表面口径直径(mm)
uedim = 5 # 单元胞间距/周期(mm)
OAM_m = 0 # 轨道角动量(OAM)模式数,0表示不携带OAM
FOD = 1000 # F/D比(焦距/口径比),1000表示近似平面波(准直)
f = FOD * rad # 焦距(mm) = F/D × D = 1000 × 100 = 100000 mm
# ---------- 3. 计算共形曲面参数 ----------
h = (rad ** 2) / (16 * f)
# 抛物面顶点高度(mm):h = D²/(16f),这是抛物面方程 z = h - (x²+y²)/(4f) 的顶点值
sign_z = +1 # 共形模式:+1=凸面(Convex),-1=凹面(Concave)
# ---------- 4. 生成二维坐标网格 ----------
xi_range = np.arange(-rad/2 + rad % uedim, rad/2 + uedim, uedim)
yi_range = np.arange(-rad/2 + rad % uedim, rad/2 + uedim, uedim)
# 在 [-rad/2, rad/2] 范围内以 uedim 为步长生成离散坐标点
# rad % uedim 用于处理口径不能被周期整除时的边界对齐
XI, YI = np.meshgrid(xi_range, yi_range)
# 生成二维网格坐标矩阵
# ---------- 5. 计算OAM角向相位 ----------
angular_phase = OAM_m * np.arctan2(YI, XI)
# OAM相位 = m × arctan(y/x),当 OAM_m=0 时此项为0(不携带涡旋相位)
# ---------- 6. 初始化存储数组 ----------
phase_deg_2d = np.full(XI.shape, np.nan)
# 初始化2D相位数组,用NaN填充(圆口径外的区域保持NaN)
patch_data = []
# 初始化patch数据列表,每个元素是一个字典
# ---------- 7. 遍历网格,逐个计算patch参数 ----------
for ix, xi in enumerate(xi_range):
for iy, yi in enumerate(yi_range):
# 只处理圆形口径内的单元胞
if np.sqrt(xi**2 + yi**2) < rad/2:
# --- 7a. 计算该位置的曲面高度(抛物面方程) ---
zi = sign_z * (h - (xi**2 + yi**2) / (4 * f))
# 抛物面方程:z = ±[h - (x²+y²)/(4f)]
# sign_z=+1 为凸面,sign_z=-1 为凹面
# --- 7b. 计算馈源到该单元胞的距离 ---
R = np.sqrt((x_cor - xi)**2 + (y_cor - yi)**2 + (z_cor - zi)**2)
# 三维欧氏距离:从馈源(x_cor,y_cor,z_cor)到patch中心(xi,yi,zi)
# --- 7c. 计算补偿相位(空间相位延迟) ---
phase = k * (
R # 球面波传播相位
- zi * np.cos(np.deg2rad(the_dir)) # 波束指向补偿(theta分量)
- np.sin(np.deg2rad(the_dir)) * ( # 波束指向补偿(横向分量)
xi * np.cos(np.deg2rad(phi_dir))
+ yi * np.sin(np.deg2rad(phi_dir))
)
)
# 总相位 = k × [R - zi·cosθ - sinθ·(xi·cosφ + yi·sinφ)]
# 这是将球面波转换为指定方向平面波所需的相位补偿公式
# --- 7d. 叠加OAM相位并转换为角度 ---
m_phase = np.mod(angular_phase[iy, ix] + phase, 2 * np.pi)
# 总相位 = (OAM角向相位 + 空间补偿相位) mod 2π,限制在[0, 2π)
m_phase_deg = m_phase * 180 / np.pi + pha_zer
# 转换为角度制,并加上参考相位偏移(-180°)
# --- 7e. 存储相位到2D数组 ---
phase_deg_2d[iy, ix] = m_phase_deg
# --- 7f. 根据相位查找对应的patch尺寸 ---
patch_size = calculate_patch_size(m_phase_deg, phases, sizes)
# 在查找表中找最接近 m_phase_deg 的相位,返回对应的patch尺寸
# --- 7g. 记录该patch的所有参数 ---
patch_data.append({
"xi": xi, # x坐标(mm)
"yi": yi, # y坐标(mm)
"zi": zi, # z坐标/曲面高度(mm)
"patch_size": patch_size, # patch边长(mm)
"m_phase_deg": m_phase_deg # 计算得到的目标相位(度),仅供参考
})
# ---------- 8. 保存结果文件 ----------
# 保存2D相位分布到CSV(供Plotter.py绘制相位分布图)
pd.DataFrame(phase_deg_2d).to_csv(phase_data_file, header=False, index=False)
# 保存patch数据到JSON(供Generate_hfss_script.py读取并在HFSS中自动建模)
pd.DataFrame(patch_data).to_json(output_file, orient="records")
# ===================== 程序入口 =====================
if __name__ == "__main__":
pre_calculate_data("patch_data.json", "phase_data.csv")
# 执行预计算,输出 patch_data.json 和 phase_data.csv
复制成功
HFSS 内置的 Python 解释器基于 Python 2.7,默认只认 ASCII。文件开头添加 # -*- coding: utf-8 -*-
本脚本使用HFSS内嵌的Python环境(Python 2.7),该环境与功能完整的Python不同。需确保已安装HFSS并设置好项目。
代码块
PlainText
自动换行
复制代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
# -*- coding: utf-8 -*-
import ScriptEnv
import json
# ScriptEnv: HFSS内置脚本环境模块(非标准Python库,仅在HFSS脚本编辑器中可用)
# json: 用于读取patch_data.json数据文件
def main():
# ===================== 1. HFSS环境初始化 =====================
ScriptEnv.Initialize("Ansoft.ElectronicsDesktop")
# 初始化HFSS脚本环境,连接到Ansys Electronics Desktop应用
oDesktop.RestoreWindow()
# 恢复HFSS桌面窗口到前台
oProject = oDesktop.SetActiveProject("metasurface")
# 激活名为 "meta-surface7" 的已有项目(项目名称硬编码,需与实际项目名一致)
oDesign = oProject.SetActiveDesign("HFSSDesign1")
# 激活项目中名为 "HFSSDesign1" 的设计
oEditor = oDesign.SetActiveEditor("3D Modeler")
# 激活3D建模器,后续所有几何创建操作都通过此对象执行
# ===================== 2. 加载预计算的patch数据 =====================
with open("F:\\patch_data.json", "r") as f:
patch_data = json.load(f)
# 硬编码的绝对路径!从Jason_data_creator输出的JSON文件中读取所有patch参数
# 每个元素包含: xi, yi, zi, patch_size, m_phase_deg
# ===================== 3. 用户定义的全局固定参数 =====================
ground_height = 0.1 # 接地板厚度(mm)
dielectric_height = 1.0 # 介质基板厚度(mm)
top_patch_height = 0.1 # 顶部金属贴片厚度(mm)
dielectric_material = "Rogers RO3003 (tm)" # 基板材料名称(必须在HFSS材料库中存在)
uedim = 5 # 单元胞间距/周期(mm),与Jason_data_creator中的uedim一致
# ===================== 4. 遍历每个patch,创建三层结构 =====================
for i, patch in enumerate(patch_data):
xi = patch["xi"] # patch所在单元胞的x坐标(mm)
yi = patch["yi"] # patch所在单元胞的y坐标(mm)
zi = patch["zi"] # patch所在曲面高度z坐标(mm),来自抛物面方程
patch_size = patch["patch_size"] # 该位置对应的patch边长(mm)
# 计算patch中心坐标(在单元胞内居中)
xi_center = xi + uedim / 2
yi_center = yi + uedim / 2
# 注意:这里将(xi,yi)视为单元胞左下角,patch在其中心偏移uedim/2处
# ---------- 4a. 创建接地板(Ground) ----------
oEditor.CreateBox(
[
"NAME:BoxParameters",
"XPosition:=", "{}mm".format(xi), # X起点 = 单元胞左下角x
"YPosition:=", "{}mm".format(yi), # Y起点 = 单元胞左下角y
"ZPosition:=", "{}mm".format(zi - 0.0001), # Z起点 = 曲面高度略下方(避免与patch重叠)
"XSize:=", "{}mm".format(uedim - 0.0001), # X尺寸 = 周期略小(避免相邻ground接触)
"YSize:=", "{}mm".format(uedim - 0.0001), # Y尺寸 = 周期略小
"ZSize:=", "{}mm".format(ground_height) # Z尺寸 = 接地板厚度
],
[
"NAME:Attributes",
"Name:=", "Ground_{}".format(i), # 唯一命名: Ground_0, Ground_1, ...
"MaterialValue:=", "\"pec\"", # 材料: 理想电导体(PEC)
"SolveInside:=", False # PEC内部不求解电磁场
]
)
# zi - 0.0001 和 uedim - 0.0001 是防止几何重合/相交的微调技巧
# ---------- 4b. 创建介质基板(Dielectric/PCB) ----------
oEditor.CreateBox(
[
"NAME:BoxParameters",
"XPosition:=", "{}mm".format(xi), # 与ground对齐
"YPosition:=", "{}mm".format(yi),
"ZPosition:=", "{}mm".format(zi + ground_height), # 紧贴接地板顶面
"XSize:=", "{}mm".format(uedim - 0.0001),
"YSize:=", "{}mm".format(uedim - 0.0001),
"ZSize:=", "{}mm".format(dielectric_height) # 基板厚度
],
[
"NAME:Attributes",
"Name:=", "Dielectric_{}".format(i), # 唯一命名: Dielectric_0, ...
"MaterialValue:=", "\"{}\"".format(dielectric_material), # Rogers RO3203
"SolveInside:=", True, # 介质内部需要求解场
"Color:=", "(128 128 128)" # 灰色显示
]
)
# ---------- 4c. 创建顶部金属贴片(Top Patch) ----------
oEditor.CreateBox(
[
"NAME:BoxParameters",
"XPosition:=", "{}mm".format(xi_center - patch_size / 2), # 居中放置
"YPosition:=", "{}mm".format(yi_center - patch_size / 2),
"ZPosition:=", "{}mm".format(zi + ground_height + dielectric_height), # 基板顶面
"XSize:=", "{}mm".format(patch_size), # patch边长(每个不同!)
"YSize:=", "{}mm".format(patch_size),
"ZSize:=", "{}mm".format(top_patch_height) # 贴片厚度
],
[
"NAME:Attributes",
"Name:=", "TopPatch_{}".format(i), # 唯一命名: TopPatch_0, ...
"MaterialValue:=", "\"pec\"", # 理想电导体
"SolveInside:=", False # PEC内部不求解
]
)
# 每个patch的尺寸(patch_size)不同,但都在各自单元胞内居中
# z坐标 = zi + ground_height + dielectric_height,随曲面高度zi变化 → 共形
# ===================== 程序入口 =====================
if __name__ == "__main__":
main()
复制成功
代码逐步讲解:
在HFSS中运行脚本的指南:确保已安装HFSS(脚本直接与HFSS交互,因此必须安装并配置该软件);验证项目和设计名称(确保 Project1 和 HFSSDesign1 与 在HFSS中的项目和设计名称匹配);检查文件路径(确认文件路径正确且可访问)。
运行脚本:打开HFSS,Tools > Run Script...,在HFSS中加载并运行脚本以自动化生成超表面。该脚本通过利用预计算的贴片数据自动创建超表面设计。它从JSON文件读取数据,在HFSS中设置各层,并根据预计算信息确保每个单元的位置和尺寸正确。 (Record Script 可以记录界面图形化操作到 Python 文件)

代码块
PlainText
自动换行
复制代码
1234567891011121314151617181920212223242526272829
import numpy as np # 导入NumPy库,用于数值计算
import pandas as pd # 导入Pandas库,用于数据处理和分析
import matplotlib.pyplot as plt # 导入Matplotlib的pyplot模块,用于绘图
def plot_phase_data(phase_data_file="phase_data_file", output_image_file="phase_plot.png"):
# 功能:绘制相位分布图
# 输入:包含相位数据的CSV文件名(默认值 "phase_data_file")
# 输出:生成的图片文件名(默认值 "phase_plot.png")
# 从CSV文件加载2D相位数据
# header=None 表示文件不包含标题行
# to_numpy() 将DataFrame转换为NumPy数组
phase_deg_2d = pd.read_csv(phase_data_file, header=None).to_numpy()
# 绘制相位数据
plt.figure(figsize=(8, 8)) # 创建一个8x8英寸的图形窗口
# 使用imshow绘制2D数组作为图像
# cmap='jet' 设置颜色映射为jet(蓝-青-黄-红)
# origin='lower' 设置坐标原点在左下角
plt.imshow(phase_deg_2d, cmap='jet', origin='lower')
plt.colorbar(label="Phase (degrees)") # 添加颜色条,标签为 "Phase (degrees)"
plt.title("Phase Distribution") # 设置图表标题为 "Phase Distribution"
plt.xlabel("X (mm)") # 设置X轴标签为 "X (mm)"
plt.ylabel("Y (mm)") # 设置Y轴标签为 "Y (mm)"
plt.savefig(output_image_file) # 将图形保存为文件
plt.close() # 关闭图形窗口,释放内存
if __name__ == "__main__": # 如果脚本作为主程序运行
plot_phase_data("phase_data.csv", "phase_plot.png") # 调用绘图函数,指定输入输出文件
复制成功
该Python脚本负责将之前计算步骤中生成的二维相位数据可视化。它从CSV文件读取相位数据,并使用matplotlib将其绘制为图像,这类似于Matlab中的imagesc函数。
所需软件包:numpy(高效数值运算)、pandas(将CSV文件读取为结构化格式并转换为numpy数组)、matplotlib(创建和保存图表)。
代码逐步讲解:
该脚本设计用于使用pandas从CSV文件读取二维相位数组,使用matplotlib将二维相位数据可视化为图像,并将结果图表保存为PNG图像。
既然我们已经解释了代码的所有部分,让我们开始HFSS仿真。
HFSS仿真的第一部分是设计照射超表面的喇叭馈电天线。我们点击“新建”创建一个新项目,然后点击"HFSS"在项目中创建HFSS环境。
接着,我们使用 View 菜单中的 Component Libraries 选项创建预设计的圆形喇叭天线,并设置喇叭的参数。或者使用 ACT Extensions 同样可以创建。





接下来,我们在天线周围创建开放边界,将频率设置为30 GHz,然后添加分析设置。
依据具体版本,HFSS 求解类型取消勾选 Auto-Open Region
添加分析求解



现在我们验证HFSS设置并运行仿真。仿真结束后,我们得到三维和二维辐射方向图。可以看到,方向图一侧的3dB波束宽度约为45°。





我们需要仿真超表面的超原子单元,并分析单元的反射系数与其尺寸的关系。我们首先绘制超原子的三维模型,该模型可以在贴片尺寸和单元本身尺寸方面动态重新配置。
在本教程中,我们使用5 mm的单元尺寸。


现在我们需要在模型周围创建空气盒。


接下来设置Floquet端口,这个设置对于能够使用周期性边界条件至关重要。请确保HFSS求解类型必须设置为 Modal 才能运行仿真。

我们使用耦合的主边界和辅边界条件来模拟周期边界条件。HFSS中的Floquet端口应被这种边界条件包围。



选择相对的面

或者 同时设置一对面,同样设置另外一对面。或者选择整个对象使用 Auto Identify lattice pair


单元底面的边界条件为PEC,因为我们仿真的是反射阵列单元。

贴片尺寸

我们添加分析设置,然后为顶部贴片的尺寸添加参数扫描——我们希望获得单元的反射相位与天线顶部贴片尺寸的关系。



解决相交区域材料冲突的问题,允许材料覆盖

接下来我们验证HFSS设置并运行仿真。我们需要导出结果。

选择 角度



仿真结束后,我们将反射相位与贴片尺寸的关系结果导出到Excel文件中,作为Python自动化代码的输入因子。
文件数据格式调整 Phase 和 Size,重命名为 phase_vs_size.csv
现在让我们专注于HFSS的主设计。我们创建一个项目,然后在项目中创建HFSS环境。
接下来,我们使用Visual Studio Code打开 json_data_creator.py。在该文件中,我们为超表面设置所需的参数,然后运行代码。
产生的相位数据 phase_data.csv

为了查看单元相位的可视化结果,我们可以运行 plotter.py 文件。

然后,我们需要打开 generate_hfss_script.py,在代码中我们必须确保使用与我们创建的项目相同的名称以及相同的HFSS环境名称。代码中需要设置由 json_data_creator.py 脚本创建的 patch_data.json 文件的路径。
进入HFSS,选择 Automation 自动化,再选择 Run Script 运行脚本,最后选择 generate_hfss_script.py 脚本。(注意,这里使用的是 HFSS 自带的 Python 2.7 IronPython)

(这里没有使用)HFSS 提供额外安装的新版的 pyaedt 支持最新的 Python 3,新版在不断开发中。

现在超表面开始在HFSS环境中创建,我们等待脚本完成超表面的创建。

接下来,我们使用HFSS中的预定义结构设置喇叭馈源。我们动态地指示馈源的位置。虽然可以运行优化,但出于本教程的目的,我们只需将其放置在超表面上方60 mm处。
创建一个相对坐标系


通过组件库,或者导入已经存在的喇叭天线组件


选择相对坐标系

创建开放区域


然后我们设置分析,并确保选择至少六到七次网格细化迭代,这是因为使用粗糙网格会导致不真实的结果。



我们设置开放边界以及三维和二维远场辐射方向图的结果。接下来我们验证HFSS设置并运行仿真。求解时间漫长。
在本教程的最后一部分,我们想展示一些不同超表面设计的样例:



我们可以看到超表面上的旋转相位以及OAM辐射方向图的中空波束。
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删