使用python-cst实现角锥喇叭的建模仿真


内容

完全使用python-cst联合仿真脚本模式,从0开始实现角锥喇叭的建模、端口添加、远场监视器添加,以及模型仿真。喇叭的形状如图所示:
在这里插入图片描述

一,创建cst项目

# 创建CST文件,文件路径名为cst_path
def creat_cst(cst_path):
    allpids = cst.interface.running_design_environments()  # 以列表形式返回运行的cst环境名(PIDs)
    DE_is_open = False   # 判断是否有打开的DE
    for pid in allpids:
        my_DE = cst.interface.DesignEnvironment.connect(pid)  # 连接到指定PID的DE
        DE_is_open = True
        break
    if not DE_is_open:  # DE不存在,则新建一个DE,否则使用上面已打开的最后一个DE
        my_DE = cst.interface.DesignEnvironment()
    my_project = my_DE.new_mws()
    my_project.save(cst_path)
    return my_DE, my_project

二,定义VBA执行(添加历史书)

# 执行VBA代码并添加历史书
def add_vba_history(my_modeler, sCommand, history_name):
    line_break = '\n'  # 用于VBA代码的拼接
    sCommand = line_break.join(sCommand)
    my_modeler.add_to_history(history_name, sCommand)
    return my_modeler

三,设置变量和仿真频率

# 设置参数
class set_parameter(object):
    def __init__(self, my_modeler):
        super().__init__()

        self.parameter_list = {
            'taper_angle': 7,  # 嘴部抬头角度
            'horn_length': 166.71,  # 喇叭嘴部长
            'wall_thickness': 1.8,  # 喇叭厚度
            'waveguide_height': 24,  # 喇叭尾部高
            'waveguide_width': 12,   # 喇叭尾部宽
            'waveguide_length': 51.4,  # # 喇叭尾部长
            'theta': 0,   # unit cell下设置的入射电磁波角度
            'phi': 0
        }

        self.frq = [12, 14]

        self.my_modeler = my_modeler

    def add_parameter(self):
        for par_key, par_value in self.parameter_list.items():
            self.my_modeler.add_to_history('StoreParameter', f'MakeSureParameterExists("{par_key}", {par_value})')
        return self.my_modeler

    # 添加频率
    def set_frq(self):
        sCommand = 'Solver.FrequencyRange %f, %f' % (self.frq[0], self.frq[1])
        self.my_modeler.add_to_history('define FrequencyRange', sCommand)
        return self.my_modeler

四,设置Units

# 单位初始化
def init_unit(my_modeler):
    sCommand = ['With Units',
                '.Geometry "mm"',
                '.Frequency "GHz"',
                '.Voltage "V"',
                '.Resistance "Ohm"',
                '.Inductance "H"',
                '.TemperatureUnit  "Kelvin"',
                '.Time "s"',
                '.Current "A"',
                '.Conductance "Siemens"',
                '.Capacitance "F"',
                'End With']
    history_name = 'define Units'
    my_modeler = add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

五,设置Background

# 设置背景材料
def set_background(my_modeler):
    sCommand = ['With Background',
                '.ResetBackground',
                '.Type "Normal"',
                '.XminSpace "0.0"',
                '.XmaxSpace "0.0"',
                '.YminSpace "0.0"',
                '.YmaxSpace "0.0"',
                '.ZminSpace "0.0"',
                '.ZmaxSpace "0.0"',
                '.ApplyInAllDirections "False"',
                'End With']
    history_name = 'define Background'
    my_modeler = add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

六,设置Boundaries

这里设置的open(add space)边界条件,如果是设置成unit cell,则将注释部分的注释取消,其中周期边界角度设置为了theta, phi。

def set_boundary(my_modeler):
    sCommand = ['With Boundary',
                '.Xmin "expanded open"',
                '.Xmax "expanded open"',
                '.Ymin "expanded open"',
                '.Ymax "expanded open"',
                '.Zmin "expanded open"',
                '.Zmax "expanded open"',
                '.Xsymmetry "none"',
                '.Ysymmetry "none"',
                '.Zsymmetry "none"',
                '.ApplyInAllDirections "False"',
                '.OpenAddSpaceFactor "0.5"',
                # '.XPeriodicShift "0.0"',
                # '.YPeriodicShift "0.0"',
                # '.ZPeriodicShift "0.0"',
                # '.PeriodicUseConstantAngles "True"',
                # '.SetPeriodicBoundaryAngles "theta", "phi"',
                # '.SetPeriodicBoundaryAnglesDirection "outward"',
                # '.UnitCellFitToBoundingBox "True"',
                # '.UnitCellDs1 "0.0"',
                # '.UnitCellDs2 "0.0"',
                # '.UnitCellAngle "90.0"',
                'End With']
    history_name = 'define boundaries'
    my_modeler = add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

七,喇叭建模

为了方便查错管理,这里是将建模所需要的操作都分别定义好,之后只进行调用即可。

1, 创建新component

在使用新的component时,CST不会自动创建目标组,因此需要提前创建。

def add_new_component(my_modeler, component_name):
    sCommand = [f'Component.New "{component_name}"']
    history_name = f'new component: {component_name}'
    add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

2,brick创建

def brick_model(my_modeler, name, component, material, xrange, yrange, zrange):
    sCommand = ['With Brick',
                '.Reset',
                '.Name "%s"' % name,
                '.Component "%s"' % component,
                '.Material "%s"' % material,
                f'.Xrange {xrange[0]}, {xrange[1]}',
                f'.Yrange {yrange[0]}, {yrange[1]}',
                f'.Zrange {zrange[0]}, {zrange[1]}',
                '.Create',
                'End With']
    history_name = 'define brick:%s:%s' % (component, name)
    add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

3,pick face操作

其中的value表示选中面所代表的序号,目前我还没搞懂这个值与模型的面的联系,只能在cst界面交互后实验下才知道。

def pick_face(my_modeler, component, obj_name, value):
    sCommand = [f'Pick.PickFaceFromId "{component}:{obj_name}", "{value}"']
    history_name = 'pick face'
    add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

4,Extrude face操作

在进行Extrude face操作之前,需要先进行pick face选中一个操作面。

def extrude_face(my_modeler, component, name, material):
    sCommand = ['With Extrude',
                f'.Name "{name}"',
                f'.Component "{component}"',
                f'.Material "{material}"',
                '.Mode "Picks"',
                '.Height "horn_length"',
                '.Twist "0.0"',
                '.Taper "taper_angle"',
                '.UsePicksForHeight "False"',
                '.DeleteBaseFaceSolid "False"',
                '.ClearPickedFace "True"',
                '.Create',
                'End With']
    history_name = f'define extrude: {component}:{name}'
    add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

5,Add操作

class boolean(object):
    def __init__(self, my_modeler, obj_name1, obj_component1, obj_name2, obj_component2):
        super().__init__()
        self.my_modeler = my_modeler
        self.name1 = obj_component1 + ':' + obj_name1
        self.name2 = obj_component2 + ':' + obj_name2

    def add(self):  # +
        sCommand = [f'Solid.Add "{self.name1}", "{self.name2}"']
        history_name = f'boolean add shapes: {self.name1}, {self.name2}'
        add_vba_history(self.my_modeler, sCommand, history_name)
        return self.my_modeler

6,挖空操作

在使用此操作之前,需要先使用pick face操作分别选中两个面。

def shell(my_modeler, component, name):
    sCommand = ['With Solid',
                f'.AdvancedShell "{component}:{name}", "Outside", "wall_thickness"',
                'End With']
    history_name = f'shell object: {component}, {name}'
    add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

7,transform操作

obj_component, obj_name:操作对象的组和名
num:操作次数
save_component:目标操作完成后,得到的新的对象的保存component,默认与目标对象一致

# 模型翻转操作
class transform(object):  # 输入为操作对象分组,对象名,操作次数,保存分组
    def __init__(self, my_modeler, obj_component, obj_name=None, num=1, save_component="", is_copy=True):
        super().__init__()
        self.my_modeler = my_modeler
        if obj_name is None:  # 对整个分组进行操作
            self.name = obj_component
        else:
            self.name = obj_component + ':' + obj_name
        self.num = num  # 操作次数
        self.save_component = save_component
        self.is_copy = is_copy

    # 镜像
    def mirrow(self, plane_normal):  # 输入为镜像的方向向量
        sCommand = ['With Transform',
                    '.Reset',
                    f'.Name "{self.name}"',
                    '.Origin "Free"',
                    '.Center "0", "0", "0"',
                    f'.PlaneNormal "{plane_normal[0]}", "{plane_normal[1]}", "{plane_normal[2]}"',
                    f'.MultipleObjects "{self.is_copy}"',
                    '.GroupObjects "False"',
                    f'.Repetitions "{self.num}"',
                    '.MultipleSelection "False"',
                    f'.Destination "{self.save_component}"',
                    '.Material ""',
                    '.Transform "Shape", "Mirror"',
                    'End With']
        history_name = f'transform: mirrow {self.name}'
        add_vba_history(self.my_modeler, sCommand, history_name)
        return self.my_modeler

    # 平移,输入为:移动的方向向量
    def translate(self, tran_vector):
        sCommand = ['With Transform',
                    '.Reset',
                    f'.Name "{self.name}"',
                    f'.Vector "{tran_vector[0]}", "{tran_vector[1]}", "{tran_vector[2]}"',
                    '.UsePickedPoints "False"',
                    '.InvertPickedPoints "False"',
                    f'.MultipleObjects "{self.is_copy}"',
                    '.GroupObjects "False"',
                    f'.Repetitions "{self.num}"',
                    '.MultipleSelection "False"',
                    '.Transform "Shape", "Translate"',
                    'End With']
        history_name = f'transform: translate {self.name}'
        add_vba_history(self.my_modeler, sCommand, history_name)
        return self.my_modeler

8,喇叭建模

def horn_model(my_modeler):
    material = 'PEC'
    component = 'component1'
    add_new_component(my_modeler, component)
    # 尾部波导
    waveguide_name = 'waveguide'
    xrange = ["-waveguide_width/2", "waveguide_width/2"]
    yrange = ["-waveguide_height/2", "waveguide_height/2"]
    zrange = ["0", "waveguide_length"]
    brick_model(my_modeler, waveguide_name, component, material,
                xrange, yrange, zrange)

    # 喇叭嘴部
    pick_face(my_modeler, component, waveguide_name, 1)
    horn_name = 'horn'
    extrude_face(my_modeler, component, horn_name, material)
    boolean(my_modeler, horn_name, component, waveguide_name, component).add()

    # 挖空
    pick_face(my_modeler, component, horn_name, 2)
    pick_face(my_modeler, component, horn_name, 11)
    shell(my_modeler, component, horn_name)

    transform(my_modeler, component, horn_name, is_copy=False).mirrow([0, 0, 1])
    transform(my_modeler, component, horn_name, is_copy=False).translate([0, 0, 'horn_length+waveguide_length'])

    xrange = ["-waveguide_width/2", "waveguide_width/2"]
    yrange = ["-waveguide_height/2", "waveguide_height/2"]
    zrange = ['horn_length+waveguide_length', 'horn_length+waveguide_length']
    pick_face(my_modeler, component, horn_name, '11')
    set_port(my_modeler).waveguide_port(1, xrange, yrange, zrange, 'positive')  # 设置端口
    return my_modeler

八,修改频域求解

由于项目初始时求解器为时域求解器,因此需要将其修改为频域求解。

# 更改为频域求解器
def get_frq_solver(my_modeler):
    sCommand = ['ChangeSolverType "HF Frequency Domain"']
    history_name = 'change solver type'
    add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

九,设置波导端口

这里是用于将喇叭的尾部设置为波导端口,使用时需要先进行pick face操作选中一个面。其中:
port_num: 波导端口编号
port_dir:波导方向,只能是"positive"和"negative"
modes_num:端口模式数,默认为1

class set_port(object):
    def __init__(self, my_modeler):
        super().__init__()
        self.modeler = my_modeler

    def waveguide_port(self, port_num, xrange, yrange, zrange, port_dir, modes_num=1):  
        sCommand = ['With Port',
                    '.Reset',
                    f'.PortNumber "{port_num}"',
                    '.Label ""',
                    '.Folder ""',
                    f'.NumberOfModes "{modes_num}"',
                    '.AdjustPolarization "False"',
                    '.PolarizationAngle "0.0"',
                    '.ReferencePlaneDistance "0"',
                    '.TextSize "50"',
                    '.TextMaxLimit "1"',
                    '.Coordinates "Picks"',
                    f'.Orientation "{port_dir}"',  
                    '.PortOnBound "False"',
                    '.ClipPickedPortToBound "False"',
                    f'.Xrange "{xrange[0]}", "{xrange[1]}"',
                    f'.Yrange "{yrange[0]}", "{yrange[1]}"',
                    f'.Zrange "{zrange[0]}", "{zrange[1]}"',
                    '.XrangeAdd "0.0", "0.0"',
                    '.YrangeAdd "0.0", "0.0"',
                    '.ZrangeAdd "0.0", "0.0"',
                    '.SingleEnded "False"',
                    '.WaveguideMonitor "False"',
                    '.Create',
                    'End With']
        history_name = f'define port:{port_num}'
        add_vba_history(self.modeler, sCommand, history_name)
        return self.modeler

十,添加远场监视器

这里是需要设置一个13GHz的远场监视器。

def set_monitor(my_modeler, frq, xrange, yrange, zrange):
    sCommand = ['With Monitor',
                '.Reset',
                f'.Name "farfield (f={frq})"',
                '.Domain "Frequency"',
                '.FieldType "Farfield"',
                f'.MonitorValue "{frq}"',
                '.ExportFarfieldSource "False"',
                '.UseSubvolume "False"',
                '.Coordinates "Structure"',
                f'.SetSubvolume "{xrange[0]}", "{xrange[1]}", "{yrange[0]}", "{yrange[1]}", "{zrange[0]}", "{zrange[1]}"',
                '.SetSubvolumeOffset "10", "10", "10", "10", "10", "10"',
                '.SetSubvolumeInflateWithOffset "False"',
                '.SetSubvolumeOffsetType "FractionOfWavelength"',
                '.EnableNearfieldCalculation "True"',
                '.Create',
                'End With']
    history_name = f'define farfield monitor: farfield (f={frq})'
    add_vba_history(my_modeler, sCommand, history_name)
    return my_modeler

十一,模块调用

if __name__ == '__main__':
    work_path = os.getcwd()
    my_path = os.path.join(work_path, r'cst_file/horn.cst')
    my_DE, my_project = creat_cst(my_path)
    my_modeler = my_project.modeler

    set_parameter(my_modeler).add_parameter()
    set_parameter(my_modeler).set_frq()

    init_unit(my_modeler)
    set_background(my_modeler)
    set_boundary(my_modeler)
    horn_model(my_modeler)
    get_frq_solver(my_modeler)
    xrange = ["-28.282931833949", "28.282931833949"]
    yrange = ["-34.282931833949", "34.282931833949"]
    zrange = ["-2.8421709430404e-14", 'horn_length+waveguide_length']
    set_monitor(my_modeler, 13, xrange, yrange, zrange)
    # Zoom(my_modeler)
    my_modeler.run_solver()
    my_project.save()

代码执行效果

弹出窗口是CST2021及以上版本新加入的脚本(静态)模式/交互模式,即使不关闭弹窗,脚本也会执行下去,只是无法看到界面而已。

角锥喇叭仿真

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值