def set_group(self, groupID): #select circle slightly larger than the rotor select_oversize = 0.001 #mm fe.mi_selectcircle(0, 0, self.OR + select_oversize, 4) fe.mi_setgroup(groupID) fe.mi_clearselected()
def addNodeZ(n, group=-1): if group == -1: group = femmgroupmode femm.mi_addnode(n.real, n.imag) femm.mi_selectnode(n.real, n.imag) femm.mi_setgroup(group) femm.mi_clearselected()
def setCirc(r, phi, mat, circuit, turns, group=-1): if group == -1: group = femmgroupmode n = cmath.rect(r, rad(phi)) femm.mi_selectlabel(n.real, n.imag) femm.mi_setblockprop(mat, 1, 0, circuit, 0, group, turns) femm.mi_clearselected()
def setMagnet(r, phi, mat, magdir, group=-1): if group == -1: group = femmgroupmode n = cmath.rect(r, rad(phi)) femm.mi_selectlabel(n.real, n.imag) femm.mi_setblockprop(mat, 1, 0, '<None>', magdir, group, 0) femm.mi_clearselected()
def addNode(r, phi, group=-1): if group == -1: group = femmgroupmode n = cmath.rect(r, rad(phi)) femm.mi_addnode(n.real, n.imag) femm.mi_selectnode(n.real, n.imag) femm.mi_setgroup(group) femm.mi_clearselected()
def addBlockLabel(r, phi, group=-1): if group == -1: group = femmgroupmode n = cmath.rect(r, rad(phi)) femm.mi_addblocklabel(n.real, n.imag) femm.mi_selectlabel(n.real, n.imag) femm.mi_setgroup(group) femm.mi_clearselected() return n
def addLineZZ(n1, n2, group=-1): if group == -1: group = femmgroupmode femm.mi_addsegment(n1.real, n1.imag, n2.real, n2.imag) # select middle of arc for adding group n = (n1.real + n2.real) / 2 + ((n1.imag + n2.imag) / 2) * 1j femm.mi_selectsegment(n.real, n.imag) femm.mi_setgroup(group) femm.mi_clearselected()
def deleteCoil(self): """Delete the coil Provided for debugging, should not be used. """ femm.mi_clearselected() femm.mi_selectgroup(2) femm.mi_deleteselected() femm.mi_deletematerial("Cuivre")
def conditions_limites(self): """Méthode permettant d'attribuer les conditions aux limites""" femm.mi_addboundprop('lim', 0, 0, 0, 0, 0, 0, 0, 0, 0) femm.mi_selectsegment(0, self.hauteur / 2) femm.mi_selectsegment(0, -self.hauteur / 2) femm.mi_selectsegment(self.largeur / 2, 0) femm.mi_selectsegment(-self.largeur / 2, 0) femm.mi_setsegmentprop('lim', 0, 1, 0, 0) femm.mi_clearselected()
def deleteProjectile(self): """Delete the projectile Deletes the projectile (drawn) but doesn't erase its properties. """ femm.mi_clearselected() femm.mi_selectgroup(1) femm.mi_deleteselected() femm.mi_deletematerial("Projectile") if self.espace is not None: femm.mi_addsegment(0, -self.espace, 0, self.espace)
def addLine(r1, phi1, r2, phi2, group=-1): if group == -1: group = femmgroupmode n1 = cmath.rect(r1, rad(phi1)) n2 = cmath.rect(r2, rad(phi2)) femm.mi_addsegment(n1.real, n1.imag, n2.real, n2.imag) # select middle of arc for adding group # todo: better guess at point on line (unpredictable if phi1 != phi2) n = cmath.rect((r1 + r2) / 2., rad((phi1 + phi2) / 2.)) femm.mi_selectsegment(n.real, n.imag) femm.mi_setgroup(group) femm.mi_clearselected()
def addArcZZ(n1, n2, group=-1): if group == -1: group = femmgroupmode r1, phi1 = cmath.polar(n1) r2, phi2 = cmath.polar(n2) femm.mi_addarc(n1.real, n1.imag, n2.real, n2.imag, deg(abs(phi1 - phi2)), 10) # select middle of arc for adding group # todo: better guess at point on arc (unpredictable if r1 != r2) n = cmath.rect((r1 + r2) / 2., (phi1 + phi2) / 2.) femm.mi_selectarcsegment(n.real, n.imag) femm.mi_setgroup(group) femm.mi_clearselected()
def affectation_materiaux(self): """Méthode permettant d'attribuer la propriété des matériaux""" # Affectation de l'air (x,y) femm.mi_addmaterial('Air', 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) femm.mi_addblocklabel(0, 0) femm.mi_selectlabel(0, 0) femm.mi_setblockprop('Air', 0, 1, '<None>', 0, 0, 0) femm.mi_clearselected() # Affectation du Cuivre (bobine positive) (Attention J en A/mm²) femm.mi_addmaterial('Cuivre-', 1, 1, 0, -self.k_b * self.j_max * 1.0e-6, 0, 0, 0, 0, 0, 0, 0) femm.mi_addblocklabel(self.largeur / 4, 0) femm.mi_selectlabel(self.largeur / 4, 0) femm.mi_setblockprop('Cuivre-', 0, 1, 'incricuit', 0, 0, 0) femm.mi_clearselected() # Affectation du Cuivre (bobine négative) femm.mi_addmaterial('Cuivre+', 1, 1, 0, self.k_b * self.j_max * 1.0e-6, 0, 0, 0, 0, 0, 0, 0) femm.mi_addblocklabel(-self.largeur / 4, 0) femm.mi_selectlabel(-self.largeur / 4, 0) femm.mi_setblockprop('Cuivre+', 0, 1, 'incircuit', 0, 0, 0) femm.mi_clearselected() # Matériau non linéaire # Création d'un matériau linéaire femm.mi_addmaterial('Iron', 2100, 2100, 0, 0, 0, 0, 0, 0, 0, 0, 0) # Les points de la courbe BH bdata = [ 0.1, 0.2, 0.4, 0.7, 1., 1.2, 1.3, 1.4, 1.5, 1.55, 1.6, 1.65, 1.7 ] hdata = [ 26.5, 37.8, 52.4, 71.9, 99.3, 136, 176, 279, 659, 1084, 1718, 2577, 3670 ] # Affectation des points de la courbe for n in range(0, len(bdata)): femm.mi_addbhpoint('Iron', bdata[n], hdata[n]) # Les points de la courbe Pertes fer = f(B) pdata = [ 0.0176, 0.0683, 0.240, 0.602, 1.09, 1.51, 1.79, 2.14, 2.56, 2.77, 2.96, 3.13, 3.29 ] self._interp_pertes_fer = interp1d(bdata, pdata, bounds_error=False, fill_value=(pdata[0], pdata[-1])) # Affectation du matériau femm.mi_addblocklabel(self.largeur / 2 - self.l_dent / 4, 0) femm.mi_selectlabel(self.largeur / 2 - self.l_dent / 4, 0) femm.mi_setblockprop('Iron', 0, 1, '<None>', 0, 0, 0) femm.mi_clearselected()
def draw_conductor(coords, in_conductor, label_name, label_dict): '''Draw a square conductor, set a block label in the middle of the conductor and add label properties.''' femm.mi_drawrectangle(*coords) label_coord = (average( (coords[0], coords[2])), average((coords[1], coords[3]))) femm.mi_addblocklabel(*label_coord) femm.mi_selectlabel(*label_coord) if in_conductor == 1: femm.mi_setblockprop('copper', 1, 0, 'phase_prim', 0, 1, 1) elif in_conductor == 0: femm.mi_setblockprop('copper', 1, 0, 'phase_sec', 0, 1, 1) femm.mi_clearselected() label_dict[label_name] = label_coord
def build_coil(self, coil_dict): """ load coil_cross sections into femm environment :param coil_dict: :return: """ for section, section_tuple in coil_dict.items(): path_point = np.array(section_tuple[0]) profile = section_tuple[1] + path_point # draw line segments between nodes for index, point in enumerate(profile): last_point = profile[index - 1] femm.mi_drawline(last_point[1], last_point[0], point[1], point[0]) femm.mi_addblocklabel(path_point[1], path_point[0]) femm.mi_selectlabel(path_point[1], path_point[0]) femm.mi_setblockprop(str(section)) femm.mi_clearselected()
def setSpace(self): """Define space Define the whole space used in FEMM Raises: Exception -- Coil and projectile must be defined first to compute a safe space size. """ if self.Lp is not None and self.Lb is not None: femm.mi_clearselected() self.espace = self.__space_factor * max(self.Lb, self.Rbo, self.Lp) femm.mi_addblocklabel(2 * self.Rbo, 0) femm.mi_selectlabel(2 * self.Rbo, 0) femm.mi_setblockprop("Air", 0, self.meshsize, "<None>", 0, 3, 0) femm.mi_makeABC(7, self.espace, 0, 0, 0) femm.mi_zoomnatural() else: raise Exception("Define coil and projectile first.")
def affectation_materiaux(self): """Méthode permettant d'attribuer la propriété des matériaux""" # Affectation de l'air (x,y) femm.mi_addmaterial('Air', 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) femm.mi_addblocklabel(0, 0) femm.mi_selectlabel(0, 0) femm.mi_setblockprop('Air', 0, 1, '<None>', 0, 0, 0) femm.mi_clearselected() # Affectation du Cuivre (bobine positive) (Attention J en A/mm²) femm.mi_addmaterial('Cuivre+', 1, 1, 0, self.k_b * self.j_max * 1.0e-6, 0, 0, 0, 0, 0, 0, 0) femm.mi_addblocklabel(self.largeur / 4, 0) femm.mi_selectlabel(self.largeur / 4, 0) femm.mi_setblockprop('Cuivre+', 0, 1, 'incricuit', 0, 0, 0) femm.mi_clearselected() # Affectation du Cuivre (bobine négative) femm.mi_addmaterial('Cuivre-', 1, 1, 0, -self.k_b * self.j_max * 1.0e-6, 0, 0, 0, 0, 0, 0, 0) femm.mi_addblocklabel(-self.largeur / 4, 0) femm.mi_selectlabel(-self.largeur / 4, 0) femm.mi_setblockprop('Cuivre-', 0, 1, 'incircuit', 0, 0, 0) femm.mi_clearselected() # Matériau non linéaire # Création d'un matériau linéaire femm.mi_addmaterial('Iron', 2100, 2100, 0, 0, 0, 0, 0, 0, 0, 0, 0) # Les points de la courbe BH bdata = [ 0., 0.2, 0.4, 0.7, 1, 1.2, 1.3, 1.4, 1.5, 1.55, 1.6, 1.65, 1.7, 1.8, 1.91, 2, 2.1, 3.2454 ] hdata = [ 0., 31.9, 44.9, 67.3, 106., 164., 235., 435., 1109., 1813., 2802., 4054., 5592., 9711., 16044., 31319., 88491., 1000000. ] # Affectation des points de la courbe for n in range(0, len(bdata)): femm.mi_addbhpoint('Iron', bdata[n], hdata[n]) # Affectation du matériau femm.mi_addblocklabel(self.largeur / 2 - self.l_dent / 4, 0) femm.mi_selectlabel(self.largeur / 2 - self.l_dent / 4, 0) femm.mi_setblockprop('Iron', 0, 1, '<None>', 0, 0, 0) femm.mi_clearselected()
def draw_FEMM(self, nodeprop=None, maxseg=None, propname=None, hide=False, group=None): """Draw the Arc object in FEMM and assign the property Parameters ---------- nodeprop : Nodal property (Default value = None) maxseg : Meshed with elements that span at most maxsegdeg degrees per element (Default value = None) propname : Boundary property ’propname’ (Default value = None) hide : 0 = not hidden in post-processor, 1 == hidden in post processor (Default value = False) group : the group the Arc1 object belongs (Default value = None) Returns ------- None """ # Get BC (if any) if self.label in boundary_prop: propname = boundary_prop[self.label] # Create the nodes begin = self.get_begin() end = self.get_end() X1, Y1 = begin.real, begin.imag X2, Y2 = end.real, end.imag femm.mi_addnode(X1, Y1) femm.mi_selectnode(X1, Y1) femm.mi_setnodeprop(nodeprop, group) femm.mi_clearselected() femm.mi_addnode(X2, Y2) femm.mi_selectnode(X2, Y2) femm.mi_setnodeprop(nodeprop, group) femm.mi_clearselected() # Create the arc angle = self.get_angle(is_deg=True) if angle > 0: femm.mi_addarc(X1, Y1, X2, Y2, angle, 2) else: femm.mi_addarc(X2, Y2, X1, Y1, -angle, 2) # Set Arc properties Zm = self.get_middle() femm.mi_selectarcsegment(Zm.real, Zm.imag) femm.mi_setarcsegmentprop(maxseg, propname, hide, group) femm.mi_clearselected()
def drawCoil(self): """Draw the coil Draws the coil in the FEMM instance Raises: Exception -- The coil is not defined, please call defineCoil before. """ if self.Lb is not None: femm.mi_clearselected() femm.mi_addmaterial("Cuivre", 1, 1, 0, 0, 1 / self.rho * 10**-6, 0, 0, 1, 3 if self.wire_type == "round" else 6, 0, 0, 1, self.phi) femm.mi_addnode(self.Rbi, -self.Lb / 2) femm.mi_addnode(self.Rbo, -self.Lb / 2) femm.mi_addnode(self.Rbi, self.Lb / 2) femm.mi_addnode(self.Rbo, self.Lb / 2) femm.mi_addsegment(self.Rbi, -self.Lb / 2, self.Rbo, -self.Lb / 2) femm.mi_addsegment(self.Rbo, -self.Lb / 2, self.Rbo, self.Lb / 2) femm.mi_addsegment(self.Rbo, self.Lb / 2, self.Rbi, self.Lb / 2) femm.mi_addsegment(self.Rbi, -self.Lb / 2, self.Rbi, self.Lb / 2) femm.mi_selectnode(self.Rbi, -self.Lb / 2) femm.mi_selectnode(self.Rbo, -self.Lb / 2) femm.mi_selectnode(self.Rbi, self.Lb / 2) femm.mi_selectnode(self.Rbo, self.Lb / 2) femm.mi_selectsegment(self.Rbi, 0) femm.mi_selectsegment((self.Rbi + self.Rbo) / 2, -self.Lb / 2) femm.mi_selectsegment(self.Rbo, 0) femm.mi_selectsegment((self.Rbi + self.Rbo) / 2, self.Lb / 2) femm.mi_setgroup(2) femm.mi_addblocklabel((self.Rbi + self.Rbo) / 2, 0) femm.mi_selectlabel((self.Rbi + self.Rbo) / 2, -self.Lb / 2) femm.mi_setblockprop("Cuivre", 0, self.meshsize, "Bobine", 0, 2, self.n) femm.mi_clearselected() else: raise Exception("No coil defined.")
def drawProjectile(self): """Draw projectile Draws the projectil in the FEMM instance Raises: Exception -- Projectile is not defined """ if self.Lp is not None: femm.mi_addmaterial("Projectile", self.mu, self.mu, 0, 0, 0, 0, 0, 1, 0, 0, 0) femm.mi_clearselected() femm.mi_addnode(0, -self.Lp / 2) femm.mi_addnode(self.Rp, -self.Lp / 2) femm.mi_addnode(0, self.Lp / 2) femm.mi_addnode(self.Rp, self.Lp / 2) femm.mi_addsegment(0, -self.Lp / 2, self.Rp, -self.Lp / 2) femm.mi_addsegment(self.Rp, -self.Lp / 2, self.Rp, self.Lp / 2) femm.mi_addsegment(self.Rp, self.Lp / 2, 0, self.Lp / 2) femm.mi_addsegment(0, self.Lp / 2, 0, -self.Lp / 2) femm.mi_selectnode(0, -self.Lp / 2) femm.mi_selectnode(self.Rp, -self.Lp / 2) femm.mi_selectnode(0, self.Lp / 2) femm.mi_selectnode(self.Rp, self.Lp / 2) femm.mi_selectsegment(0, 0) femm.mi_selectsegment(self.Rp / 2, -self.Lp / 2) femm.mi_selectsegment(self.Rp, 0) femm.mi_selectsegment(self.Rp / 2, self.Lp / 2) femm.mi_setgroup(1) femm.mi_addblocklabel(self.Rp / 2, 0) femm.mi_selectlabel(self.Rp / 2, 0) femm.mi_setblockprop("Projectile", 0, self.meshsize, "<None>", 0, 1, 0) femm.mi_clearselected() else: raise Exception("No projectile defined.")
def set_materials(self, magnet, iron): #ensure that the materials are actually added to the analysis magnet.add() iron.add() R1 = self.OR - (self.dm + self.dri) #inner radius of rotor R2 = self.OR - self.dm #radius to inside of PM #assign magnet material mag_center = [(R2 + self.OR) / 2, 0] mag_orientation = 1 #1 = North facing out, -1 = North facing in num_magnets = 2 * self.p theta = 360 / num_magnets for i in range(num_magnets): xy = rotate(*mag_center, theta * i) #add 180 degrees if magnet faces in mag_dir = theta * i + 180 * (mag_orientation < 0 ) #magnet orientation in deg fe.mi_addblocklabel(*xy) fe.mi_selectlabel(*xy) fe.mi_setblockprop(magnet.name, 1, 0, 0, mag_dir, 0, 0) fe.mi_clearselected() mag_dir *= -1 #alternate between N and S poles #assign steel material xy = [(R1 + R2) / 2, 0] fe.mi_addblocklabel(*xy) fe.mi_selectlabel(*xy) fe.mi_setblockprop(iron.name, 1, 0, 0, 0, 1, 0) fe.mi_clearselected() #add air to center if rotor is hollow if self.hollow: fe.mi_addblocklabel(0, 0) fe.mi_selectlabel(0, 0) fe.mi_setblockprop('Air', 1, 0, 0, 0, 0, 0) fe.mi_clearselected()
def add_block_labels(tg, etiquettes_dict): '''Add block labels to pcbs, air, isolation disc, isolation gel/liquid.''' # Add block labels # ei seteditmode(editmode) # From manual: Sets the current editmode to: # – "nodes" - nodes # – "segments" - line segments # – "arcsegments" - arc segments # – "blocks" - block labels # – "group" - selected group femm.mi_seteditmode('blocks') # ei addblocklabel(x,y) # From manual: Add a new block label at (x,y) # labels for the PCBs coords = [2, tg.height_dielectric + tg.height_pcb_core / 2.] femm.mi_addblocklabel(*coords) etiquettes_dict['pcb_prim'] = coords coords = [2, -tg.height_pcb_core / 2.] femm.mi_addblocklabel(*coords) etiquettes_dict['pcb_sec'] = coords # label for the surrounding air coords = [2, tg.height_dielectric * 2 + tg.height_gel] femm.mi_addblocklabel(*coords) etiquettes_dict['air'] = coords # label for the dilectric gel or liquid surrounding the transformer coords = [tg.radius_pcb + 2, tg.height_dielectric + tg.height_gel / 2.] femm.mi_addblocklabel(*coords) etiquettes_dict['gel'] = coords # label for the isolation disc coords = [2, tg.height_dielectric / 2.] femm.mi_addblocklabel(*coords) etiquettes_dict['isolant'] = coords # Set material type for all blocks # mi_setblockprop("blockname", automesh, meshsize, "incircuit", # magdirection, group, turns) # From manual: Set the selected block labels to have the properties: # – Block property "blockname". # – automesh: 0 = mesher defers to mesh size constraint defined in # meshsize, 1 = mesher automatically chooses the mesh density. # – meshsize: size constraint on the mesh in the block marked by this label # – Block is a member of the circuit named "incircuit" # – The magnetization is directed along an angle in measured in degrees # denoted by the parameter magdirection. Alternatively, magdirection can be # a string containing a formula that prescribes the magnetization direction # as a function of element position. In this formula theta and R denotes # the angle in degrees of a line connecting the center each element with # the origin and the length of this line, respectively; x and y denote the # x- and y-position of the center of the each element. For axisymmetric # problems, r and z should be used in place of x and y. # – A member of group number group # – The number of turns associated with this label is denoted by turns. femm.mi_selectlabel(*etiquettes_dict['pcb_prim']) femm.mi_selectlabel(*etiquettes_dict['pcb_sec']) femm.mi_setblockprop('fr4', 1, 0, '<None>', 0, 1, 0) femm.mi_clearselected() femm.mi_selectlabel(*etiquettes_dict['air']) femm.mi_setblockprop('air', 1, 0, '<None>', 0, 1, 0) femm.mi_clearselected() femm.mi_selectlabel(*etiquettes_dict['gel']) femm.mi_setblockprop('silgel', 1, 0, 'None') femm.mi_clearselected() femm.mi_selectlabel(*etiquettes_dict['isolant']) femm.mi_setblockprop(tg.material_dielectric, 1, 0, 'None') femm.mi_clearselected()
def clearGroup(group): if group != 0: clearGroup(0) femm.mi_selectgroup(group) femm.mi_deleteselected() femm.mi_clearselected()
def assign_FEMM_surface(surf, prop, FEMM_dict, rotor, stator): """Assign the property given in parameter to surface having the label given Parameters ---------- surf : Surface the surface to assign prop : str The property to assign in FEMM FEMM_dict : dict Dictionnary containing the main parameters of FEMM rotor : Lamination The rotor of the machine stator : Lamination The stator of the machine Returns ------- None """ mesh_dict = get_mesh_param(surf.label, FEMM_dict) label = surf.label Clabel = 0 # By default no circuit Ntcoil = 0 # By default no circuit mag = 0 # By default no magnetization # Select the lamination according to the label if "Rotor" in label: lam = rotor else: lam = stator # point_ref is None => don't assign the surface if surf.point_ref is not None: # Select the surface point_ref = surf.point_ref femm.mi_addblocklabel(point_ref.real, point_ref.imag) femm.mi_selectlabel(point_ref.real, point_ref.imag) # Get circuit or magnetization properties if needed if "Wind" in label: # If the surface is a winding if "Rotor" in label: # Winding on the rotor Clabel = "Circr" + prop[2] else: # winding on the stator Clabel = "Circs" + prop[2] Ntcoil = lam.winding.Ntcoil if prop[-1] == "-": # Adapt Ntcoil sign if needed Ntcoil *= -1 elif "HoleMagnet" in label: # LamHole if "Parallel" in label: # calculate pole angle and angle of pole middle alpha_p = 360 / lam.hole[0].Zh mag_0 = (floor_divide(angle(point_ref, deg=True), alpha_p) + 0.5) * alpha_p # HoleM50 or HoleM53 if (type(lam.hole[0]) == HoleM50) or (type(lam.hole[0]) == HoleM53): if "_T0_" in label: mag = mag_0 + lam.hole[0].comp_alpha() * 180 / pi else: mag = mag_0 - lam.hole[0].comp_alpha() * 180 / pi # HoleM51 if type(lam.hole[0]) == HoleM51: if "_T0_" in label: mag = mag_0 + lam.hole[0].comp_alpha() * 180 / pi elif "_T1_" in label: mag = mag_0 else: mag = mag_0 - lam.hole[0].comp_alpha() * 180 / pi # HoleM52 if type(lam.hole[0]) == HoleM52: mag = mag_0 # modifiy magnetisation of south poles if "_S_" in label: mag = mag + 180 else: raise NotImplementedYetError( "Only parallele magnetization are available for HoleMagnet" ) elif "Magnet" in label: # LamSlotMag if "Radial" in label and "_N_" in label: # Radial magnetization mag = "theta" # North pole magnet elif "Radial" in label: mag = "theta + 180" # South pole magnet elif "Parallel" in label and "_N_" in label: mag = angle(point_ref) * 180 / pi # North pole magnet elif "Parallel" in label: mag = angle(point_ref) * 180 / pi + 180 # South pole magnet elif "Hallbach" in label: Zs = lam.slot.Zs mag = str(-(Zs / 2 - 1)) + " * theta + 90 " elif "Ventilation" in label: prop = "Air" elif "Hole" in label: prop = "Air" # Set the surface property femm.mi_setblockprop( prop, mesh_dict["automesh"], mesh_dict["meshsize"], Clabel, mag, mesh_dict["group"], Ntcoil, ) femm.mi_clearselected()
(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), ) femm.mi_drawline( -halfWidth + leftCurrentGap + bodyWidth + (2 * currentWidth) + (iman * (bodyWidth + innerStatorGap)), (halfHeight - barHeight - currentHeight) * up_down(side), -halfWidth + leftCurrentGap + bodyWidth + currentWidth +
def drawroundedcorner_box(femm, group, width, length, x_center, y_center, corner_radius, one_sided): x1 = x_center - width / 2 y1 = y_center - length / 2 x2 = x1 + width y2 = y1 + length # mc = .02 * inches mc = corner_radius # first create nodes at the 4 corners # because they will be joined by an arc segment c1_x = x1 c1_y = y1 c2_x = x2 c2_y = y1 c3_x = x2 c3_y = y2 c4_x = x1 c4_y = y2 # now make blunted edge magnet based on it n1x = c1_x n1y = c1_y + mc n2x = c1_x + mc n2y = c1_y n3x = c2_x - mc n3y = c2_y n4x = c2_x n4y = c2_y + mc n5x = c3_x n5y = c3_y - mc n6x = c3_x - mc n6y = c3_y n7x = c4_x + mc n7y = c4_y n8x = c4_x n8y = c4_y - mc # If drawing all 4 corners if (one_sided == 0): femm.mi_addnode(n1x, n1y) femm.mi_addnode(n2x, n2y) femm.mi_addnode(n3x, n3y) femm.mi_addnode(n4x, n4y) femm.mi_addnode(n5x, n5y) femm.mi_addnode(n6x, n6y) femm.mi_addnode(n7x, n7y) femm.mi_addnode(n8x, n8y) femm.mi_addarc(n1x, n1y, n2x, n2y, 90, 3) femm.mi_addsegment(n2x, n2y, n3x, n3y) femm.mi_addarc(n3x, n3y, n4x, n4y, 90, 3) femm.mi_addsegment(n4x, n4y, n5x, n5y) femm.mi_addarc(n5x, n5y, n6x, n6y, 90, 3) femm.mi_addsegment(n6x, n6y, n7x, n7y) femm.mi_addarc(n7x, n7y, n8x, n8y, 90, 3) femm.mi_addsegment(n8x, n8y, n1x, n1y) femm.mi_clearselected() # femm.mi_drawrectangle(x1, mag_y1, mag_x2, mag_y2) # femm.mi_selectrectangle(x1, mag_y1, mag_x2, mag_y2,0) femm.mi_selectsegment(c1_x, c1_y) femm.mi_setgroup(group) femm.mi_selectsegment(c1_x + width / 4, c1_y) femm.mi_setgroup(group) femm.mi_selectsegment(c2_x, c2_y) femm.mi_setgroup(group) femm.mi_selectsegment(c3_x, c3_y + length / 2) femm.mi_setgroup(group) femm.mi_selectsegment(c3_x, c3_y) femm.mi_setgroup(group) femm.mi_selectsegment(c3_x - width / 4, c3_y) femm.mi_setgroup(group) femm.mi_selectsegment(c4_x, c4_y) femm.mi_setgroup(group) femm.mi_selectsegment(c4_x, c4_y - length / 2) femm.mi_setgroup(group) #femm.mi_clearselected() # if drawing only rounded corners on far side # because location is on axis. if (one_sided == 1): femm.mi_addnode(c1_x, c1_y) femm.mi_addnode(n3x, n3y) femm.mi_addnode(n4x, n4y) femm.mi_addnode(n5x, n5y) femm.mi_addnode(n6x, n6y) femm.mi_addnode(c4_x, c4_y) femm.mi_addsegment(c4_x, c4_y, c1_x, c1_y) femm.mi_addsegment(c1_x, c1_y, n3x, n3y) femm.mi_addarc(n3x, n3y, n4x, n4y, 90, 3) femm.mi_addsegment(n4x, n4y, n5x, n5y) femm.mi_addarc(n5x, n5y, n6x, n6y, 90, 3) femm.mi_addsegment(n6x, n6y, c4_x, c4_y) femm.mi_clearselected() femm.mi_selectsegment(c1_x, c1_y + length / 2) femm.mi_setgroup(group) femm.mi_selectsegment(c1_x + width / 2, c1_y) femm.mi_setgroup(group) femm.mi_selectsegment(c2_x, c2_y) femm.mi_setgroup(group) femm.mi_selectsegment(c2_x, c2_y + length / 2) femm.mi_setgroup(group) femm.mi_selectsegment(c3_x, c3_y) femm.mi_setgroup(group) femm.mi_selectsegment(c3_x - width / 2, c3_y) femm.mi_setgroup(group)
def computeMuImpact(self, mus=[5, 10, 50, 100, 500, 1000, 5000], error=0.1): """Compute the impact of Mu The model is NOT LINEAR in mu. It is hard to guess what would be the effect of an increased suceptibility and it may highly modify the response of the coil. However, for some configuration the error is low (typically a long coil and a small projectile). This function provides some help to know if we can consider the model linear in Mu. Simply provide a range of possible susceptibilities for your projectile, and an acceptable relative error. We do not check the whole linearity, but simply in two points selected empirically. Therefore some care should be taken regarding the output of this helper method. Keyword Arguments: mus {list} -- [description] (default: {[5, 10, 50, 100, 500, 1000, 5000]}) error {number} -- [description] (default: {0.1}) """ _mu = self.mu res = [] test_res = [] print("Coil " + self._seed + " mus") for mu in mus: self.mu = mu self.deleteProjectile() self.drawProjectile() femm.mi_clearselected() femm.mi_selectgroup(1) femm.mi_analyze() femm.mi_loadsolution() femm.mo_groupselectblock(1) res.append(femm.mo_getcircuitproperties("Bobine")[2] / self._i0) femm.mi_movetranslate2(0, self.Lb / 4, 4) femm.mi_analyze() femm.mi_loadsolution() femm.mo_groupselectblock(1) test_res.append( femm.mo_getcircuitproperties("Bobine")[2] / self._i0) self.mu = _mu success = True errors = [] for i in range(0, len(test_res)): errors.append( numpy.abs((res[i] / res[0]) / (test_res[i] / test_res[0]) - 1)) if errors[-1] > error: success = False # break if success: return { 'valid': True, 'mus': mus, 'mu_Lz_0': res, 'mu_Lz_1': test_res, 'errors': errors } else: return { 'valid': False, 'mus': mus, 'mu_Lz_0': res, 'mu_Lz_1': test_res, 'errors': errors }
def draw_FEMM(self, nodeprop=None, maxseg=None, propname=None, hide=False, group=None): """Draw the Arc object in FEMM and assign the property Parameters ---------- nodeprop : Nodal property (Default value = None) maxseg : Meshed with elements that span at most maxsegdeg degrees per element (Default value = None) propname : Boundary property ’propname’ (Default value = None) hide : 0 = not hidden in post-processor, 1 == hidden in post processor (Default value = False) group : the group the Arc1 object belongs (Default value = None) Returns ------- None """ # Get BC (if any) for bound_label in boundary_prop: if bound_label in self.label: propname = boundary_prop[bound_label] # split if arc angle > 180 angle = self.get_angle(is_deg=True) # Create the nodes begin = self.get_begin() mid = self.get_middle() end = self.get_end() X1, Y1 = begin.real, begin.imag X2, Y2 = mid.real, mid.imag X3, Y3 = end.real, end.imag femm.mi_addnode(X1, Y1) femm.mi_selectnode(X1, Y1) femm.mi_setnodeprop(nodeprop, group) femm.mi_clearselected() femm.mi_addnode(X3, Y3) femm.mi_selectnode(X3, Y3) femm.mi_setnodeprop(nodeprop, group) femm.mi_clearselected() if abs(angle) > 180: femm.mi_addnode(X2, Y2) femm.mi_selectnode(X2, Y2) femm.mi_setnodeprop(nodeprop, group) femm.mi_clearselected() # invert the nodes if angle < 0: angle = -angle X1, Y1, X3, Y3 = X3, Y3, X1, Y1 if angle > 180: femm.mi_addarc(X1, Y1, X2, Y2, angle / 2, 2) femm.mi_addarc(X2, Y2, X3, Y3, angle / 2, 2) else: femm.mi_addarc(X1, Y1, X3, Y3, angle, 2) # Set Arc properties if angle > 180: cent = self.get_center() mid1 = cent + (mid - cent) * exp(1j * angle / 4) mid2 = cent + (mid - cent) * exp(-1j * angle / 4) femm.mi_selectarcsegment(mid1.real, mid1.imag) femm.mi_selectarcsegment(mid2.real, mid1.imag) else: femm.mi_selectarcsegment(X2, Y2) femm.mi_setarcsegmentprop(maxseg, propname, hide, group) femm.mi_clearselected()
def draw_FEMM( self, nodeprop=None, propname=None, elementsize=None, automesh=None, hide=False, group=None, ): """< Draw the segment in FEMM and assign the property Parameters ---------- nodeprop : Nodal property (Default value = None) propname : Boundary property ’propname’ (Default value = None) elementsize : Local element size along segment no greater than elementsize (Default value = None) automesh : 0 = mesher defers to the element constraint defined by elementsize, 1 = mesher automatically chooses mesh size along the selected segments (Default value = None) hide : 0 = not hidden in post-processor, 1 == hidden in post processorc (Default value = False) group : group the segment belongs (Default value = None) Returns ------- """ # Get BC (if any) if self.label in boundary_prop: propname = boundary_prop[self.label] # Add the nodes X1, Y1 = self.begin.real, self.begin.imag X2, Y2 = self.end.real, self.end.imag femm.mi_addnode(X1, Y1) femm.mi_selectnode(X1, Y1) femm.mi_setnodeprop(nodeprop, group) femm.mi_clearselected() femm.mi_addnode(X2, Y2) femm.mi_selectnode(X2, Y2) femm.mi_setnodeprop(nodeprop, group) femm.mi_clearselected() # add the segment femm.mi_addsegment(X1, Y1, X2, Y2) # Set property femm.mi_selectsegment((X1 + X2) / 2, (Y1 + Y2) / 2) femm.mi_setsegmentprop(propname, elementsize, automesh, hide, group) femm.mi_clearselected()
def draw_FEMM( output, is_mmfr, is_mmfs, sym, is_antiper, type_calc_leakage, is_remove_vent=False, is_remove_slotS=False, is_remove_slotR=False, type_BH_stator=0, type_BH_rotor=0, kgeo_fineness=1, kmesh_fineness=1, user_FEMM_dict={}, path_save="FEMM_model.fem", is_sliding_band=True, transform_list=[], rotor_dxf=None, stator_dxf=None, ): """Draws and assigns the property of the machine in FEMM Parameters ---------- output : Output Output object is_mmfr : bool 1 to compute the rotor magnetomotive force / rotor magnetic field is_mmfs : bool 1 to compute the stator magnetomotive force/stator magnetic field type_calc_leakage : int 0 no leakage calculation 1 calculation using single slot is_remove_vent : bool True to remove the ventilation ducts in FEMM (Default value = False) is_remove_slotS : bool True to solve without slot effect on the Stator (Default value = False) is_remove_slotR : bool True to solve without slot effect on the Rotor (Default value = False) type_BH_stator: int 2 Infinite permeability, 1 to use linear B(H) curve according to mur_lin, 0 to use the B(H) curve type_BH_rotor: bool 2 Infinite permeability, 1 to use linear B(H) curve according to mur_lin, 0 to use the B(H) curve kgeo_fineness : float global coefficient to adjust geometry fineness in FEMM (1: default ; > 1: finner ; < 1: less fine) kmesh_fineness : float global coefficient to adjust mesh fineness in FEMM (1: default ; > 1: finner ; < 1: less fine) sym : int the symmetry applied on the stator and the rotor (take into account antiperiodicity) is_antiper: bool To apply antiperiodicity boundary conditions rotor_dxf : DXFImport To use a dxf version of the rotor instead of build_geometry stator_dxf : DXFImport To use a dxf version of the stator instead of build_geometry Returns ------- FEMM_dict : dict Dictionnary containing the main parameters of FEMM (including circuits and materials) """ # Initialization from output for readibility BHs = output.geo.stator.BH_curve # Stator B(H) curve BHr = output.geo.rotor.BH_curve # Rotor B(H) curve Is = output.elec.Is # Stator currents waveforms Ir = output.elec.Ir # Rotor currents waveforms machine = output.simu.machine # Computing parameter (element size, arcspan...) needed to define the simulation FEMM_dict = comp_FEMM_dict(machine, kgeo_fineness, kmesh_fineness, type_calc_leakage) FEMM_dict.update(user_FEMM_dict) # Overwrite some values if needed # The package must be initialized with the openfemm command. try: femm.openfemm() except Exception as e: raise FEMMError( "ERROR: Unable to open FEMM, please check that FEMM is correctly installed\n" + str(e)) # We need to create a new Magnetostatics document to work on. femm.newdocument(0) # Minimize the main window for faster geometry creation. femm.main_minimize() # defining the problem femm.mi_probdef(0, "meters", FEMM_dict["pbtype"], FEMM_dict["precision"]) # Modifiy the machine to match the conditions machine = type(machine)(init_dict=machine.as_dict()) if is_remove_slotR: # Remove all slots on the rotor lam_dict = machine.rotor.as_dict() machine.rotor = Lamination(init_dict=lam_dict) if is_remove_slotS: # Remove all slots on the stator lam_dict = machine.stator.as_dict() machine.stator = Lamination(init_dict=lam_dict) if is_remove_vent: # Remove all ventilations machine.rotor.axial_vent = list() machine.stator.axial_vent = list() # Building geometry of the (modified) stator and the rotor surf_list = list() lam_list = machine.get_lam_list() lam_int = lam_list[0] lam_ext = lam_list[1] # Adding no_mesh for shaft if needed if lam_int.Rint > 0 and sym == 1: surf_list.append( Circle(point_ref=0, radius=lam_int.Rint, label="No_mesh")) # adding the Airgap surface if is_sliding_band: surf_list.extend( get_sliding_band(sym=sym, lam_int=lam_int, lam_ext=lam_ext)) else: surf_list.extend(get_airgap_surface(lam_int=lam_int, lam_ext=lam_ext)) # adding Both laminations surfaces (or import from DXF) if rotor_dxf is not None: femm.mi_readdxf(rotor_dxf.file_path) surf_list.extend(rotor_dxf.get_surfaces()) else: surf_list.extend(machine.rotor.build_geometry(sym=sym)) if stator_dxf is not None: femm.mi_readdxf(stator_dxf.file_path) surf_list.extend(stator_dxf.get_surfaces()) else: surf_list.extend(machine.stator.build_geometry(sym=sym)) # Applying user defined modifications for transfrom in transform_list: for surf in surf_list: if transfrom["label"] in surf.label and transfrom[ "type"] == "rotate": surf.rotate(transfrom["value"]) elif transfrom["label"] in surf.label and transfrom[ "type"] == "translate": surf.translate(transfrom["value"]) # Creation of all the materials and circuit in FEMM prop_dict, materials, circuits = create_FEMM_materials( machine, surf_list, Is, Ir, BHs, BHr, is_mmfs, is_mmfr, type_BH_stator, type_BH_rotor, is_eddies, j_t0=0, ) create_FEMM_boundary_conditions(sym=sym, is_antiper=is_antiper) # Draw and assign all the surfaces of the machine for surf in surf_list: label = surf.label # Get the correct element size and group according to the label surf.draw_FEMM( nodeprop="None", maxseg=FEMM_dict["arcspan"], # max span of arc element in degrees propname="None", FEMM_dict=FEMM_dict, hide=False, ) assign_FEMM_surface(surf, prop_dict[label], FEMM_dict, machine.rotor, machine.stator) # Apply BC for DXF import if rotor_dxf is not None: for BC in rotor_dxf.BC_list: if BC[1] is True: # Select Arc femm.mi_selectarcsegment(BC[0].real, BC[0].imag) femm.mi_setarcsegmentprop(FEMM_dict["arcspan"], BC[2], False, None) else: # Select Line femm.mi_selectsegment(BC[0].real, BC[0].imag) femm.mi_setsegmentprop(BC[2], None, None, False, None) femm.mi_clearselected() femm.mi_zoomnatural() # Zoom out femm.mi_probdef( FEMM_dict["freqpb"], "meters", FEMM_dict["pbtype"], FEMM_dict["precision"], FEMM_dict["Lfemm"], FEMM_dict["minangle"], FEMM_dict["acsolver"], ) femm.smartmesh(FEMM_dict["smart_mesh"]) femm.mi_saveas(path_save) # Save # femm.mi_close() FEMM_dict["materials"] = materials FEMM_dict["circuits"] = circuits return FEMM_dict