def extract_magnetic_field_map(range_a, range_o, delta_abscissa, delta_ordinate): # todo: calculate the norm of b instead of transversal fetching # extract the transverse component of the magnetic flux of the solution loaded in femm (last '.ans' file created) # return the data as a 2D numpy array na = int((range_a[1] - range_a[0]) / delta_abscissa) + 1 # number of point on the abscissa axis no = int((range_o[1] - range_o[0]) / delta_ordinate) + 1 # number of point on the ordinate axis abscissa_axis = numpy.linspace(range_a[0], range_a[1], na) # abscissa coordinates of data ordinate_axis = numpy.linspace(range_o[0], range_o[1], no) # coordinates_list = [] b_list = [] for j in abscissa_axis: for q in ordinate_axis: # coordinates_list.append((j, q)) b_list.append( femm.mo_getb(j, q) [1]) # fetch the data in the femm solution for each data point b_map = numpy.asarray(b_list).reshape(na, no) return b_map
def calcul_pertes_fer(self): """Calcul des pertes fer de l'inductance""" FREQUENCE = 50 # Coefficients des pertes fer : # Pertes volumique = ALPHA*B**1.5*FREQUENCE**1.5+ # BETA*B**2*FREQUENCE+ # GAMMA*B**2*FREQUENCE**2 ALPHA = 1.1119e-4 BETA = 1.688e-4 GAMMA = 4.361e-4 # Mesure du Bx, By au milieu de la dent centrale b_x, b_y = femm.mo_getb(0, self.hauteur / 4) b_moy = np.sqrt(b_x**2 + b_y**2) pertes_fer_masse = (ALPHA * b_moy**1.5 * FREQUENCE**1.5 + BETA * b_moy**2 * FREQUENCE + GAMMA * b_moy**2 * FREQUENCE**2) pertes_fer = pertes_fer_masse * self.calcul_masse_fer() return pertes_fer
def getFluxRiemanSum(self): riemanSum = 0 interval = self.magnetLength / 200 for i in range(200): x = self.testPoint.x + interval * i pointFlux = femm.mo_getb(x, self.testPoint.y)[1] riemanSum += .001 * (interval * pointFlux) return abs(riemanSum)
def getFlux(self): flux = [] offsets = [] for i in range(200): offset = i * self.numPoles * self.unbufferedMagnetLength / 200 b = femm.mo_getb(offset, self.testPoint.y) flux.append(b[1]) offsets.append(offset) return max(flux)
def pertes_fer(self): """ Calcul des pertes fer de l'inductance """ FREQUENCE = 50 # (en Hz) # Mesure du Bx, By au milieu de la dent centrale b_x, b_y = femm.mo_getb(0, self.hauteur / 4) b_moy = np.sqrt(b_x**2 + b_y**2) # TODO : faire la moyenne de Bx et By sur tout le volume # plutôt que juste dans la dent ? return self._interp_pertes_fer(b_moy)
def solve_FEMM(self, output, sym, FEMM_dict): # Loading parameters for readibilitys angle = output.mag.angle L1 = output.simu.machine.stator.comp_length() Nt_tot = output.mag.Nt_tot # Number of time step Na_tot = output.mag.Na_tot # Number of angular step save_path = self.get_path_save(output) if (hasattr(output.simu.machine.stator, "winding") and output.simu.machine.stator.winding is not None): qs = output.simu.machine.stator.winding.qs # Winding phase number Npcpp = output.simu.machine.stator.winding.Npcpp Phi_wind_stator = zeros((Nt_tot, qs)) else: Phi_wind_stator = None # Create the mesh femm.mi_createmesh() # Initialize results matrix Br = zeros((Nt_tot, Na_tot)) Bt = zeros((Nt_tot, Na_tot)) Tem = zeros((Nt_tot, 1)) lam_int = output.simu.machine.get_lamination(True) lam_ext = output.simu.machine.get_lamination(False) Rgap_mec_int = lam_int.comp_radius_mec() Rgap_mec_ext = lam_ext.comp_radius_mec() if self.is_get_mesh or self.is_save_FEA: meshFEMM = [Mesh() for ii in range(Nt_tot)] solutionFEMM = [Solution() for ii in range(Nt_tot)] else: meshFEMM = [Mesh()] solutionFEMM = [Solution()] # Compute the data for each time step for ii in range(Nt_tot): # Update rotor position and currents update_FEMM_simulation( output=output, materials=FEMM_dict["materials"], circuits=FEMM_dict["circuits"], is_mmfs=self.is_mmfs, is_mmfr=self.is_mmfr, j_t0=ii, is_sliding_band=self.is_sliding_band, ) # try "previous solution" for speed up of FEMM calculation if self.is_sliding_band: try: base = basename(self.get_path_save_fem(output)) ans_file = splitext(base)[0] + ".ans" femm.mi_setprevious(ans_file, 0) except: pass # Run the computation femm.mi_analyze() femm.mi_loadsolution() # Get the flux result if self.is_sliding_band: for jj in range(Na_tot): Br[ii, jj], Bt[ii, jj] = femm.mo_getgapb("bc_ag2", angle[jj] * 180 / pi) else: Rag = (Rgap_mec_ext + Rgap_mec_int) / 2 for jj in range(Na_tot): B = femm.mo_getb(Rag * np.cos(angle[jj]), Rag * np.sin(angle[jj])) Br[ii, jj] = B[0] * np.cos(angle[jj]) + B[1] * np.sin(angle[jj]) Bt[ii, jj] = -B[0] * np.sin(angle[jj]) + B[1] * np.cos(angle[jj]) # Compute the torque Tem[ii] = comp_FEMM_torque(FEMM_dict, sym=sym) if (hasattr(output.simu.machine.stator, "winding") and output.simu.machine.stator.winding is not None): # Phi_wind computation Phi_wind_stator[ii, :] = comp_FEMM_Phi_wind( qs, Npcpp, is_stator=True, Lfemm=FEMM_dict["Lfemm"], L1=L1, sym=sym) # Load mesh data & solution if self.is_get_mesh or self.is_save_FEA: meshFEMM[ii], solutionFEMM[ii] = self.get_meshsolution( self.is_get_mesh, self.is_save_FEA, save_path, ii) # Shift to take into account stator position roll_id = int(self.angle_stator * Na_tot / (2 * pi)) Br = roll(Br, roll_id, axis=1) Bt = roll(Bt, roll_id, axis=1) # Store the results output.mag.Br = Br output.mag.Bt = Bt output.mag.Tem = Tem output.mag.Tem_av = mean(Tem) if output.mag.Tem_av != 0: output.mag.Tem_rip = abs( (np_max(Tem) - np_min(Tem)) / output.mag.Tem_av) output.mag.Phi_wind_stator = Phi_wind_stator output.mag.FEMM_dict = FEMM_dict if self.is_get_mesh: cond = (not self.is_sliding_band) or (Nt_tot == 1) output.mag.meshsolution = MeshSolution( name="FEMM_magnetic_mesh", mesh=meshFEMM, solution=solutionFEMM, is_same_mesh=cond, ) if self.is_save_FEA: save_path_fea = join(save_path, "MeshSolutionFEMM.json") output.mag.meshsolution.save(save_path_fea) if (hasattr(output.simu.machine.stator, "winding") and output.simu.machine.stator.winding is not None): # Electromotive forces computation (update output) self.comp_emf() else: output.mag.emf = None
femm.mi_clearselected() # Now, the finished input geometry can be displayed. femm.mi_zoomnatural() # We have to give the geometry a name before we can analyze it. femm.mi_saveas('coil.fem'); # Now,analyze the problem and load the solution when the analysis is finished femm.mi_analyze() femm.mi_loadsolution() # If we were interested in the flux density at specific positions, # we could inquire at specific points directly: b0=femm.mo_getb(0,0); print('Flux density at the center of the bar is %g T' % b0[1]); b1=femm.mo_getb(0,50); print('Flux density at r=0,z=50 is %g T' % b1[1]); # The program will report the terminal properties of the circuit: # current, voltage, and flux linkage vals = femm.mo_getcircuitproperties('icoil'); # [i, v, \[Phi]] = MOGetCircuitProperties["icoil"] # If we were interested in inductance, it could be obtained by # dividing flux linkage by current L = 1000*vals[2]/vals[0]; print('The self-inductance of the coil is %g mH' % L);
def write_Torque_and_B_data_to_file(str_rotor_position, rotation_operator): # call this after mi_analyze femm.mi_loadsolution() # Physical Amount on the Rotor femm.mo_groupselectblock(100) # rotor iron femm.mo_groupselectblock(101) # rotor bars Fx = femm.mo_blockintegral( 18) #-- 18 x (or r) part of steady-state weighted stress tensor force Fy = femm.mo_blockintegral( 19) #--19 y (or z) part of steady-state weighted stress tensor force torque = femm.mo_blockintegral( 22) #-- 22 = Steady-state weighted stress tensor torque femm.mo_clearblock() # write results to a data file (write to partial files to avoid compete between parallel instances) handle_torque.write("%s %g %g %g\n" % (str_rotor_position, torque, Fx, Fy)) # Field Amount of 1/4 model (this is valid if we presume the suspension two pole field is weak) number_of_elements = femm.mo_numelements() stator_Bx_data = [] stator_By_data = [] stator_Area_data = [] rotor_Bx_data = [] rotor_By_data = [] rotor_Area_data = [] # one_list = [] for id_element in range(1, number_of_elements + 1): _, _, _, x, y, area, group = femm.mo_getelement(id_element) if y > 0 and x > 0: if group == 10: # stator iron # 1. What we need for iron loss evaluation is the B waveform at a fixed point (x,y). # For example, (x,y) is the centeroid of element in stator tooth. Bx, By = femm.mo_getb(x, y) stator_Bx_data.append(Bx) stator_By_data.append(By) stator_Area_data.append(area) if group == 100: # rotor iron # 2. The element at (x,y) is no longer the same element from last rotor position. # To find the exact element from last rotor position, # we rotate the (x,y) forward as we rotate the model (rotor), get the B value there: (x,y)*rotation_operator, and correct the (Bx,By)/rotation_operator complex_new_xy = (x + 1j * y) * rotation_operator Bx, By = femm.mo_getb(complex_new_xy.real, complex_new_xy.imag) complex_new_BxBy = (Bx + 1j * By) * rotation_operator rotor_Bx_data.append(complex_new_BxBy.real) rotor_By_data.append(complex_new_BxBy.imag) rotor_Area_data.append(area) # one_list.append(sqrt(Bx**2 + By**2)) # one_list.append(area) # option 1 handle_stator_B_data.write(str_rotor_position + ',' + ','.join([ '%g,%g,%g' % (Bx, By, A) for Bx, By, A in zip(stator_Bx_data, stator_By_data, stator_Area_data) ]) + '\n') handle_rotor_B_data.write(str_rotor_position + ',' + ','.join([ '%g,%g,%g' % (Bx, By, A) for Bx, By, A in zip(rotor_Bx_data, rotor_By_data, rotor_Area_data) ]) + '\n') # option 2: one_list # handle_B_data.write(str_rotor_position + ',' + ','.join(['%g'%(B) for B in B_data ]) + ','.join(['%g'%(A) for A in Area_data ]) + '\n') # numpy is slower than open().write!!! # tic = time() # # savetxt(handle_B_data, c_[one_list]) # savetxt(handle_B_data, one_list) # toc = time() # print toc - tic, 's\n\n' femm.mo_close()
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 solve_FEMM(self, output, sym, FEMM_dict): # Loading parameters for readibility angle = output.mag.angle L1 = output.simu.machine.stator.comp_length() Nt_tot = output.mag.Nt_tot # Number of time step Na_tot = output.mag.Na_tot # Number of angular step save_path = self.get_path_save(output) if (hasattr(output.simu.machine.stator, "winding") and output.simu.machine.stator.winding is not None): qs = output.simu.machine.stator.winding.qs # Winding phase number Npcpp = output.simu.machine.stator.winding.Npcpp Phi_wind_stator = zeros((Nt_tot, qs)) else: Phi_wind_stator = None # Create the mesh femm.mi_createmesh() # Initialize results matrix Br = zeros((Nt_tot, Na_tot)) Bt = zeros((Nt_tot, Na_tot)) Tem = zeros((Nt_tot)) Rag = output.simu.machine.comp_Rgap_mec() # Compute the data for each time step for ii in range(Nt_tot): # Update rotor position and currents update_FEMM_simulation( output=output, materials=FEMM_dict["materials"], circuits=FEMM_dict["circuits"], is_mmfs=self.is_mmfs, is_mmfr=self.is_mmfr, j_t0=ii, is_sliding_band=self.is_sliding_band, ) # try "previous solution" for speed up of FEMM calculation if self.is_sliding_band: try: base = basename(self.get_path_save_fem(output)) ans_file = splitext(base)[0] + ".ans" femm.mi_setprevious(ans_file, 0) except: pass # Run the computation femm.mi_analyze() femm.mi_loadsolution() # Get the flux result if self.is_sliding_band: for jj in range(Na_tot): Br[ii, jj], Bt[ii, jj] = femm.mo_getgapb("bc_ag2", angle[jj] * 180 / pi) else: for jj in range(Na_tot): B = femm.mo_getb(Rag * np.cos(angle[jj]), Rag * np.sin(angle[jj])) Br[ii, jj] = B[0] * np.cos(angle[jj]) + B[1] * np.sin(angle[jj]) Bt[ii, jj] = -B[0] * np.sin(angle[jj]) + B[1] * np.cos(angle[jj]) # Compute the torque Tem[ii] = comp_FEMM_torque(FEMM_dict, sym=sym) if (hasattr(output.simu.machine.stator, "winding") and output.simu.machine.stator.winding is not None): # Phi_wind computation Phi_wind_stator[ii, :] = comp_FEMM_Phi_wind( qs, Npcpp, is_stator=True, Lfemm=FEMM_dict["Lfemm"], L1=L1, sym=sym) # Load mesh data & solution if (self.is_sliding_band or Nt_tot == 1) and (self.is_get_mesh or self.is_save_FEA): tmpmeshFEMM, tmpB, tmpH, tmpmu, tmpgroups = self.get_meshsolution( save_path, ii) if ii == 0: meshFEMM = [tmpmeshFEMM] groups = [tmpgroups] B = np.zeros( [Nt_tot, meshFEMM[ii].cell["triangle"].nb_cell, 3]) H = np.zeros( [Nt_tot, meshFEMM[ii].cell["triangle"].nb_cell, 3]) mu = np.zeros([Nt_tot, meshFEMM[ii].cell["triangle"].nb_cell]) B[ii, :, 0:2] = tmpB H[ii, :, 0:2] = tmpH mu[ii, :] = tmpmu # Shift to take into account stator position roll_id = int(self.angle_stator * Na_tot / (2 * pi)) Br = roll(Br, roll_id, axis=1) Bt = roll(Bt, roll_id, axis=1) # Store the results Time = DataLinspace( name="time", unit="s", symmetries={}, initial=output.mag.time[0], final=output.mag.time[-1], number=Nt_tot, include_endpoint=True, ) Angle = DataLinspace( name="angle", unit="rad", symmetries={}, initial=angle[0], final=angle[-1], number=Na_tot, include_endpoint=True, ) Br_data = DataTime( name="Airgap radial flux density", unit="T", symbol="B_r", axes=[Time, Angle], values=Br, ) Bt_data = DataTime( name="Airgap tangential flux density", unit="T", symbol="B_t", axes=[Time, Angle], values=Bt, ) output.mag.B = VectorField( name="Airgap flux density", symbol="B", components={ "radial": Br_data, "tangential": Bt_data }, ) output.mag.Tem = DataTime( name="Electromagnetic torque", unit="Nm", symbol="T_{em}", axes=[Time], values=Tem, ) output.mag.Tem_av = mean(Tem) output.mag.Tem_rip_pp = abs(np_max(Tem) - np_min(Tem)) # [N.m] if output.mag.Tem_av != 0: output.mag.Tem_rip_norm = output.mag.Tem_rip_pp / output.mag.Tem_av # [] else: output.mag.Tem_rip_norm = None output.mag.Phi_wind_stator = Phi_wind_stator output.mag.FEMM_dict = FEMM_dict if self.is_get_mesh: output.mag.meshsolution = self.build_meshsolution( Nt_tot, meshFEMM, Time, B, H, mu, groups) if self.is_save_FEA: save_path_fea = join(save_path, "MeshSolutionFEMM.h5") output.mag.meshsolution.save(save_path_fea) if (hasattr(output.simu.machine.stator, "winding") and output.simu.machine.stator.winding is not None): # Electromotive forces computation (update output) self.comp_emf() else: output.mag.emf = None
b = np.zeros( [ns, nn], dtype=np.complex64) # matrix that will hold the flux density info # Store element flux densities B and magnetic potential A for m in range(nn): if g[m] == GroupSummary[ 'magnet']: # Element is in a rotor magnet, marked with group numbers 11 and higher # Store vector potential at the element centroid for elements that are in PMs A[index, m] = femm.mo_geta(float(np.real(z[m])), float(np.imag(z[m]))) elif g[m] == GroupSummary['stator_iron_core'] \ or g[m] == GroupSummary['rotor_iron_core'] \ or g[m] == GroupSummary['coils']: # Element is on the stator or rotor iron or coils # Store flux density at the element centroid for these elements b_temp = femm.mo_getb(float(np.real(z[m])), float(np.imag(z[m]))) b[index, m] = b_temp[0] + 1j * b_temp[1] # Torque, force, fluxes torque = femm.mo_gapintegral('WholeModelSlidingBand', 0) forces = femm.mo_gapintegral('WholeModelSlidingBand', 1) energy = femm.mo_gapintegral('WholeModelSlidingBand', 2) cP_Uac = femm.mo_getcircuitproperties('U-GrpAC') cP_Vac = femm.mo_getcircuitproperties('V-GrpAC') cP_Wac = femm.mo_getcircuitproperties('W-GrpAC') cP_Ubd = femm.mo_getcircuitproperties('U-GrpBD') cP_Vbd = femm.mo_getcircuitproperties('V-GrpBD') cP_Wbd = femm.mo_getcircuitproperties('W-GrpBD') M[index, 0] = torque M[index, 1] = forces[0]
femm.mi_setblockprop('Air', 0, 1, '<None>', 0, 0, 0) femm.mi_clearselected() # Now, the finished input geometry can be displayed. femm.mi_zoomnatural() # We have to give the geometry a name before we can analyze it. femm.mi_saveas('coil.fem') # Now,analyze the problem and load the solution when the analysis is finished femm.mi_analyze() femm.mi_loadsolution() # If we were interested in the flux density at specific positions, # we could inquire at specific points directly: b0 = femm.mo_getb(0, 0) print('Flux density at the center of the bar is %g T' % b0[1]) b1 = femm.mo_getb(0, 50) print('Flux density at r=0,z=50 is %g T' % b1[1]) # Or we could, for example, plot the results along a line using zee = [] bee = [] for n in range(-100, 101): 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')