def main(): n_pontos = 40 polos = 7 deg_mec = np.linspace(0, 360, n_pontos) deg_ele = deg_mec / polos a_flux = np.zeros(n_pontos) b_flux = np.zeros(n_pontos) c_flux = np.zeros(n_pontos) print(a_flux) for i in range(n_pontos): femm.mi_modifyboundprop("Sliding", 11, deg_ele[i]) femm.mi_analyse() femm.mi_loadsolution() a_flux[i] = femm.mo_getcircuitproperties("A")[2] b_flux[i] = femm.mo_getcircuitproperties("A")[2] c_flux[i] = femm.mo_getcircuitproperties("A")[2] flux_1n = np.zeros(n_pontos) for i in range(n_pontos): femm.mi_modifyboundprop("Sliding", 11, deg_ele[i]) femm.mi_analyse() femm.mi_loadsolution() femm.mo_selectblock(1.5, 8.6) flux_1n[i] = femm.mo_blockintegral(1) / femm.mo_blockintegral(5) femm.mo_clearblock() ap = 10e-3 * (10.86 + 10.96) * 1e-3 * np.pi / 14 bt = flux_1n / ap / 4
def calcul_energie(self): """Calcul de l'energie dans l'entrefer et le fer""" femm.mo_selectblock(0, 0) # On selectionne l'entrefer femm.mo_selectblock(0, self.hauteur / 2 - self.l_dent / 4) # On selectionne le fer energie = femm.mo_blockintegral(2) * self.l_active femm.mo_clearblock() return energie
def energie_stockee(self): """Calcul de l'energie dans l'entrefer et le fer""" femm.mo_selectblock(0, 0) # On selectionne l'entrefer femm.mo_selectblock(0, self.hauteur / 4) # On selectionne le fer energie = femm.mo_blockintegral( 2) * self.l_active # 2 : Magnetic field energy femm.mo_clearblock() return energie
def comp_FEMM_torque(FEMM_dict, sym=1): """Compute the torque of the current FEMM simulation result """ # Select rotor groups mo_seteditmode("area") mo_groupselectblock(FEMM_dict["groups"]["GROUP_RC"]) mo_groupselectblock(FEMM_dict["groups"]["GROUP_RH"]) mo_groupselectblock(FEMM_dict["groups"]["GROUP_RW"]) # sym = 2 => Only half the machine return sym * mo_blockintegral(22)
def get_slipfreq_torque(): # 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 freq = femm.mo_getprobleminfo()[1] femm.mo_clearblock() femm.mo_close() return freq, torque
def computedLz(self, ite=0, rType="linear"): """Compute dLz Compute the variation of inductance while the projectile moves on the axis. If ite is zero, some guess is made about the number of iterations required for decent approximation. By default the projectile is moved linearly, but it is possible to set the movement type to tchebychev in order to minimize the Runge phenomenom. However not all the code is compatible with it. Rather than computing the variation of inductance, we compute the force on the projectile and correct it (explanations are available somewhere on this git :) ). Keyword Arguments: ite {number} -- number of steps (default: {0}) rType {str} -- type of movement, linear or tchebychev (default: {"linear"}) """ self.deleteProjectile() self.drawProjectile() (pas, pos, ite) = self._compute_range(ite, rType) force = numpy.zeros(ite) femm.mi_selectgroup(1) femm.mi_movetranslate2(0, pos[0], 4) for i in tqdm(range(ite // 2), disable=self.bHide): femm.mi_analyze() femm.mi_loadsolution() femm.mo_groupselectblock(1) force[i] = femm.mo_blockintegral(19) force[ite - i - 1] = -force[i] femm.mi_selectgroup(1) femm.mi_movetranslate2(0, pas[i], 4) self.dLz = 2 * force / self._i0**2 self.dLz_z = pos * 10**-3 self.dLz_nyquist = 1 / (2 * numpy.mean(pas) * 10**-3)
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)
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.opendocument(output_file_name + '.fem') # femm.callfemm_noeval('mi_smartmesh(0)') try: # femm.mi_createmesh() # [useless] femm.mi_analyze(1) # None for inherited. 1 for a minimized window, # print '[debug]', deg_per_step*i*number_of_instances, 'deg' # rotor_position = deg_per_step*i*number_of_instances / 180. * pi # write_Torque_and_B_data_to_file(output_file_name[-4:], exp(1j*rotor_position)) # this function is moved to FEMM_Solver.py as keep... if True: # 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" % (output_file_name[-4:], torque, Fx, Fy)) # output_file_name[-4:] = str_rotor_position # close post-process femm.mo_close() except Exception as error:
z = np.linspace(z_start, z_end, num_points) fz = [] # START OF MOTION counter = 0 # Initialize a counter because I was too lazy to get the index in the for loop for z_loc in z: mag_y_loc = z_loc # Only start after the initial position has been used. if (counter > 0): femm.mi_movetranslate(0, dz) femm.mi_analyze(0) femm.mi_loadsolution() femm.mi_selectgroup(3) femm.mo_selectblock(0, mag_y_loc) fz.append(femm.mo_blockintegral(21) * 2) counter = counter + 1 # END OF MOTION # POST-PROCESSING femm.mi_saveas("final.fem") # Save the final simulation step max_loc = fz.index(max(fz)) # Find the location of maximum force plt.figure(1) plt.plot(z - z[max_loc], fz) plt.show() plt.xlabel('z (in)') plt.ylabel('F [N]') # Save plot data to text file
import femm import matplotlib.pyplot as plt femm.openfemm() femm.opendocument("coilgun.fem") femm.mi_saveas("temp.fem") femm.mi_seteditmode("group") z = [] f = [] for n in range(0, 16): femm.mi_analyze() femm.mi_loadsolution() femm.mo_groupselectblock(1) fz = femm.mo_blockintegral(19) z.append(n * 0.1) f.append(fz) femm.mi_selectgroup(1) femm.mi_movetranslate(0, -0.1) femm.closefemm() plt.plot(z, f) plt.ylabel('Force, N') plt.xlabel('Offset, in') plt.show()
for coil_origin in coil_origins: coil = Rectangle(coil_origin.x, coil_origin.y, Params.D4, Params.D3) coil.assign_material(Params.CoilMaterial, Params.Turns, 'Circuit') # 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('feladat2.fem') move_vectors = [Point(0, 0)] # do it once without moving for previous, current in zip(Params.core_gap, Params.core_gap[1:]): move_vectors.append(Point(0, previous - current)) forces = {} for core_gap, move_vector in zip(Params.core_gap, move_vectors): bottom_part.move(move_vector.x, move_vector.y) femm.mi_analyze() femm.mi_loadsolution() bottom_part.select_block_for_anal() forces[core_gap] = femm.mo_blockintegral(19) # 19 means force (current, voltage, flux_linkage) = femm.mo_getcircuitproperties('Circuit') inductance = flux_linkage / current print( f'In case of {core_gap:.1f} cm gap, force is {forces[core_gap]:.2f} N; inductance is {inductance*1000:.2f} mH' ) femm.closefemm()
def postGetTorque(group): femm.mo_groupselectblock(group) T = femm.mo_blockintegral(22) femm.mo_clearblock() return T