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:
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:
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:
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:
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 |
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:
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:
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.