9. Inductance/Saliency Analyzer

This analyzer enables the inductance evaluation of an electric machine after running 2D FEA simulations using JMAG.

9.1. Model Background

The inductance of a coil is the resistance to a change in the electric current flowing through it. The inductance of a coil within an electric machine can come from multiple sources, including its own electric current as well as the electric current flowing through other phases of the machine. Understanding the inductance characteristics of an electric machine leads to finding any saliency that an electric machine rotor may have. In some electric machines, such as reluctance or induction machines, saliency exists and aids in producing electromagnetic torque between the rotor and stator. This can be seen in the torque equation for a 3-phase machine:

\[\begin{split}T &= \frac{3p}{2}[\psi_\text{pm} I_\text{q} + (L_\text{d} - L_\text{q}) I_\text{d} I_\text{q}] \\\end{split}\]
    1. Vo-Duy, and M. C. Ta, Encyclopedia of Electrical and Electronic Power Engineering. Oxford: Elsevier, 2023.

where \(T\) is calculated based on the rotor pole pairs \(p\), any permanent magnet flux \(\psi_\text{pm}\), the d- and q-axis currents \(I_\text{d,q}\), and the d- and q-axis inductances \(L_\text{d,q}\). In this equation the first term \(\frac{3p}{2} \psi_\text{pm} I_\text{q}\) represents the torque based on the permanent magnet flux and the second term \(\frac{3p}{2} (L_\text{d} - L_\text{q}) I_\text{d} I_\text{q}\) represents the reluctance torque, which is generated by different d- and q-axis inductances.

The code is structured such that the inductance_analyzer contains the code for setting up and running the JMAG simulations based on 1) the machine inputs and conditions of the user and 2) the conditions required of the machine to be able to calculate the necessary parameters. In the case of this machine, DC excitement of the U-phase is required with both the V- and W-phases being open. The post-analyzer script post-processes the .csv file generated to take the self-inductance of the U-phase coil and mutual-inductance of the V-phase coil to calcualte \(L_\text{d}\) and \(L_\text{q}\). This is done using the following equations:

\[\begin{split}L_\text{d} &= L_\text{ls} + \frac{3}{2}(L_\text{0} - L_\text{g}) \\ L_\text{q} &= L_\text{ls} + \frac{3}{2}(L_\text{0} + L_\text{g}) \\\end{split}\]

where \(L_\text{ls}\) is the average value of the self leakage inductance, \(L_\text{0}\) is the inductance component caused by the air-gap magnetic field, and \(L_\text{g}\) is the the amplitude of self/mutual inductance variation due to saliency. More information and images depicting the relationships between these variables can be found using the reference at the conclusion of this paragraph. Together, both \(L_\text{d}\) and \(L_\text{q}\) can be used to find the saliency ratio, which is defined as:

\[\begin{split}\xi &= \frac{L_\text{d}}{L_\text{q}} \\\end{split}\]
    1. Qiu, and W. Wang, and J. Yang, and J. Jiang, and J. Yang, “Phase-Inductance-Based Position Estimation Method for Interior Permanent Magnet Synchronous Motors,” Energies 2017, 10, 2002.

This analyzer calculates \(L_\text{d}\), \(L_\text{q}\), and \(\xi\) using JMAG’s transient solver. It models a synchronous reluctance machine under synchronous operation. The following document will provide a description of the analyzer inputs and outputs:

9.2. Input from User

This analyzer is used in the same way as the SynR_JMAG_2D_FEA_Analyzer. The inputs and initialization are the exact same and are shown in the tables below:

MachineDesign Input

Arguments

Description

machine

object of type SynR_Machine describing a SynR design

operating_point

object of type SynR_Machine_Oper_Pt describing a SynR design operating point

SynR_induction_analyzer Initialization

Arguments

Description

configuration

object of type SynR_EM_Config describing time step, JMAG configurations, etc.

The example code initializing the machine design for the optimized SynR design provided in the example found in the SynR Design section of MACHINE DESIGNS is also identical, along with the example_SynR_machine file in the SynR_eval folder within the mach_eval_examples folder in the examples folder of eMach. This example code is used exactly the same, where the step within the SynR_evaluator file should be changed to the inductance_step, which is also contained in the aforementinoed folder. The objective of this file is to call the example machine (in this case the example_SynR_machine.py that was just created in the SynR_eval folder) and create a machine design object.

import os
import sys
from time import time as clock_time

os.chdir(os.path.dirname(__file__))

from eMach.mach_eval import (MachineEvaluator, MachineDesign)
from eMach.examples.mach_eval_examples.SynR_eval.inductance_step import inductance_step
from eMach.examples.mach_eval_examples.SynR_eval.example_SynR_machine import Example_SynR_Machine, Machine_Op_Pt

############################ Create Evaluator ########################
SynR_evaluator = MachineEvaluator(
    [
        inductance_step
    ]
)

design_variant = MachineDesign(Example_SynR_Machine, Machine_Op_Pt)

results = SynR_evaluator.evaluate(design_variant)

Example code defining the inductance step is provided below. This code defines the analyzer problem class (input to the analyzer), initializes the analyzer class with an explanation of the required configurations, and calls the post-analyzer class.

import os
import sys
import copy

from mach_eval import AnalysisStep, ProblemDefinition
from mach_eval.analyzers.electromagnetic.SynR import SynR_inductance_analyzer as SynR_inductance
from mach_eval.analyzers.electromagnetic.SynR.SynR_inductance_config import SynR_Inductance_Config
from examples.mach_eval_examples.SynR_eval.SynR_inductance_post_analyzer import SynR_Inductance_PostAnalyzer

############################ Define Inductance Step ###########################
class SynR_Inductance_ProblemDefinition(ProblemDefinition):
    """Converts a State into a problem"""

    def __init__(self):
        pass

    def get_problem(state):

        problem = SynR_inductance.SynR_Inductance_Problem(
            state.design.machine, state.design.settings)
        return problem

# initialize inductance analyzer class with FEA configuration
configuration = SynR_Inductance_Config(
    no_of_rev = 1,
    no_of_steps = 72,

    mesh_size=3, # mm
    mesh_size_rotor=1.5, # mm
    airgap_mesh_radial_div=4,
    airgap_mesh_circum_div=720,
    mesh_air_region_scale=1.05,

    only_table_results=False,
    csv_results=("FEMCoilFlux"),
    del_results_after_calc=False,
    run_folder=os.path.dirname(__file__) + "/run_data/",
    jmag_csv_folder=os.path.dirname(__file__) + "/run_data/jmag_csv/",

    max_nonlinear_iterations=50,
    multiple_cpus=True,
    num_cpus=4,
    jmag_scheduler=False,
    jmag_visible=True,
    scale_axial_length = True,
    jmag_version=None,
)

SynR_inductance_analysis = SynR_inductance.SynR_Inductance_Analyzer(configuration)

inductance_step = AnalysisStep(SynR_Inductance_ProblemDefinition, SynR_inductance_analysis, SynR_Inductance_PostAnalyzer)

9.3. Output to User

The SynR_inductance_analyzer returns a dictionary holding the results obtained from the transient analysis of the machine. The elements of this dictionary and their descriptions are provided below:

SynR_inductance_analyzer Output

Output

Description

Ld

Scalar value of d-axis inductance

Lq

Scalar value of q-axis inductance

saliency_ratio

Ratio between Ld and Lq

As mentioned, the post analyzer is necessary to extract and compute the analyzer’s computations and to interpret the results. The post analyzer contains the following code and lies also in the eMach\examples\mach_eval_examples\SynR_eval folder. The code contained in the post analyzer, in this case to find inductance quantities the saliency ratio, can be seen here:

import copy
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize

class SynR_Inductance_PostAnalyzer:

    def get_next_state(results, in_state):
        state_out = copy.deepcopy(in_state)

        ############################ Extract required info ###########################
        inductances = results["coil_inductances"]
        I_hat = results["current_peak"]

        ############################ post processing ###########################
        data = inductances.to_numpy() # change csv format to readable array

        t = data[:,0] # define x axis data as time
        Uu = data[:,1] # define y axis data as self inductance
        Uv = data[:,2] # define y axis data as mutual inductance

        # curve fit inductance values and calculate curve
        def fit_sin(t, y):
            fft_func = np.fft.fftfreq(len(t), (t[1]-t[0])) # define fft function with assumed uniform spacing
            fft_y = abs(np.fft.fft(y)) # carry out fft function for inductance values
            guess_freq = abs(fft_func[np.argmax(fft_y[1:])+1]) # excluding the zero frequency "peak", which can cause problematic fits
            guess_amp = np.std(y) # guess amplitude based on one standard deviation
            guess_offset = np.mean(y) # guess y offset based on average of magnitude
            guess = np.array([guess_amp, 2.*np.pi*guess_freq, 0, guess_offset]) # arrage in array

            # define sin function
            def sinfunc(t, A, w, p, c):
                return A * np.sin(w*t + p) + c

            popt, pcov = scipy.optimize.curve_fit(sinfunc, t, y, p0=guess) # calculate sin function fit
            A, w, p, c = popt # assign appropriate variables
            fitfunc = lambda t: A * np.sin(w*t + p) + c # define fit function for curve fit

            # define function used to calculate least square
            def sumfunc(x):
                return sum((sinfunc(t, x[0], x[1], x[2], x[3]) - y)**2)

            sUx = scipy.optimize.minimize(fun=sumfunc, x0=np.array([guess_amp, 2.*np.pi*guess_freq, 0, guess_offset])) # calculate matching curve fit values with minimum error
            return [{"amp": A, "omega": w, "phase": p, "offset": c, "fitfunc": fitfunc}, sUx]

        [Uu_fit, sUu] = fit_sin(t, Uu) # carry out calculations on self inductance
        [Uv_fit, sUv] = fit_sin(t, Uv) # carry out calculations on mutual inductance

        fig1, ax1 = plt.subplots()
        ax1.plot(t, Uu, "-k", label="y", linewidth=2)
        ax1.plot(t, Uu_fit["fitfunc"](t), "r-", label="y fit curve", linewidth=2)
        ax1.legend(loc="best")
        plt.savefig("temp1.svg")

        fig2, ax2 = plt.subplots()
        ax2.plot(t, Uv, "-k", label="y", linewidth=2)
        ax2.plot(t, Uv_fit["fitfunc"](t), "r-", label="y fit curve", linewidth=2)
        ax2.legend(loc="best")
        plt.savefig("temp2.svg")

        Lzero = -2*sUv.x[3]/I_hat; # calculate L0 based on equations in publication
        Lg = sUv.x[0]/I_hat # calculate Lg based on equations in publication
        Lls = (sUu.x[3] + 2*sUv.x[3])/I_hat # calculate Lls based on equations in publication
        Ld = Lls + 3/2*(Lzero - Lg) # calculate Ld based on equations in publication
        Lq = Lls + 3/2*(Lzero + Lg) # calculate Lq based on equations in publication
        saliency_ratio = Ld/Lq # calculate saliency ratio

        ############################ Output #################################
        post_processing = {}
        post_processing["Ld"] = Ld
        post_processing["Lq"] = Lq
        post_processing["saliency_ratio"] = saliency_ratio

        state_out.conditions.inductance = post_processing

        print("\n************************ INDUCTANCE RESULTS ************************")
        print("Ld = ", Ld, " H")
        print("Lq = ", Lq, " H")
        print("Saliency Ratio = ", saliency_ratio)
        print("*************************************************************************\n")

        return state_out

All example SynR evaluation scripts, including the one used for this analyzer, can be found in eMach\examples\mach_eval_examples\SynR_eval, where the post-analyzer script uses FEA results and calculates machine performance metrics, including torque density, power density, efficiency, and torque ripple. This analyzer can be run by simply running the SynR_evaluator file in the aforementioned folder using the inductance_step. This example should produce the following results:

SynR_inductance_analyzer Results

Result

Value

Unit

Ld

0.0144

H

Lq

0.004

H

saliency_ratio

3.56

It should be noted that the inductance values calculated will be dependent on the number of turns in the stator. The saliency ratio however will remain independent of this.