Source code for pyleecan.Methods.Output.LUTdq.interp_Ploss_dqh

import numpy as np
import scipy.interpolate as scp_int

from ....Functions.Electrical.comp_loss_joule import comp_loss_joule


[docs]def interp_Ploss_dqh(self, Id, Iq, N0, exclude_models=[]): """Interpolate losses in function of Id and Iq and for given speed Meant to be used with SIPMSM/IPMSM machine with LossFEA (to have the correct loss models name) Parameters ---------- self : LUTdq a LUTdq object Id : float or ndarray current Id Iq : float or ndarray current Iq N0: float rotation speed [rpm] exclude_models: list of strings list of LossModel names to exclude from the interpolation Returns ---------- Ploss_dqh : float or ndarray interpolated losses function of dq currents (N_OP, 5) - 1st column : Joule losses - 2nd column : stator core losses - 3rd column : magnet losses - 4th column : rotor core losses - 5th column : proximity losses """ # Name of the losses model to interpolate (in order) name_list = ["joule", "stator core", "magnets", "rotor core", "proximity"] # Check that all the losses are available if self.output_list is None or len(self.output_list) == 0: raise Exception( "Error, interpolation requires output_list, check is_keep_all_output" ) out1 = self.output_list[0] for name in name_list: if name not in out1.loss.loss_dict.keys(): raise Exception( "Error " + name + " is missing in " + str(out1.loss.loss_dict.keys()) ) p = self.simu.machine.get_pole_pair_number() felec = N0 / 60 * p Ploss_dqh = np.zeros( (len(self.output_list), len(self.output_list[0].loss.loss_dict)) ) for ii, out in enumerate(self.output_list): for kk, loss_name in enumerate(name_list): loss = out.loss.loss_dict[loss_name] if loss.loss_model not in exclude_models: Ploss_dqh[ii, kk] = loss.get_loss_scalar(felec) # Get unique Id, Iq sorted in ascending order OP_matrix = self.get_OP_array("N0", "Id", "Iq") XId, jd = np.unique(OP_matrix[:, 1], return_inverse=True) XIq, jq = np.unique(OP_matrix[:, 2], return_inverse=True) nd, nq = XId.size, XIq.size Ploss_dqh_mat = np.zeros((nd, nq, 5)) # Perform 2D interpolation if nd * nq == OP_matrix.shape[0]: # sort flux linkage matrix and reshape to (nd, nq, 2) is_rect_interp = True for ii, (m, n) in enumerate(zip(jd, jq)): Ploss_dqh_mat[m, n, :] = Ploss_dqh[ii, :] elif nd + nq - 1 == OP_matrix.shape[0]: # Rebuild 2D grid from xId and xIq is_rect_interp = True # Find Id=Iq=0 i0 = self.get_index_open_circuit() Ploss_dqh_mag = Ploss_dqh[i0, :] for m, x in enumerate(XId): for n, y in enumerate(XIq): # Find indice of current Id value in OP_matrix ii = np.where(OP_matrix[:, 1] == x)[0] # Find indice of current Iq value in OP_matrix jj = np.where(OP_matrix[:, 2] == y)[0] # check if (Id, Iq) is in OP_matrix kk = np.intersect1d(ii, jj) if kk.size > 0: # take values directly from Phi_dqh_mean if (Id, Iq) is in OP_matrix Ploss_dqh_mat[m, n, :] = Ploss_dqh[kk, :] else: # Sum flux values for (Id, Iq): Phi_dq(Id, Iq) = Phi_dq(Id, 0) + Phi_dq(0, Iq) Ploss_dqh_mat[m, n, :] = ( Ploss_dqh[ii, :] + Ploss_dqh[jj, :] - Ploss_dqh_mag ) else: is_rect_interp = False if nd == 1: # 1D interpolation along q axis Ploss_dqh_interp = scp_int.interp1d(XIq, Ploss_dqh_mat, kind="linear", axis=1) elif nq == 1: # 1D interpolation along d axis Ploss_dqh_interp = scp_int.interp1d(XId, Ploss_dqh_mat, kind="linear", axis=0) elif is_rect_interp: # regular grid interpolation Ploss_dqh_interp = scp_int.RegularGridInterpolator( (XId, XIq), Ploss_dqh_mat, method="linear" ) else: # scattered interpolation # not working since LinearNDInterpolator is not of same class as RegularGridInterpolator Ploss_dqh_interp = scp_int.LinearNDInterpolator( (OP_matrix[:, 1], OP_matrix[:, 2]), Ploss_dqh ) # Interpolate losses function of dq currents if nd == 1: Ploss_dqh = np.squeeze(Ploss_dqh_interp(Iq)) elif nq == 1: Ploss_dqh = np.squeeze(Ploss_dqh_interp(Id)) else: if np.isscalar(Id) and np.isscalar(Iq): Ploss_dqh = Ploss_dqh_interp((Id, Iq))[:, None] else: Ploss_dqh = Ploss_dqh_interp((Id, Iq)) return Ploss_dqh