def __init__(self, bHide=False, meshsize=config.MESHSIZE, _i0=config.CURRENT, _id=None): """Initialize a FEMM solver Open FEMM and define the key elements of the magnetic problem. The problem is considered STATIC. All measurements are in MILLIMETERS here ! Keyword Arguments: bHide {bool} -- Either to show or hide the window. Hiding it provides a nice speed improvement (default: {False}) meshsize {number} -- Size of the mesh used for the finite elements. The smaller the more precise, but it comes with a computational cost (default: {1}) _i0 {number} -- Current used in computation. Any value should do, we use 100 to avoid working with very small floats (default: {100}) _id {number} -- Some id used to save the problem, if one requires to track and come back to the FEMM model (default: {None}) """ if _id is not None: self._seed = str(_id) else: self._seed = str(numpy.random.randint(10000)) self.meshsize = meshsize self.Lb = None self.Rbi = None self.Rbo = None self.phi = None self.rho = None self.n = None self.resistance = None self.Lp = None self.Rp = None self.m_vol_fer = None self.mu = None self.mass = None self.espace = None self.wire_type = None self._i0 = _i0 self.bHide = bHide femm.openfemm(bHide) femm.create(0) femm.mi_probdef(0, "millimeters", "axi", 1E-16) femm.mi_saveas("temp/temp" + self._seed + ".fem") femm.mi_addcircprop("Bobine", self._i0, 1) femm.mi_addmaterial("Air", 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0)
def set_FEMM_circuit_prop(circuits, Clabel, I, is_mmf, Npcpp, j_t0): """Create or update the property of a circuit Parameters ---------- circuits: list list the name of all circuits label: str the label of the related surface q_id : int Index of the phase I : Data Lamination currents waveforms is_mmf: bool 1 to compute the lamination magnetomotive force / lamination magnetic field Npcpp: int number of parallel circuits per phase (maximum 2p) j_t0 : int time step for winding current calculation Returns ------- circuits : list list the name of the circuits in FEMM """ q_id = int(Clabel[5:]) if I is not None: I = I.values if Clabel in circuits: if I is not None and I.size != 0 and LA.norm(I) != 0: # Update existing circuit femm.mi_modifycircprop(Clabel, 1, is_mmf * I[q_id, j_t0] / Npcpp) else: # Create new circuit femm.mi_addcircprop(Clabel, 0, 1) circuits.append(Clabel) return circuits
def initial_setup(boundary, currents, **kwargs): '''Start femm and setup problem definition and set boundary condition.''' if kwargs.get('hide') is True: femm.openfemm(1) femm.main_minimize() else: femm.openfemm() # newdocument(doctype) # From manual: Creates a new preprocessor document and opens up a new # preprocessor window. Specify doctype to be 0 for a magnetics problem, 1 # for an electrostatics problem, 2 for a heat flow problem, or 3 for a # current flow problem. An alternative syntax for this command is # create(doctype) femm.newdocument(0) # ei probdef(units,type,precision,(depth),(minangle)) # From manual: changes the problem definition. The units parameter # specifies the units used for measuring length in the problem domain. # Valid "units" entries are "inches", "millimeters", "centimeters", "mils", # "meters, and "micrometers". Set problemtype to "planar" for a 2-D planar # problem, or to "axi" for an axisymmetric problem. The precision parameter # dictates the precision required by the solver. For example, entering # 1.E-8 requires the RMS of the residual to be less than 10^-8. A fourth # parameter, representing the depth of the problem in the into-thepage # direction for 2-D planar problems, can also be specified for planar # problems. A sixth parameter represents the minimum angle constraint sent # to the mesh generator. if 'frequency' in kwargs: freq = kwargs['frequency'] else: freq = 6.78e6 if 'precision' in kwargs: precision = kwargs['precision'] else: precision = 5e-9 if 'min_angle' in kwargs: min_angle = kwargs['min_angle'] else: min_angle = 30 femm.mi_probdef(freq, 'millimeters', 'axi', precision, 50, min_angle) # Circuit parameters # mi addcircprop("circuitname", i, circuittype) # From manual: adds a new circuit property with name "circuitname" with a # prescribed current, i. The circuittype parameter is 0 for a # parallel-connected circuit and 1 for a series-connected circuit. # The currents in the primary and secondary circuits are set I1, I2 = currents femm.mi_addcircprop('phase_prim', I1, 1) femm.mi_addcircprop('phase_sec', I2, 1) # Add materials properties used in the simulation # mi addmaterial("materialname", mu x, mu y, H c, J, Cduct, Lam d, # Phi hmax, lam fill, LamType, Phi hx, Phi hy,NStrands,WireD) # From manual: adds a newmaterial with called "materialname" with the # material properties: # – mu x Relative permeability in the x- or r-direction. # – mu y Relative permeability in the y- or z-direction. # – H c Permanent magnet coercivity in Amps/Meter. # – J Real Applied source current density in Amps/mm2. # – Cduct Electrical conductivity of the material in MS/m. # – Lam d Lamination thickness in millimeters. # – Phi hmax Hysteresis lag angle in degrees, used for nonlinear BH curves. # – Lam fill Fraction of the volume occupied per lamination that is # actually filled with iron (Note that this parameter defaults to 1 the # femm preprocessor dialog box because, by default, iron completely fills # the volume) # – Lamtype Set to # ? 0 – Not laminated or laminated in plane # ? 1 – laminated x or r # ? 2 – laminated y or z # ? 3 – Magnet wire # ? 4 – Plain stranded wire # ? 5 – Litz wire # ? 6 – Square wire # – Phi hx Hysteresis lag in degrees in the x-direction for linear problems # – Phi hy Hysteresis lag in degrees in the y-direction for linear problems # – NStrands Number of strands in the wire build. Should be 1 for Magnet or # Square wire. # – WireD Diameter of each wire constituent strand in millimeters. femm.mi_addmaterial('air', 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) femm.mi_addmaterial('fr4', 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) femm.mi_addmaterial('copper', 1, 1, 0, 0, 58, 0, 0, 0, 0, 0, 0) femm.mi_addmaterial('polysterimide', 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) femm.mi_addmaterial('teflon', 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) femm.mi_addmaterial('silgel', 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) if 'material' in kwargs: for m in kwargs['material']: femm.mi_addmaterial(*m) # Boundary condition # ei makeABC(n,R,x,y,bc) # From manual: creates a series of circular shells that emulate the # impedance of an unbounded domain (i.e. an Improvised Asymptotic Boundary # Condition). The n parameter contains the number of shells to be used # (should be between 1 and 10), R is the radius of the solution domain, and # (x,y) denotes the center of the solution domain. The bc parameter should # be specified as 0 for a Dirichlet outer edge or 1 for a Neumann outer # edge. If the function is called without all the parameters, the function # makes up reasonable values for the missing parameters. femm.mi_makeABC(7, boundary, 0, 0, 0)
-halfWidth + leftCurrentGap + (iman * (bodyWidth + innerStatorGap)), (halfHeight - barHeight - currentHeight) * up_down(side), -halfWidth + leftCurrentGap + currentWidth + (iman * (bodyWidth + innerStatorGap)), (halfHeight - barHeight - currentHeight) * up_down(side), ) current_x_label = -halfWidth + leftCurrentGap + (currentWidth / 2) + ( iman * (bodyWidth + innerStatorGap)) current_y_label = (halfHeight - barHeight - (currentHeight / 2)) * up_down(side) femm.mi_addblocklabel(current_x_label, current_y_label) femm.mi_addcircprop(f"circuit_{side}_{iman}", 30, 1) femm.mi_selectlabel(current_x_label, current_y_label) femm.mi_setblockprop('Coil', 0, 1, f"circuit_{side}_{iman}", 0, 0, 500 * up_down(side) * up_down(iman % 2)) femm.mi_clearselected() femm.mi_drawline( -halfWidth + leftCurrentGap + bodyWidth + (2 * currentWidth) + (iman * (bodyWidth + innerStatorGap)), (halfHeight - barHeight) * up_down(side), -halfWidth + leftCurrentGap + bodyWidth + (2 * currentWidth) + (iman * (bodyWidth + innerStatorGap)), (halfHeight - barHeight - currentHeight) * up_down(side), )
# A more interesting material to add is the iron with a nonlinear # BH curve. First, we create a material in the same way as if we # were creating a linear material, except the values used for # permeability are merely placeholders. femm.mi_addmaterial('Iron', 2100, 2100, 0, 0, 0, 0, 0, 1, 0, 0, 0); # A set of points defining the BH curve is then specified. bdata = [ 0.,0.3,0.8,1.12,1.32,1.46,1.54,1.62,1.74,1.87,1.99,2.046,2.08]; hdata = [ 0, 40, 80, 160, 318, 796, 1590, 3380, 7960, 15900, 31800, 55100, 79600]; for n in range(0,len(bdata)): femm.mi_addbhpoint('Iron', bdata[n],hdata[n]); # Add a "circuit property" so that we can calculate the properties of the # coil as seen from the terminals. femm.mi_addcircprop('icoil', 20, 1); # Apply the materials to the appropriate block labels femm.mi_selectlabel(5,0); femm.mi_setblockprop('Iron', 0, 1, '<None>', 0, 0, 0); femm.mi_clearselected() femm.mi_selectlabel(75,0); femm.mi_setblockprop('Coil', 0, 1, 'icoil', 0, 0, 200); femm.mi_clearselected() femm.mi_selectlabel(30,100); femm.mi_setblockprop('Air', 0, 1, '<None>', 0, 0, 0); femm.mi_clearselected() # Now, the finished input geometry can be displayed.
def create_FEMM_circuit(label, is_eddies, lam, I, is_mmf, j_t0, materials): """Set in FEMM circuits property Parameters ---------- label : label of the surface sym : integer for symmetry is_eddies : 1 to calculate eddy currents lam : LamSlotWind Lamination to set the winding I : ndarray Lamination currents waveforms is_mmf : 1 to compute the lamination magnetomotive force / lamination magnetic field j_t0 : time step for winding current calculation@type integer materials : list of materials already created in FEMM Returns ------- (str, list) the property of the surface having label as surf.label and materials """ is_defcirc = 1 # 1 to define circuits (necessary for eddy current loss kJ = 1 # estimation in AC mode, not necessary for magnetostatics) Zs = lam.slot.Zs rho = lam.mat_type.elec.rho # Resistivity at 20°C wind_mat = lam.winding.comp_connection_mat(Zs) # number of parallel circuits per phase (maximum 2p) Npcpp = lam.winding.Npcpp Ntcoil = lam.winding.Ntcoil # number of turns per coil Swire = lam.winding.conductor.comp_surface() Sact = lam.winding.conductor.comp_active_surface() if "Rotor" in label: # winding on the rotor Jlabel = "Jr" Clabel = "Circr" else: Jlabel = "Js" Clabel = "Circs" st = label.split("_") Nr = int(st[1][1:]) # zone radial coordinate Nt = int(st[2][1:]) # zone tangential coordinate pos = int(st[3][1:]) # Zone slot number coordinate A = wind_mat[Nr, Nt, pos, :] for zz in range(len(A)): # search for the phase of the winding if A[zz] != 0: q = zz # circuit definition if is_defcirc: if I.size == 0 or LA.norm(I) == 0: femm.mi_addcircprop(Clabel + str(q), 0, 1) # series connected else: femm.mi_addcircprop(Clabel + str(q), is_mmf * I[j_t0][q] / Npcpp, 1) # series connected # definition of armature field current sources and circuits s = sign(wind_mat[Nr, Nt, pos, q]) # same as the sign of Cwind1 if s == 1: cname = Jlabel + str(q) + "+" else: cname = Jlabel + str(q) + "-" if LA.norm(I) == 0: Jcus = 0 else: # equivalent stator current density [A/mm2] Jcus = kJ * 1e-6 * Ntcoil * (I[j_t0, q] / Npcpp) * is_mmf / Sact if cname not in materials: # adding new current source material if necessary femm.mi_addmaterial( cname, 1, 1, 0, s * Jcus, is_eddies * 1e-6 / rho, 0, 0, 1, 0, 0, 0, 1, sqrt(4 * Swire / pi), ) materials.append(cname) return cname, materials
0.06695, 0.05975, 0.0534, 0.0478, 0.04275, 0.0382, 0.03425, 0.0306, 0.02735, 0.0246, 0.02205, 0.0197, 0.01765, 0.0159, 0.01425, 0.0128, 0.01145, 0.0103, 0.00935 ] ### DEFINE THE COIL inches = 1.0 # Define units AWG_coil = 22 od_wire = OD_list[AWG_list.index(AWG_coil)] # find the AWG N_layers = 6 # Number of stacked layers of wire id_coil = 1 * inches # inner coil diameter Lc = 0.77 * inches # Length of the Coil N_turns = round(Lc / od_wire) # Define lengthwise turns current = -6 # Define the amount of current in the coil femm.mi_addcircprop('icoil', current, 1) # Add it to the FEMM model od_coil = id_coil + 2 * N_layers * od_wire # outer coil diameter coil_group_number = 5 # Define coil number different as magnet # Call this function to draw a box with rounded corners # I find this introduces less errors coil_center_x = id_coil / 2 + (od_coil - id_coil) / 4 coil_center_y = 0 drawroundedcorner_box(femm, coil_group_number, (od_coil - id_coil) / 2, Lc, coil_center_x, coil_center_y, od_wire, 0) # With segments now drawn, label it femm.mi_addblocklabel(coil_center_x, coil_center_y) # Create a label within the coil segments femm.mi_selectlabel(coil_center_x, coil_center_y) # Select that label femm.mi_setblockprop('22 AWG', 0, 1, 'icoil', 0, 0,
automesh = 1 meshsize = 30 minangle = 1 # Set up problem type. This sets up problem as an axisymmetric problem with units of micrometers femm.mi_probdef(0, 'micrometers', 'axi', 10**(-8), 0, minangle, 0) # Add materials to our workspace femm.mi_addmaterial('magnet', 1.05, 1.05, 922850, 0, 0.667, 0, 0, 1, 0, 0, 0) femm.mi_addmaterial('air', 1, 1, 0) femm.mi_addmaterial('36awgcopper', 1, 1, 0, i / ((wire_thickness / 2)**(2) * 3.14), 58, 0, 0, 1, 3, 0, 0, 1, 127) #change J applied current #define circuit with current i in series femm.mi_addcircprop('spiral', i, 1) #draw and label magnet wall femm.mi_drawrectangle(0, wall_distance, wall_radius, (wall_distance + wall_thickness)) femm.mi_addblocklabel(wall_radius / 2, (wall_distance + wall_thickness / 2)) femm.mi_selectlabel(wall_radius / 2, (wall_distance + wall_thickness / 2)) femm.mi_setblockprop('magnet', automesh, meshsize, 0, 270, 0, 0) femm.mi_clearselected() #draw and label spiral cross section while (r < outer_radius): if (r == inner_radius): pass else: r = r + wire_spacing
CoreMaterial = "M-15 Steel" CoilMaterial = "Copper" Params.core_gap.sort() femm.openfemm() femm.newdocument(ProblemType.MagnetoStatic.value) Rectangle.problemType = ProblemType.MagnetoStatic femm.mi_probdef(0, 'centimeters', 'planar', 1.e-8, Params.Depth, 30) femm.mi_getmaterial(Params.CoreMaterial) femm.mi_getmaterial(Params.CoilMaterial) femm.mi_getmaterial('Air') femm.mi_addcircprop('Circuit', Params.ExcitationCurrent, 1) # 0 = paralel, 1 = series # name, A0, A1, A2, Phi, Mu, Sig, c0, c1, BdryFormat, ia, oa femm.mi_addboundprop('Boundary', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) # define air around everything air_width = 2 * Params.D4 + Params.D1 + Params.coil_gap * 2 + 2 * Params.air_margin air_height = 2 * Params.air_margin + Params.D7 + Params.core_gap[-1] + Params.D2 air_rectangle = Rectangle( 0 - Params.D4 - Params.coil_gap - Params.air_margin, 0 - Params.core_gap[-1] - Params.D7 - Params.air_margin, air_width, air_height) air_rectangle.assign_material( 'Air', 0, 0, Point(Params.D1 / 2,
femm.mi_clearselected() femm.mi_addblocklabel(0.02, d) femm.mi_selectlabel(0.02, d) femm.mi_setblockprop('Pure Iron', 1, 0, '<None>', 0, 0, 0) # Secondary Coil Copper Labels femm.mi_clearselected() femm.mi_addblocklabel(0.075, 0.21) femm.mi_addblocklabel(0.075, -0.21) femm.mi_selectlabel(0.075, 0.21) femm.mi_selectlabel(0.075, -0.21) femm.mi_setblockprop('30 AWG', 1, 0, '<None>', 0, 0, 0) # Primary Coil Circuit and Block Labels femm.mi_clearselected() femm.mi_addcircprop('Primary', 1, 1) # Primary coil, 1A current, series femm.mi_addblocklabel(0.075, 0) femm.mi_selectlabel(0.075, 0) femm.mi_setblockprop('30 AWG', 1, 0, 'Primary', 0, 0, 200) # Lets make a default open air boundary femm.mi_makeABC() input('Press enter to continue...') # Save so we can analyze femm.mi_saveas('lvdt_sweep.fem') femm.mi_analyze() femm.mi_loadsolution() # Show the density plot
def makeCircuit(name, current=0, series=1): femm.mi_addcircprop(name, current, series)