Skip to content

Commit 290bd4b

Browse files
author
agonzale
committed
fix: improved robustness for multi-cooling system configurations including spray cooling
1 parent abd4414 commit 290bd4b

File tree

6 files changed

+91
-39
lines changed

6 files changed

+91
-39
lines changed

GenerateSimulinkThermalModel.mlx

139 KB
Binary file not shown.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ The license is available in the License file within this repository.
6666
## Community Support
6767
[MATLAB Central](https://www.mathworks.com/matlabcentral)
6868

69-
Copyright 2022-2024 The MathWorks, Inc.
69+
Copyright 2022-2025 The MathWorks, Inc.

ValidateSimulinkThermalModel.mlx

791 KB
Binary file not shown.

interface/+mcadinterface/ThermalInterface.m

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ function updateLabLossTables(obj)
887887

888888
obj.turnOffLossDependenceWithTemperatureOrSpeed();
889889

890-
% 1) COMPUTE ROM DATA
890+
% 1) COMPUTE ROM DATA ---------------------------------------
891891

892892
% Enable the cooling systems and get the flowrate and inlet
893893
% temperature property names.
@@ -912,6 +912,7 @@ function updateLabLossTables(obj)
912912
end
913913
end
914914
obj.updateModel();
915+
AdjacencyMat = obj.AdjacencyMat;
915916

916917
% Get ambient temperature and initial node temperatures
917918
Tambient_degC = obj.Tambient_degC;
@@ -942,18 +943,47 @@ function updateLabLossTables(obj)
942943
samplingGridStruct = getSamplingGridFromBkpts(BkptsStruct);
943944
StateSpaceND.SamplingGrid = samplingGridStruct;
944945

945-
% Get coolant data
946-
AdjacencyMat = obj.AdjacencyMat;
946+
% Build inlet/outlet index rows that match coolingSystemsEnabled one-to-one
947+
numCoolSys = numel(coolingSystemsEnabled);
948+
inletCells = cell(1,numCoolSys);
949+
outletCells = cell(1,numCoolSys);
950+
for kSys = 1:numCoolSys
951+
csName = coolingSystemsEnabled{kSys};
952+
% identify which rows in the object belong to csName
953+
if any(startsWith(obj.MultiNozzleSprayCoolingSystems, string(csName))) % is multi-nozzle spray cooling (front and rear)
954+
% Multi-nozzle aggregate: collect all spray rows
955+
rowMask = ismember(obj.CoolingSystemNamesAndMcadIdxes(:,1), ...
956+
obj.MultiNozzleSprayCoolingSystems);
957+
else
958+
% Normal case: exact match
959+
rowMask = strcmp(obj.CoolingSystemNamesAndMcadIdxes(:,1), csName);
960+
end
961+
rows = find(rowMask);
962+
if isempty(rows)
963+
error(['Cooling system "%s" is not enabled in Motor-CAD (or its ' ...
964+
'name does not match SupportedCoolingSystemsMcadNames).'], csName);
965+
end
966+
% concatenate indices from all matching rows
967+
inIdx = [];
968+
outIdx = [];
969+
for r = rows(:)'
970+
inIdx = [inIdx obj.InletArrayIdxs{r}]; %#ok<AGROW>
971+
tmpOut = obj.OutletArrayIdxs{r};
972+
if isempty(tmpOut) % per-element fallback
973+
tmpOut = obj.InletArrayIdxs{r};
974+
end
975+
outIdx = [outIdx tmpOut]; %#ok<AGROW>
976+
end
977+
inletCells{kSys} = inIdx;
978+
outletCells{kSys} = outIdx;
979+
end
980+
obj.InletArrayIdxs = inletCells;
981+
obj.OutletArrayIdxs = outletCells;
982+
947983
% Simulink does not accept cell arrays as parameters, need to
948984
% transform them to arrays:
949985
InletCoolIdxs = adaptInletOutletArrays(obj.InletArrayIdxs);
950986
OutletCoolIdxs = adaptInletOutletArrays(obj.OutletArrayIdxs);
951-
% Some cooling systems (multinozzle spray) have no outlet node in Motor-CAD.
952-
if isempty(OutletCoolIdxs)
953-
% FixMe: temporary workaround, assume outlet=inlet (no heat transfer)
954-
OutletCoolIdxs = InletCoolIdxs;
955-
% TO DO: estimate outlet coolant temperature from the heat transfer
956-
end
957987

958988
% Calculate state-space model at each breakpoint -------
959989
idxsCell = getNestedForLoopIdxs(sizeMatND(1:end-2));
@@ -1036,7 +1066,8 @@ function updateLabLossTables(obj)
10361066
xCoolantArrayIdxs = obj.CoolantArrayIdxs;
10371067
xCapMat = obj.CapMat;
10381068

1039-
% 2) GENERATE SIMULINK MODEL
1069+
% 2) GENERATE SIMULINK MODEL ---------------------------------
1070+
10401071
disp("Creating Simulink model...")
10411072
% create and open the model
10421073
open_system(new_system(modelName));
817 KB
Binary file not shown.

utils/compareSimulinkAndMcadAtBkpt.m

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,23 @@
1616
% is the SROTM node temperatures and Tmcad is the Motor-CAD node
1717
% temperature, in the transient simulation.
1818

19-
% Copyright 2022 The MathWorks, Inc.
19+
% Copyright 2022-2025 The MathWorks, Inc.
2020

2121
mdlWks = get_param(modelName,'ModelWorkspace');
2222
StateSpaceND = mdlWks.getVariable('StateSpaceND');
2323
samplingGrid = StateSpaceND.SamplingGrid;
2424

25-
if length(bkptIdxComb)==3 % one cooling system
25+
% Obtain Simulink results ------------------------------------------
26+
if length(bkptIdxComb)==3 % one cooling system - e5_IM_HWJ case
2627
wBkpts = squeeze(samplingGrid.w(:,1,1))';
2728
fr1Bkpts = squeeze(samplingGrid.fr1(1,:,1));
2829
Tin1Bkpts = squeeze(samplingGrid.Tin1(1,1,:))';
2930
rpmVal = wBkpts(bkptIdxComb(1));
3031
fr1Val = fr1Bkpts(bkptIdxComb(2));
31-
Tin1Val = Tin1Bkpts(bkptIdxComb(3));
32-
elseif length(bkptIdxComb)==5 % two cooling systems
32+
Tin1Val = Tin1Bkpts(bkptIdxComb(3));
33+
set_param(strcat(modelName, '/HousingWaterJacket_Flowrate_lpm'), 'Value', num2str(fr1Val));
34+
set_param(strcat(modelName, '/HousingWaterJacket_InletTemp_degC'), 'Value', num2str(Tin1Val));
35+
elseif length(bkptIdxComb)==5 % two cooling systems - e8_IPMSM_HWJandVent case
3336
wBkpts = squeeze(samplingGrid.w(:,1,1,1,1))';
3437
fr1Bkpts = squeeze(samplingGrid.fr1(1,:,1,1,1));
3538
fr2Bkpts = squeeze(samplingGrid.fr2(1,1,:,1,1))';
@@ -40,46 +43,63 @@
4043
fr2Val = fr2Bkpts(bkptIdxComb(3));
4144
Tin1Val = Tin1Bkpts(bkptIdxComb(4));
4245
Tin2Val = Tin2Bkpts(bkptIdxComb(5));
43-
end
44-
45-
set_param(strcat(modelName, '/TorqueNm'), 'Value', num2str(torqueVal));
46-
set_param(strcat(modelName, '/SpeedRPM'), 'Value', num2str(rpmVal));
47-
% set HWJ for e8 model
48-
try
4946
set_param(strcat(modelName, '/HousingWaterJacket_Flowrate_lpm'), 'Value', num2str(fr1Val));
5047
set_param(strcat(modelName, '/HousingWaterJacket_InletTemp_degC'), 'Value', num2str(Tin1Val));
51-
catch
52-
% just continue
53-
end
54-
% set spray cooling for e8 model
55-
try
48+
set_param(strcat(modelName, '/Ventilated_Flowrate_lpm'), 'Value', num2str(fr2Val));
49+
set_param(strcat(modelName, '/Ventilated_InletTemp_degC'), 'Value', num2str(Tin2Val));
50+
elseif length(bkptIdxComb)==7 % three cooling systems - e8_IPMSM_SprayMultiNozzle case
51+
wBkpts = squeeze(samplingGrid.w(:,1,1,1,1,1,1))';
52+
fr1Bkpts = squeeze(samplingGrid.fr1(1,:,1,1,1,1,1));
53+
Tin1Bkpts = squeeze(samplingGrid.Tin1(1,1,:,1,1,1,1))';
54+
fr2Bkpts = squeeze(samplingGrid.fr2(1,1,1,:,1,1,1))';
55+
Tin2Bkpts = squeeze(samplingGrid.Tin2(1,1,1,1,:,1,1))';
56+
fr3Bkpts = squeeze(samplingGrid.fr3(1,1,1,1,1,:,1))';
57+
Tin3Bkpts = squeeze(samplingGrid.Tin3(1,1,1,1,1,1,:))';
58+
rpmVal = wBkpts(bkptIdxComb(1));
59+
fr1Val = fr1Bkpts(bkptIdxComb(2));
60+
fr2Val = fr2Bkpts(bkptIdxComb(3));
61+
fr3Val = fr3Bkpts(bkptIdxComb(4));
62+
Tin1Val = Tin1Bkpts(bkptIdxComb(5));
63+
Tin2Val = Tin2Bkpts(bkptIdxComb(6));
64+
Tin3Val = Tin3Bkpts(bkptIdxComb(7));
5665
set_param(strcat(modelName, '/Spray_RadialHousing_Flowrate_lpm'), 'Value', num2str(fr1Val));
5766
set_param(strcat(modelName, '/Spray_RadialHousing_InletTemp_degC'), 'Value', num2str(Tin1Val));
58-
catch
59-
% just continue
67+
set_param(strcat(modelName, '/HousingWaterJacket_Flowrate_lpm'), 'Value', num2str(fr2Val));
68+
set_param(strcat(modelName, '/HousingWaterJacket_InletTemp_degC'), 'Value', num2str(Tin2Val));
69+
set_param(strcat(modelName, '/Spray_RadialRotor_Flowrate_lpm'), 'Value', num2str(fr3Val));
70+
set_param(strcat(modelName, '/Spray_RadialRotor_InletTemp_degC'), 'Value', num2str(Tin3Val));
6071
end
6172

62-
if length(bkptIdxComb)==5
63-
set_param(strcat(modelName, '/Ventilated_Flowrate_lpm'), 'Value', num2str(fr2Val));
64-
set_param(strcat(modelName, '/Ventilated_InletTemp_degC'), 'Value', num2str(Tin2Val));
65-
end
73+
set_param(strcat(modelName, '/TorqueNm'), 'Value', num2str(torqueVal));
74+
set_param(strcat(modelName, '/SpeedRPM'), 'Value', num2str(rpmVal));
6675

6776
stopTime = 1000; % s
6877
out = sim(modelName, 'StopTime', num2str(stopTime));
6978
TnodesSeries = out.yout{1}.Values;
70-
7179
TnodesInit = mdlWks.getVariable('TnodesInit');
80+
81+
% Obtain Motor-CAD baseline ------------------------------------------
7282
mcadIntf.Tambient_degC = TnodesInit(1);
7383
mcadIntf.Shaft_Speed_RPM = rpmVal;
74-
mcadIntf.HousingWaterJacket_FlowRate_m3ps = fr1Val/60/1000; % lpm to m3ps
75-
mcadIntf.HousingWaterJacket_InletTemperature_degC = Tin1Val;
76-
mcadIntf.Spray_RadialHousing_FlowRate_m3ps = fr1Val/60/1000; % lpm to m3ps
77-
mcadIntf.Spray_RadialHousing_InletTemperature_F_degC = Tin1Val;
78-
mcadIntf.Spray_RadialHousing_InletTemperature_R_degC = Tin1Val;
79-
if length(bkptIdxComb)==5
84+
if length(bkptIdxComb)==3 % one cooling system - e5_IM_HWJ case
85+
mcadIntf.HousingWaterJacket_FlowRate_m3ps = fr1Val/60/1000; % lpm to m3ps
86+
mcadIntf.HousingWaterJacket_InletTemperature_degC = Tin1Val;
87+
elseif length(bkptIdxComb)==5 % two cooling systems - e8_IPMSM_HWJandVent case
88+
mcadIntf.HousingWaterJacket_FlowRate_m3ps = fr1Val/60/1000; % lpm to m3ps
89+
mcadIntf.HousingWaterJacket_InletTemperature_degC = Tin1Val;
8090
mcadIntf.Ventilated_FlowRate_m3ps = fr2Val/60/1000; % lpm to m3ps
8191
mcadIntf.Ventilated_InletTemperature_degC = Tin2Val;
92+
elseif length(bkptIdxComb)==7 % three cooling systems - e8_IPMSM_SprayMultiNozzle case
93+
mcadIntf.Spray_RadialHousing_FlowRate_m3ps = fr1Val/60/1000; % lpm to m3ps
94+
mcadIntf.Spray_RadialHousing_InletTemperature_F_degC = Tin1Val;
95+
mcadIntf.Spray_RadialHousing_InletTemperature_R_degC = Tin1Val;
96+
mcadIntf.HousingWaterJacket_FlowRate_m3ps = fr2Val/60/1000; % lpm to m3ps
97+
mcadIntf.HousingWaterJacket_InletTemperature_degC = Tin2Val;
98+
mcadIntf.Spray_RadialRotor_FlowRate_m3ps = fr3Val/60/1000; % lpm to m3ps
99+
mcadIntf.Spray_RadialRotor_InletTemperature_F_degC = Tin3Val;
100+
mcadIntf.Spray_RadialRotor_InletTemperature_R_degC = Tin3Val;
82101
end
102+
83103
mcadIntf.EnableStatorTempCoeffRes = 1;
84104
mcadIntf.EnableRotorTempCoeffRes = 1;
85105
mcadIntf.updateModel();
@@ -88,6 +108,7 @@
88108
allMcadIdxs = [mcadIntf.NodeNamesAndMcadIdx{:,2}];
89109
[tVecMcad, TnodesMcad] = mcadIntf.getTransientTemperatureForNodeMcadIdxs(allMcadIdxs);
90110

111+
% Plot results ------------------------------------------------------
91112
TnodesMcadSeries = timeseries(TnodesMcad', tVecMcad);
92113
[TnodesMcadSeries,TnodesSeries] = synchronize(TnodesMcadSeries,TnodesSeries,'Union');
93114
TnodesMcadSeries.Name = 'Motor-CAD';

0 commit comments

Comments
 (0)