前言
最近正在复现一个Vivaldi天线,需要绘制由曲线阵列的圆形构成的开槽。由于HFSS如同大便一般的建模逻辑实在不方便完成这个操作,我决定研究一下使用Autodesk Fusion进行阵列,再将坐标导入到Ansys HFSS中绘制圆柱。
得益于这两款软件提供的自动化API,我们能够分别编写两个Python脚本,实现我们需要的功能。
Fusion 建模
导入参考图后,在草图中绘制阵列对象和曲线,之后进行路径阵列,如下图所示。注意路径起点
在“实用程序-附加模块”中,点击加号,选择“创建脚本或附加模块”,在弹出的窗口中选择“脚本”,修改名称,选择编程语言为“Python”,最后点击“创建”。
勾选左侧“由我创建”,找到刚才创建的脚本,右键,选择“在代码编辑器中编辑”。
编写脚本。脚本内容见附录。
运行脚本,保存阵列对象的坐标到CSV文件。
HFSS操作
在“Automation”菜单栏中,点击“Record Script”,填好文件名和路径。随便新建一点什么,再点击“Stop Recording”。
打开保存的Py,编写脚本。注意IronPython的版本貌似比较久远,不支持一些新语法。脚本内容见附录,注意修改文件路径。
最后点击“Run Script”,选择刚才创建的脚本。可以看到,我们成功完成了建模。成品如下图。
附录
注意:以下代码由AI辅助编写。
Fusion脚本如下。
"""This file acts as the main module for this script."""import traceback
import adsk.core
import adsk.fusion
import csv# import adsk.cam# Initialize the global variables for the Application and UserInterface objects.
app = adsk.core.Application.get()
ui = app.userInterfacedef run(_context: str):"""This function is called by Fusion when the script is run."""try:# Your code goes here.product = app.activeProductdesign = adsk.fusion.Design.cast(product)if not design:ui.messageBox("需要激活的Fusion设计")return# 获取根组件rootComp = design.rootComponent# 准备导出数据positions = []# 遍历所有特征for feature in rootComp.features:# 检查是否是路径阵列特征if feature.classType() == adsk.fusion.PathPatternFeature.classType():pathPattern = adsk.fusion.PathPatternFeature.cast(feature)(returnValue, startPoint, endPoint) = pathPattern.path.item(0).curve.evaluator.getEndPoints()base_position = (startPoint.x * 10,startPoint.y * 10,startPoint.z * 10,)# 获取阵列中的所有实例for occurrence in pathPattern.patternElements:# 获取变换矩阵transform = occurrence.transform# 提取位置(矩阵的平移部分)translation = transform.translationpositions.append({"x": translation.x * 10 + base_position[0],"y": translation.y * 10 + base_position[1],"z": translation.z * 10 + base_position[2],})# 导出到CSV文件if positions:# 让用户选择保存位置fileDialog = ui.createFileDialog()fileDialog.title = "保存位置数据"fileDialog.filter = "CSV文件 (*.csv)"fileDialog.isMultiSelectEnabled = Falseif fileDialog.showSave() == adsk.core.DialogResults.DialogOK:filename = fileDialog.filenamewith open(filename, "w", newline="") as csvfile:writer = csv.DictWriter(csvfile, fieldnames=["x", "y", "z"])writer.writeheader()writer.writerows(positions)ui.messageBox(f"成功导出 {len(positions)} 个位置到:\n{filename}")except Exception: # pylint:disable=bare-except# Write the error message to the TEXT COMMANDS window.app.log(f"Failed:\n{traceback.format_exc()}")
HFSS脚本如下。
# ----------------------------------------------
# Script Recorded by Ansys Electronics Desktop Version 2022.1.0# ----------------------------------------------
import ScriptEnv
import csv# Edit according to your project and design names
ScriptEnv.Initialize("Ansoft.ElectronicsDesktop")
oDesktop.RestoreWindow()
oProject = oDesktop.SetActiveProject("vivaldi")
oDesign = oProject.SetActiveDesign("AVA2")
oEditor = oDesign.SetActiveEditor("3D Modeler")# Read coordinates from CSV file
coordinates = []
# Make sure to change the path to your actual CSV file path
with open("D:\\docs\\fusion\\1.csv", "r") as file:csv_reader = csv.DictReader(file)for row in csv_reader:x = float(row["x"])y = float(row["y"])z = float(row["z"])print("read coordinates: x=%f, y=%f, z=%f" % (x, y, z))coordinates.append((x, y, z))# create cylinders at the specified coordinates
for i, (x, y, z) in enumerate(coordinates):oEditor.CreateCylinder(["NAME:CylinderParameters","XCenter:=","%f mm" % x,"YCenter:=","%f mm" % y,"ZCenter:=","%f mm" % z,"Radius:=","6mm","Height:=","-20mm","WhichAxis:=","Z","NumSides:=","0",],["NAME:Attributes","Name:=","Cylinder_From_CSV%d" % (i + 1),"Flags:=","NonModel#","Color:=","(143 175 143)","Transparency:=",0,"PartCoordinateSystem:=","Global","UDMId:=","","MaterialValue:=",'"vacuum"',"SurfaceMaterialValue:=",'""',"SolveInside:=",True,"ShellElement:=",False,"ShellElementThickness:=","0mm","IsMaterialEditable:=",True,"UseMaterialAppearance:=",False,"IsLightweight:=",False,],)
# Unite all cylinders into one object, then mirror the united object
# and unite the mirrored object with the original united object
UnitedObjects = ",".join(["Cylinder_From_CSV%d" % (i + 1) for i in range(len(coordinates))],
)
oEditor.Unite(["NAME:Selections", "Selections:=", UnitedObjects],["NAME:UniteParameters", "KeepOriginals:=", False],
)oEditor.DuplicateMirror(["NAME:Selections","Selections:=","Cylinder_From_CSV1","NewPartsModelFlag:=","Model",],["NAME:DuplicateToMirrorParameters","DuplicateMirrorBaseX:=","0mm","DuplicateMirrorBaseY:=","0mm","DuplicateMirrorBaseZ:=","0mm","DuplicateMirrorNormalX:=","-1mm","DuplicateMirrorNormalY:=","0mm","DuplicateMirrorNormalZ:=","0mm",],["NAME:Options", "DuplicateAssignments:=", True],["CreateGroupsForNewObjects:=", False],
)
oEditor.Unite(["NAME:Selections", "Selections:=", "Cylinder_From_CSV1,Cylinder_From_CSV1_1"],["NAME:UniteParameters", "KeepOriginals:=", False],
)
参考文献
[1] Prof. Halim Boutayeb, Metasurface Design: Theory, Applications & HFSS Simulations with Python | RF & Microwave Engineering, Youtube, https://www.youtube.com/watch?v=To8rcAq12mc, Nov.2024(accessed Oct. 2025).
[2] A. Hossain and A. -V. Pham, "A Novel Gain-Enhanced Miniaturized and Lightweight Vivaldi Antenna," in IEEE Transactions on Antennas and Propagation, vol. 71, no. 12, pp. 9431-9439, Dec. 2023.
[3] Ronghua.LI, [图文笔记]Fusion 创建Python脚本-入门篇01, Autodesk Community, https://forums.autodesk.com/t5/fusion-chan-pin-ji-shu-ying-yong-zhong-wen-lun-tan/tu-wen-bi-ji-fusion-chuang-jianpython-jiao-ben-ru-men-pian01/td-p/10677228, Oct. 2021(accessed Oct. 2025).