def add_pcbs(tg): '''Add primary and secondary side pcbs.''' # coordinates of the PCB on the primary side if tg.layers_primary == 1 or tg.layers_primary == 2: coords_pcb_prim = coords_of_rectangle( 0, tg.height_dielectric + tg.height_copper + tg.height_gap, tg.radius_pcb, tg.height_pcb_core) elif tg.layers_primary == 4: coords_pcb_prim = coords_of_rectangle( 0, tg.height_dielectric + tg.height_copper + tg.height_gap, tg.radius_pcb, tg.height_pcb_core + 2 * tg.height_pcb_prepreg + 2 * tg.height_copper) else: print('Unknown number of layers on primary side') femm.closefemm() return (0, 0) # coordinates of the PCB on the secondary side if tg.layers_secondary == 1 or tg.layers_secondary == 2: coords_pcb_sec = coords_of_rectangle(0, -tg.height_copper - tg.height_gap, tg.radius_pcb, -tg.height_pcb_core) elif tg.layers_secondary == 4: coords_pcb_sec = coords_of_rectangle( 0, -tg.height_copper - tg.height_gap, tg.radius_pcb, -tg.height_pcb_core - 2 * tg.height_pcb_prepreg - 2 * tg.height_copper) else: print('Unknown number of layers on secondary side') femm.closefemm() return (0, 0) femm.mi_drawrectangle(*coords_pcb_prim) femm.mi_drawrectangle(*coords_pcb_sec)
def add_pcbs(tg, label_dict): '''Add primary and secondary side pcbs. Args: tg (TransformerGeometry): contains all geometry information needed to build conductors in the problem. label_dict (dict): stores coordinates ''' # coordinates of the PCB on the primary side if tg.layers_primary == 1 or tg.layers_primary == 2: coords_pcb_prim = coords_rectangle( 0, tg.height_dielectric + tg.height_copper + tg.height_gap, tg.radius_pcb, tg.height_pcb_core) elif tg.layers_primary == 4: coords_pcb_prim = coords_rectangle( 0, tg.height_dielectric + tg.height_copper + tg.height_gap, tg.radius_pcb, tg.height_pcb_core + 2 * tg.height_pcb_prepreg + 2 * tg.height_copper) else: print('Unknown number of layers on primary side') femm.closefemm() return (0, 0) # coordinates of the PCB on the secondary side if tg.layers_secondary == 1 or tg.layers_secondary == 2: coords_pcb_sec = coords_rectangle(0, -tg.height_copper - tg.height_gap, tg.radius_pcb, -tg.height_pcb_core) elif tg.layers_secondary == 4: coords_pcb_sec = coords_rectangle( 0, -tg.height_copper - tg.height_gap, tg.radius_pcb, -tg.height_pcb_core - 2 * tg.height_pcb_prepreg - 2 * tg.height_copper) else: print('Unknown number of layers on secondary side') femm.closefemm() return (0) femm.ei_drawrectangle(*coords_pcb_prim) femm.ei_drawrectangle(*coords_pcb_sec) label_dict['PCB_prim'] = coords_pcb_prim label_dict['PCB_sec'] = coords_pcb_sec
def calc_inductance(tg, currents, inductances=(None, None), **kwargs): ''' Setup of magneto-static problem in femm to calculate inductance and resistance of planar transformer. Args: tg (:obj:'TransformerGeometry'): tg contains all geometry information of the transformer. currents (list of float): currents in the primary and secondary side circuits on the form [I_prim, I_sec]. inductances (list of float): self-inductances of the primary and secondary side circuits on the form [L_prim, L_sec]. Used to calculate mutual inductance. Returns: (inductance, resistance): calculated self or mutual inductance and equivalent series resistance of either primary or secondary circuit. ''' etiquettes_dict = {} # Dictionary to store coordinates of nodes # initialitiation of the magneto-static problem boundary_radius = 2 * tg.radius_dielectric initial_setup(boundary_radius, currents, **kwargs) # draw geometry and add block labels add_conductors(tg, etiquettes_dict) add_pcbs(tg) add_isolation(tg) add_block_labels(tg, etiquettes_dict) # mi zoomnatural() # From manual: zooms to a “natural” view with sensible extents. femm.mi_zoomnatural() # Saving geometry file femm.mi_saveas('inductance_transformer.fem') # Meshing and analysis # From manual: Note that it is not necessary to run mesh before performing # an analysis, as mi_analyze() will make sure the mesh is up to date before # running an analysis. # mi analyze(flag) # From manual: runs fkern to solve the problem. The flag parameter controls # whether the fkern window is visible or minimized. For a visible window, # either specify no value for flag or specify 0. For a minimized window, # flag should be set to 1. femm.mi_analyze(1) # Post-processing femm.mi_loadsolution() # mo_seteditmode(mode) # From manual: Sets themode of the postprocessor to point, contour, or area # mode. Valid entries for mode are "point", "contour", and "area". femm.mo_seteditmode('area') # mo_blockintegral(type) # From manual: Calculate a block integral for the selected blocks # Type Definition # 0 A · J # 1 A # 2 Magnetic field energy # 3 Hysteresis and/or lamination losses # 4 Resistive losses # 5 Block cross-section area # 6 Total losses # 7 Total current # 8 Integral of Bx (or Br) over block # 9 Integral of By (or rBz) over block # 10 Block volume # ... # mo_getcircuitproperties("circuit") # From manual: Used primarily to obtain impedance information associated # with circuit properties. Properties are returned for the circuit property # named "circuit". Three values are returned by the function. In order, # these results are: # – current Current carried by the circuit # – volts Voltage drop across the circuit # – flux_re Circuit’s flux linkage # mo_groupselectblock(n) # From manual: Selects all the blocks that are labeled by block labels # that are members of group n. If no number is specified (i.e. # mo_groupselectblock() ), all blocks are selected. # Calculate the inductance of the circuit with non-zero current. If both # currents are given, we calculate the mutual inductance. L1, L2 = inductances if (currents[0] > 0) and (currents[1] == 0): circ = femm.mo_getcircuitproperties('phase_prim') resistance = circ[1].real inductance = abs(circ[2] / circ[0]) elif (currents[0] == 0) and (currents[1] > 0): circ = femm.mo_getcircuitproperties('phase_sec') resistance = circ[1].real inductance = abs(circ[2] / circ[0]) else: femm.mo_groupselectblock() # axisymmetric problem, integral is multiplied by 2 Wm = femm.mo_blockintegral(2) * 2 inductance = ((Wm - 0.5 * (L1 * currents[1]**2 + L2 * currents[0]**2)) / (currents[0] * currents[1])) resistance = 0 femm.mo_clearblock() if kwargs.get('close') is True: femm.closefemm() return (inductance, resistance)
femm.ei_zoomnatural() # Save the geometry to disk so we can analyze it femm.ei_saveas('strips.fee') # Create a placeholder matrix which we will fill with capacitance values c = [] for k in range(0, 4): femm.ei_modifyconductorprop('v0', 1, 1 if (k == 0) else 0) femm.ei_modifyconductorprop('v1', 1, 1 if (k == 1) else 0) femm.ei_modifyconductorprop('v2', 1, 1 if (k == 2) else 0) femm.ei_modifyconductorprop('v3', 1, 1 if (k == 3) else 0) femm.ei_analyze() femm.ei_loadsolution() c.append([ femm.eo_getconductorproperties('v0')[1], femm.eo_getconductorproperties('v1')[1], femm.eo_getconductorproperties('v2')[1], femm.eo_getconductorproperties('v3')[1] ]) femm.closefemm() print('The capacitance matrix (pF/m):') for j in range(0, 4): for k in range(0, 4): c[j][k] *= 10**12 print(c[j])
def calc_field_distribution(tg, voltage_high=1, view=None, **kwargs): ''' Setup of electro-static problem in femm to calculate capacitance between primary and secondary side of planar transformer. Additionally, electric field can be investigated Args: tg (:obj:'TransformerGeometry'): tg contains all geometry information needed to solve the problem. voltage_high (float): Voltage potential of the primary side. view (:obj:'View'): Save images of edges and guards. Returns: capacitance (float): calculated capacitance between primary and secondary side of planar transformer. ''' etiquettes_dict = {} # Dictionary to store coordinates of nodes # initialitiation of the electro-static problem boundary_radius = 2 * tg.radius_dielectric initial_setup(boundary_radius, voltage_high, **kwargs) # draw conductors on primary and secondary sides add_conductors(tg, etiquettes_dict) add_pcbs(tg, etiquettes_dict) add_isolation(tg) add_block_labels(tg, etiquettes_dict) round_conductor_edges(tg, etiquettes_dict, kwargs.get('segment_angle')) # if tg.edge_type == 'Round': # round_conductor_edges(tg, etiquettes_dict) # elif tg.edge_type == 'Trapezoidal': # trapezoidal_conductor_edges(tg, etiquettes_dict) if tg.tracks: modify_tracks(tg, etiquettes_dict, kwargs.get('segment_angle')) if tg.guard: add_guard(tg, tg.guard, etiquettes_dict) # mi zoomnatural() # From manual: zooms to a “natural” view with sensible extents. femm.ei_zoomnatural() # Save geometry file femm.ei_saveas('field_calculations.fee') # Meshing and analysis # From manual: Note that it is not necessary to run mesh before performing # an analysis, as mi_analyze() will make sure the mesh is up to date before # running an analysis. # mi analyze(flag) # From manual: runs fkern to solve the problem. The flag parameter controls # whether the fkern window is visible or minimized. For a visible window, # either specify no value for flag or specify 0. For a minimized window, # flag should be set to 1. femm.ei_analyze(1) # Post-processor femm.ei_loadsolution() # eo_showdensityplot(legend,gscale,type,upper D,lower D) # From manual: Shows the flux density plot with options: # legend Set to 0 to hide the plot legend or 1 to show the plot legend. # gscale Set to 0 for a colour density plot or 1 for a grey scale density # plot. # type Sets the type of density plot. A value of 0 plots voltage, 1 plots # the magnitude of D, and 2 plots the magnitude of E # upper D Sets the upper display limit for the density plot. # lower D Sets the lower display limit for the density plot. if 'plot_field_max' in kwargs: femm.eo_showdensityplot(1, 0, 2, kwargs['plot_field_max'] * 20 / 19, 0) # Save field lines along outer point of the PCB conductors. If the # conductors have trapezoidal shape, it is difficult to estimate where the # peak field will be. Hence, the contour lines are not saved. # if not edge_trapezoid: # save_field_contour(ep_cuivre, etiquettes_dict, guard=guard) if view: set_view(view, tg.guard, etiquettes_dict) # eo_getconductorproperties("conductor") # From manual: Properties are returned for the conductor property named # ”conductor”. Two values are returned: The voltage of the specified # conductor, and the charge carried on the specified conductor. # Calculate the capacitance circuit_properties = femm.eo_getconductorproperties('zero') charge = -circuit_properties[1] # get charge on secondary side conductors capacitance = charge / voltage_high if kwargs.get('close') is True: femm.closefemm() return capacitance
femm.mi_clearselected() femm.mi_zoomnatural() # to check geometry while debuging femm.mi_saveas('ring.fem') # meshing # automaticaly done by the analysis function # analysis femm.mi_analyze() # result data export femm.mi_loadsolution() # plot the flux density along z axis zee = [] bee = [] for n in range(-0, 30): b = femm.mo_getb(0, n) zee.append(n) bee.append(b[1]) plt.plot(zee, bee) plt.ylabel('Flux Density, Tesla') plt.xlabel('Distance along the z-axis, mm') plt.title('Plot of flux density along the axis') plt.grid() plt.show() femm.closefemm() # close the instance of femm
def closeSimulation(self): femm.closefemm()
def closeFemm(filename='test.fem'): femm.mi_saveas(filename) femm.closefemm()
def fermeture_simulation(self): """Fermeture de FEMM""" femm.closefemm()