Preprocess Permanent Magnet Synchronous Motor (PMSM) Data and Autogenerate Current Controller Calibration Tables
Use this script to preprocess PMSM data for use in model-based calibration (MBC) and autogenerate current controller calibration tables using the calibratepmsm function. This script produces the table object, MBCdata, for use in MBC. You can import the MBCdata object into MBC from the workspace or use the object with the calibratepmsm function to generate torque tables for a PMSM.
PMSM characterization data can come from a finite element analysis simulation or dynamometer testing.
Import Raw Data
Import the raw PMSM data from an Excel® file.
fileName =
"PMSM150kW.xlsx";Read the units if they are defined in the second row.
opts = detectImportOptions(fileName); if opts.DataRange=="A3" opts.VariableUnitsRange = "A2"; end
Read the column-oriented data from the Excel® file to a table.
rawData = readtable(fileName, opts);
Use Standard Names for Required Channels
Save the variable names recognized by the MBC app to the array standardNames. Next, save the variable names from the imported spreadsheet to the array actualNames. Then, replace the imported variable names with the standard variable names. Channel names are read from the top row of the spreadsheet.
standardNames = ["Id", "Iq", "Fluxd", "Fluxq", "Trq"]; actualNames =["I_d", "I_q", "Psi_d", "Psi_q", "Trq_msr"]; [ok,loc]=ismember(rawData.Properties.VariableNames,actualNames); rawData.Properties.VariableNames(loc(ok)) = standardNames(ok);
Visualize Raw Data
Visualize the flux linkages data with respect to the d-axis and q-axis currents.
stem3(rawData.Id,rawData.Iq,rawData.Fluxd,"LineStyle","none"); title("Flux d [Wb]"); xlabel("Id [A]");ylabel("Iq [A]");
![Figure contains an axes object. The axes object with title Flux d [Wb], xlabel Id [A], ylabel Iq [A] contains an object of type stem.](../../examples/mbc/win64/PMSMDataPreprocessingExample_01.png)
stem3(rawData.Id,rawData.Iq,rawData.Fluxq,"LineStyle","none"); title("Flux q [Wb]"); xlabel("Id [A]"); ylabel("Iq [A]");
![Figure contains an axes object. The axes object with title Flux q [Wb], xlabel Id [A], ylabel Iq [A] contains an object of type stem.](../../examples/mbc/win64/PMSMDataPreprocessingExample_02.png)
Visualize the torque data with respect to the d-axis and q-axis currents.
stem3(rawData.Id,rawData.Iq,rawData.Trq,"LineStyle","none"); title("Measured Torque [Nm]"); xlabel("Id [A]"); ylabel("Iq [A]");
![Figure contains an axes object. The axes object with title Measured Torque [Nm], xlabel Id [A], ylabel Iq [A] contains an object of type stem.](../../examples/mbc/win64/PMSMDataPreprocessingExample_03.png)
Define PMSM Specification
Specify the DC voltage Vdc, number of pole pairs pp, resistance Rs , phase peak current IsMax, and maximum modulation voltage VsMax to align with your PMSM specification.
You may need to run tests at different levels of Vdc.
Vdc =350; pp =
4; Rs =
0.0061; IsMax =
615; VsMax = Vdc*(2/pi);
Note that VsMax=Vdc*(2/pi) is the maximum fundamental voltage of an inverter drive, calculated by applying a 6-step inverter-controlled voltage to an AC motor and performing a fast fourier transform on the output 6-step waveform. If you apply SVPWM and stay in linear modulation, then VsMax = Vdc/sqrt(3).
Calculate Gridded Data for Id and Iq Axis Currents
Calculate gridded data, [IDgrid,IQgrid], using ndgrid to create a grid for Fluxd and Fluxq, bound by IsMax. The gridded data is used to create the torque contour plot in a later step.
idAxis = linspace(-IsMax,0,51); iqAxis = linspace(0,IsMax,51); [IDgrid,IQgrid] = ndgrid(idAxis,iqAxis);
Define the breakpoints in a cell array.
currentBreakpoints = {idAxis,iqAxis};Transform Raw Data to Cartesian Coordinate System
Use the fitlookupn function to transform the raw data to the Cartesian coordinates system for these parameters:
Flux Linkage,
LambdadFlux Linkage,
LambdaqTorque,
measuredTorque
For each transformation, use the breakpoints defined in the previous section, the current column data for id and iq, and the corresponding raw data for the parameter being transformed.
Transform Flux Linkages Data
Transform the flux linkages data and plot the results.
lambdad = fitlookupn(currentBreakpoints,[rawData.Id,rawData.Iq], ... rawData.Fluxd,ShowPlot=true); title("Flux d [Wb]"); xlabel("Id [A]"); ylabel("Iq [A]");
![Figure contains an axes object. The axes object with title Flux d [Wb], xlabel Id [A], ylabel Iq [A] contains 3 objects of type surface, line. One or more of the lines displays its values using only markers](../../examples/mbc/win64/PMSMDataPreprocessingExample_04.png)
lambdaq = fitlookupn(currentBreakpoints,[rawData.Id,rawData.Iq], ... rawData.Fluxq,ShowPlot=true); xlabel("Id [A]"); ylabel("Iq [A]"); title("Flux q [Wb]");
![Figure contains an axes object. The axes object with title Flux q [Wb], xlabel Id [A], ylabel Iq [A] contains 3 objects of type surface, line. One or more of the lines displays its values using only markers](../../examples/mbc/win64/PMSMDataPreprocessingExample_05.png)
Transform Torque Data
Calculate the generated torque from the raw flux and current data. Then, transform the calculated and measured torque data and plot the result.
Use a spline approximation of 1 for additional smoothness for the calculated torque and the measured torque.
calculatedTorque = ... -1.5*pp*(rawData.Id.*rawData.Fluxq - rawData.Iq.*rawData.Fluxd); calculatedTorqueGrid = fitlookupn(currentBreakpoints, ... [rawData.Id,rawData.Iq], calculatedTorque,1); measuredTorque = fitlookupn(currentBreakpoints,[rawData.Id,rawData.Iq], ... rawData.Trq,1);
Compare Measured and Calculated Torque
Compare the measured and calculated torque. Use a hot colormap (red) for the calculated torque surface.
surf(IDgrid,IQgrid,measuredTorque,"DisplayName","Measured Torque"); cdata = mbcgui.graph.makeCData(calculatedTorqueGrid); hold on surf(IDgrid,IQgrid,calculatedTorqueGrid,"CData",cdata, ... "DisplayName","Calculated Torque"); title("Torque Comparison [Nm]"); xlabel("Id [A]"); ylabel("Iq [A]"); hold off legend
![Figure contains an axes object. The axes object with title Torque Comparison [Nm], xlabel Id [A], ylabel Iq [A] contains 2 objects of type surface. These objects represent Measured Torque, Calculated Torque.](../../examples/mbc/win64/PMSMDataPreprocessingExample_06.png)
Plot Torque Error
Plot the difference in calculated torque and measured torque, resulting in the torque error.
surf(IDgrid,IQgrid,measuredTorque- calculatedTorqueGrid); title("Torque Error [Nm]"); xlabel("Id [A]"); ylabel("Iq [A]");
![Figure contains an axes object. The axes object with title Torque Error [Nm], xlabel Id [A], ylabel Iq [A] contains an object of type surface.](../../examples/mbc/win64/PMSMDataPreprocessingExample_07.png)
Define Operating Points
Specify the number of torque operating points numTorqueLevels and the low torque levels minTorqueLevels. The remaining torque levels are evenly spaced up to the maximum measured torque. Torque is specified in Nm.
numTorqueLevels =50; minTorqueLevels =
[1 3 6 10 15];
Downsample by a factor of 5.
downsampleFactor =
5;Specify minimum speed speedMin, maximum speed speedMax, and speed step size speedStep to define speed operating points. Speed does not need to be evenly spaced, but some steps in MBC are easier with evenly spaced speed operating points. Speed is specified in rpm.
Speed is a lookup table input. Match operating points to breakpoints.
speedMin =1000; speedMax =
10000; speedStep =
250; speed = speedMin:speedStep:speedMax;
Rearrange Data in Torque-Speed Operating Points
Introduce torque as an operating point in addition to speed by rearranging the data to have both torque and speed information.
Calculate Torque Contour Levels
Initialize the torque contours at the levels in minTorqueLevels. Then, evenly space the levels up to the maximum measured torque.
TrqMax = max(abs(measuredTorque),[],"all"); numPoints = numTorqueLevels-length(minTorqueLevels)+1; torqueLevels = ... [minTorqueLevels(1:end-1) linspace(minTorqueLevels(end),TrqMax,numPoints)];
Create and Plot Torque Contour
Create and plot torque contour using the contour function.
trqContour is a 2xN array containing sets of contour data for each contour level.
trqContour = contour(IDgrid,IQgrid,measuredTorque,torqueLevels, ... "ShowText","on"); title("Torque Contour [Nm]"); xlabel("Id [A]"); ylabel("Iq [A]");
![Figure contains an axes object. The axes object with title Torque Contour [Nm], xlabel Id [A], ylabel Iq [A] contains an object of type contour.](../../examples/mbc/win64/PMSMDataPreprocessingExample_08.png)
Rearrange Data by Torque Levels
For each torque level, extract the Trq, Id, and Iq values. Next, downsample data for the torque level. If you have a Signal Processing Toolbox™ license, use the downsample function to calculate dataDownsample. Then, expand each torque level to include all speeds, attaching every speed operating point to each (id, iq) on the torque contour.
start = 1; accumulatedData = []; while start < size(trqContour,2) % process each torque levels (the contour levels). % There may be some contour lines missing currentTorque = trqContour(1,start); % The number of points in the contour for this torque. ni = trqContour(2,start); stop = start + ni; % Extract [Trq, Id, Iq] for current torque level. torqueData = [repelem(currentTorque,ni) ; trqContour(:,start+1:stop)]'; % [Id, Iq] points for current torque iffalse dataDownsample = downsample(torqueData,downsampleFactor); else dataDownsample = torqueData(1:downsampleFactor:end,:); end if ( dataDownsample(end,2)~= torqueData(end,2) ) % Make sure we have the last point in contour torqueData = [dataDownsample;torqueData(end,:)]; else torqueData = dataDownsample; end ni = size(torqueData,1); % Repeat torque contours for each speed and accumulate data. % Make sure speed is a column vector [Trq, Id, Iq, n]. accumulatedData=[accumulatedData; ... repmat(torqueData,[length(speed),1]) repelem(speed(:),ni)]; % Start of next torque contour. start = stop+1; end
Create Table Object with Preprocessed Data
Store accumulatedData with the variables Trq, Id, Iq, and n to the table, MBCdata.
MBCdata = array2table(accumulatedData,VariableNames=["Trq","Id","Iq","n"]);
Calculate the derived quantities peak current MBCdata.Is, voltage MBCdata.Vs, resultant flux MBCdata.Flux, and maximum flux MBCdata.FluxMax.
Note that MBCData.FluxMax is derived from steady state voltage and torque equations.
MBCdata.Is = sqrt(MBCdata.Id.^2 + MBCdata.Iq.^2); % electrical speed [rad/s] we = 2*pi.*MBCdata.n.*pp./60; Fluxd = interpn(idAxis,iqAxis,lambdad,MBCdata.Id,MBCdata.Iq); Fluxq = interpn(idAxis,iqAxis,lambdaq,MBCdata.Id,MBCdata.Iq); Vd = Rs.*MBCdata.Id - we.*Fluxq; Vq = Rs.*MBCdata.Iq + we.*Fluxd; MBCdata.Vs = sqrt(Vd.^2 + Vq.^2); MBCdata.Flux = sqrt(Fluxd.^2 + Fluxq.^2); MBCdata.FluxMax = ... sqrt(VsMax^2 - MBCdata.Is.^2*Rs^2 - 4*Rs.*we.*MBCdata.Trq/(3*pp))./we;
Set the units for each of the variables in the MBCdata table object.
% Trq Id Iq n Is Vs Flux FluxMax MBCdata.Properties.VariableUnits = ["Nm","A","A","rpm","A","V","Wb","Wb"];
Generate Excel Data File for MBC
Check the check box if you want to write data to an Excel file.
Note that unit information will be lost.
iffalse writetable(MBCdata,"PMSM_MBCData.xlsx"); end
Generate Calibration
Automatically generate calibration using data for specified breakpoints using the calibratepmsm function. Run the function from the MATLAB® command line with the option Display=true to show progress and final results in the MBC apps. Note that you cannot use the option Display=true within a Live Script. Do not run this code if you want to manually calibrate the PMSM using the MBC apps.
breakPoints = {speed, [1 4:4:100]};
[optimalTables,results] = calibratepmsm(MBCdata,IsMax,VsMax, ...
TableType="speedtorquepercent",...
Breakpoints=breakPoints, ...
PlotResults=true);![Figure contains an axes object. The axes object with title Speed and Torque Contours, xlabel Id [A], ylabel Iq [A] contains 26 objects of type contour, line, text. One or more of the lines displays its values using only markers These objects represent Torque contours [Nm], Maximum Stator Current [A], Speed contours [rpm], MPTA, Optimization Results.](../../examples/mbc/win64/PMSMDataPreprocessingExample_09.png)
View Lookup Tables
Torque Envelope
Plot the maximum torque envelope using optimalTables.SpeedBreakpoints and optimalTables.TrqEnvelope.
figure plot(optimalTables.SpeedBreakpoints,optimalTables.TrqEnvelope); xlabel("Speed [rpm]"); ylabel("TrqEnvelope [Nm]"); title("Maximum Torque Envelope"); grid on
![Figure contains an axes object. The axes object with title Maximum Torque Envelope, xlabel Speed [rpm], ylabel TrqEnvelope [Nm] contains an object of type line.](../../examples/mbc/win64/PMSMDataPreprocessingExample_10.png)
Id Table
Plot the Id Table using optimalTables.TorquePercentBreakpoints, optimalTables.SpeedBreakpoints, and optimalTables.Id_Table.
surf(optimalTables.TorquePercentBreakpoints, ... optimalTables.SpeedBreakpoints,optimalTables.Id_Table); xlabel("Torque Percent [%]"); ylabel("Speed [rpm]"); zlabel("Id Table [A]"); title("Id Table");
![Figure contains an axes object. The axes object with title Id Table, xlabel Torque Percent [%], ylabel Speed [rpm] contains an object of type surface.](../../examples/mbc/win64/PMSMDataPreprocessingExample_11.png)
Iq Table
Plot the Iq Table using optimalTables.TorquePercentBreakpoints, optimalTables.SpeedBreakpoints, and optimalTables.Iq_Table.
surf(optimalTables.TorquePercentBreakpoints, ... optimalTables.SpeedBreakpoints,optimalTables.Iq_Table); xlabel("Torque Percent [%]"); ylabel("Speed [rpm]"); zlabel("Iq Table [A]"); title("Iq Table");
![Figure contains an axes object. The axes object with title Iq Table, xlabel Torque Percent [%], ylabel Speed [rpm] contains an object of type surface.](../../examples/mbc/win64/PMSMDataPreprocessingExample_12.png)











