コード例 #1
0
ファイル: solve_FEMM.py プロジェクト: tmasochahub/pyleecan
def solve_FEMM(self, output, sym, FEMM_dict):

    # Loading parameters for readibility
    angle = output.mag.angle
    qs = output.simu.machine.stator.winding.qs  # Winding phase number
    Npcpp = output.simu.machine.stator.winding.Npcpp
    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

    # 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))
    Phi_wind_stator = zeros((Nt_tot, qs))

    # Compute the data for each time step
    for ii in range(Nt_tot):
        # Update rotor position and currents
        update_FEMM_simulation(
            output,
            FEMM_dict["materials"],
            FEMM_dict["circuits"],
            self.is_mmfs,
            self.is_mmfr,
            j_t0=ii,
        )
        # Run the computation
        femm.mi_analyze()
        femm.mi_loadsolution()
        # Get the flux result
        for jj in range(Na_tot):
            Br[ii, jj], Bt[ii, jj] = femm.mo_getgapb("bc_ag2",
                                                     angle[jj] * 180 / pi)
        # Compute the torque
        Tem[ii] = comp_FEMM_torque(FEMM_dict, sym=sym)
        # Phi_wind computation
        Phi_wind_stator[ii, :] = comp_FEMM_Phi_wind(qs,
                                                    Npcpp,
                                                    is_stator=True,
                                                    Lfemm=FEMM_dict["Lfemm"],
                                                    L1=L1,
                                                    sym=sym)

    # 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

    # Electromotive forces computation (update output)
    self.comp_emf()
コード例 #2
0
def solve_FEMM(self, femm, output, sym, FEMM_dict):

    L1 = output.simu.machine.stator.comp_length()
    Nt_tot = self.Nt_tot  # Number of time step

    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()

    # Compute the data for each time step
    for ii in range(Nt_tot):
        # Update rotor position and currents
        update_FEMM_simulation(
            femm=femm,
            output=output,
            materials=FEMM_dict["materials"],
            circuits=FEMM_dict["circuits"],
            is_mmfs=1,
            is_mmfr=1,
            j_t0=ii,
            is_sliding_band=self.is_sliding_band,
        )

        # Run the computation
        femm.mi_analyze()
        femm.mi_loadsolution()

        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(
                femm,
                qs,
                Npcpp,
                is_stator=True,
                Lfemm=FEMM_dict["Lfemm"],
                L1=L1,
                sym=sym,
            )

    return Phi_wind_stator
コード例 #3
0
    def computeL0(self):
        """Compute L0

        Compute the bare inductance of the coil without projectile.
        """
        self.deleteProjectile()
        femm.mi_refreshview()
        femm.mi_analyze()
        femm.mi_loadsolution()
        # print(femm.mo_getcircuitproperties("Bobine"))
        self.L0 = femm.mo_getcircuitproperties("Bobine")[2] / self._i0
        self.resistance = femm.mo_getcircuitproperties("Bobine")[1] / self._i0
        femm.mo_close()
        self.drawProjectile()
コード例 #4
0
    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)
コード例 #5
0
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)
コード例 #6
0
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
コード例 #7
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.
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"]
コード例 #8
0
femm.callfemm_noeval('smartmesh(0)')

# this is essential to reduce elements counts from >50000 to ~20000.
print('mi_smartmesh is off')

for i in range(id_solver, len(fem_file_list), number_of_instances):

    output_file_name = dir_run + fem_file_list[i][:-4]

    if not os.path.exists(output_file_name + '.ans'):
        tic = time()
        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
コード例 #9
0
z_start = mag_y_loc_o
z_end = 0
num_points = 25  # resolution of points inbetween z_start and z_end
dz = (z_end - z_start) / (num_points - 1)
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()
コード例 #10
0
    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
            }
コード例 #11
0
    def simulate(self):
        self.__updateDimensions()
        # open FEMM
        femm.openfemm()
        femm.main_maximize()

        # True Steady State
        # new Magnetostatics document

        femm.newdocument(0)

        # Define the problem type.  Magnetostatic; Units of mm; 2D planar;
        # Precision of 10^(-8) for the linear solver; a placeholder of 0 for
        # the depth dimension, and an angle constraint of 30 degrees
        femm.mi_probdef(0, 'millimeters', 'planar', 1.e-8, 0, 30)

        # Import Materials
        femm.mi_getmaterial('Air')
        femm.mi_getmaterial(self.magnetType)
        femm.mi_getmaterial(self.windingType)

        # Draw geometry
        # Coil
        for coil in range(0, self.numStators):
            corner = Vector(coil * (self.coilLength + self.coilBufferLength), 0)
            femm.mi_drawrectangle(corner.x, corner.y, corner.x + self.coilLength, corner.y + self.pcbThickness)
            femm.mi_addblocklabel(corner.x + self.coilLength / 2, corner.y + self.pcbThickness / 2)
            femm.mi_selectlabel(corner.x + self.coilLength / 2, corner.y + self.pcbThickness / 2)
            femm.mi_setblockprop(self.windingType, 1, 0, '<None>', 0, 0, self.numWindings)


        # # Upper Rotor
        for magnet in range(0, self.numPoles):
            corner = Vector(magnet * (self.magnetLength + self.magnetBufferLength), self.pcbThickness + self.airGap)
            femm.mi_drawrectangle(corner.x, corner.y, corner.x + self.magnetLength, corner.y + self.rotorThickness)
            femm.mi_addblocklabel(corner.x + self.magnetLength / 2, corner.y + self.rotorThickness / 2)
            femm.mi_selectlabel(corner.x + self.magnetLength / 2, corner.y + self.rotorThickness / 2)
            if magnet % 2 == 0:
                femm.mi_setblockprop(self.magnetType, 1, 0, '<None>', 90, 0, 0)
            else:
                femm.mi_setblockprop(self.magnetType, 1, 0, '<None>', -90, 0, 0)
            if magnet == int(self.numPoles / 2):
                self.testPoint = Vector(corner.x, 0 + self.pcbThickness / 2)

        # Lower Rotor
        for magnet in range(0, self.numPoles):
            corner = Vector(magnet * (self.magnetLength + self.magnetBufferLength), -self.airGap)
            femm.mi_drawrectangle(corner.x, corner.y, corner.x + self.magnetLength, corner.y - self.rotorThickness)
            femm.mi_addblocklabel(corner.x + self.magnetLength / 2, corner.y - self.rotorThickness / 2)
            femm.mi_selectlabel(corner.x + self.magnetLength / 2, corner.y - self.rotorThickness / 2)
            if magnet % 2 == 0:
                femm.mi_setblockprop(self.magnetType, 1, 0, '<None>', 90, 0, 0)
            else:
                femm.mi_setblockprop(self.magnetType, 1, 0, '<None>', -90, 0, 0)

        # Define an "open" boundary condition using the built-in function:
        # Add air block label outside machine
        femm.mi_makeABC()
        airLabel = Vector((self.numStators / 2) * (self.coilLength + self.coilBufferLength), 5 * (self.rotorThickness + self.airGap))
        femm.mi_addblocklabel(airLabel.x, airLabel.y)
        femm.mi_selectlabel(airLabel.x, airLabel.y)
        femm.mi_setblockprop('Air', 1, 0, '<None>', 0, 0, 0)

        # We have to give the geometry a name before we can analyze it.
        femm.mi_saveas('alternatorSim.fem')

        # Now,analyze the problem and load the solution when the analysis is finished
        femm.mi_analyze()
        femm.mi_loadsolution()

        # Now, the finished input geometry can be displayed.
        # femm.mo_zoom(self.testPoint.x - 2 * self.coilLength, self.testPoint.y - self.coilLength,
        #              self.testPoint.x + 2 * self.coilLength,
        #              self.testPoint.y + self.coilLength)
        # femm.mo_showdensityplot(1, 0, 1, 0, 'mag')

        self.fluxDensity = self.getFlux()
コード例 #12
0
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
コード例 #13
0
def analyze(flag=1):
    femm.mi_analyze(flag)
    femm.mi_loadsolution()
コード例 #14
0
    def simulation(self):
        """Simulation du système"""

        femm.mi_analyze()
        femm.mi_loadsolution()