编写Python自动化脚本,使用Autodesk Fusion辅助Ansys HFSS进行建模
前言
最近正在复现一个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.userInterface
def run(_context: str):
"""This function is called by Fusion when the script is run."""
try:
# Your code goes here.
product = app.activeProduct
design = 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.translation
positions.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 = False
if fileDialog.showSave() == adsk.core.DialogResults.DialogOK:
filename = fileDialog.filename
with 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).

浙公网安备 33010602011771号