Skip to content

Commit a6c55e5

Browse files
authored
Manually resolved merge conflict (#37)
Because I created a PR, I can't be a reviewer. Ok to bypass the review step.
1 parent 558f226 commit a6c55e5

12 files changed

+3167
-2825
lines changed

BEVProjectDescription.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

BEVProjectNavigator.m

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
win.Name = "BEV Project Navigator";
2121
win.Width = 560;
22-
win.Height = 660;
22+
win.Height = 680;
2323

2424
width_unit = LiteApp5.Utility.Constant.Width{"unitwidth"};
2525
indent = width_unit * 2;
@@ -119,11 +119,23 @@
119119
row = NewRow(layout, column);
120120
LiteApp5.Component.Label(NewSlot(layout, row, Width=indent), Text="");
121121

122-
target_app = "Vehicle1DPerformanceDesignApp";
122+
target_description_page = "Vehicle1D_Description.html";
123+
LiteApp5.Utility.getFileFullPath(target_description_page);
124+
125+
link_ui = LiteApp5.Component.Hyperlink(NewSlot(layout, row));
126+
link_ui.HyperlinkText = "Vehicle1D description";
127+
link_ui.Tooltip = "Open page: " + target_description_page;
128+
link_ui.HyperlinkClickedCallback = @() open_target_page(target_description_page);
129+
130+
%%
131+
row = NewRow(layout, column);
132+
LiteApp5.Component.Label(NewSlot(layout, row, Width=indent), Text="");
133+
134+
target_app = "Vehicle1DPerformanceDesignApp_Basic";
123135
LiteApp5.Utility.getFileFullPath(target_app);
124136

125137
link_ui = LiteApp5.Component.Hyperlink(NewSlot(layout, row));
126-
link_ui.HyperlinkText = "Vehicle1D performance design app";
138+
link_ui.HyperlinkText = "Vehicle1D performance design app for Basic model";
127139
link_ui.Tooltip = "Open app: " + target_app;
128140
link_ui.HyperlinkClickedCallback = @() open_app(target_app);
129141

@@ -141,7 +153,7 @@
141153
LiteApp5.Utility.getFileFullPath(target_description_page);
142154

143155
link_ui = LiteApp5.Component.Hyperlink(NewSlot(layout, row));
144-
link_ui.HyperlinkText = "MDU description page";
156+
link_ui.HyperlinkText = "MDU description";
145157
link_ui.Tooltip = "Open page: " + target_description_page;
146158
link_ui.HyperlinkClickedCallback = @() open_target_page(target_description_page);
147159

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
function App = Vehicle1DPerformanceDesignApp_Basic()
2+
%% Vehicle1D performance design app for Basic vehicle1d model
3+
4+
% Copyright 2025 The MathWorks, Inc.
5+
6+
arguments (Output)
7+
App (1,:) Vehicle1DPerformanceDesignAppMain
8+
end % arguments
9+
10+
parameter_file = "Vehicle1D_refsub_Basic_params";
11+
block_path = "Vehicle1D_refsub_Basic/Longitudinal Vehicle";
12+
13+
% Load block parameters to the base workspace.
14+
disp("Loading parameters: <a href=""matlab:edit('"+ parameter_file +"')"">" + parameter_file + "</a>")
15+
evalin("base", parameter_file)
16+
17+
% Open the app with the target block initially loaded.
18+
vehicle_app = Vehicle1DPerformanceDesignAppMain(BlockPath=block_path);
19+
20+
vehicle_app.Window.HeaderUI.AppSourceName = mfilename;
21+
22+
if nargout > 0
23+
App = vehicle_app;
24+
end % if
25+
end % function
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
classdef Vehicle1DPerformanceDesignApp_Basic_uitest < matlab.uitest.TestCase
2+
%% Class implementation of UI test
3+
% Overview of App Testing Framework
4+
% https://www.mathworks.com/help/matlab/matlab_prog/overview-of-app-testing-framework.html
5+
%
6+
% Table of Verifications, Assertions, and Other Qualifications
7+
% https://www.mathworks.com/help/matlab/matlab_prog/types-of-qualifications.html
8+
9+
% Overview of App Testing Framework
10+
% https://www.mathworks.com/help/matlab/matlab_prog/overview-of-app-testing-framework.html
11+
12+
% Copyright 2024-2025 The MathWorks, Inc.
13+
14+
properties
15+
16+
% Do not specify the class name for a property to hold a handle to an app.
17+
% For class-based test apps, the class name is the app name, making
18+
% it difficult to use a common teardown if the class name is specified here.
19+
App (1,1)
20+
21+
end % properties
22+
23+
methods (TestMethodSetup)
24+
% Functions in the TestMethodSetup section always run before
25+
% each test defined in the Test section runs.
26+
27+
function test_method_setup(testcase)
28+
%%
29+
close all
30+
bdclose all
31+
32+
% addTeardown adds a function which always runs after each test.
33+
% Even if the execution of a test ends with an error, the teardown function runs.
34+
addTeardown(testcase, @close_all)
35+
36+
function close_all
37+
close all
38+
bdclose all
39+
40+
% Delete the app's figure object from memory.
41+
if isstruct(testcase.App)
42+
% Function-based app
43+
if not(isfield(testcase.App, "Window"))
44+
% There is no window to close.
45+
46+
return
47+
48+
end % if
49+
% App.Window is a struct field which does not trigger destructor.
50+
% Delete the figure directly.
51+
delete(testcase.App.Window.MainFigure)
52+
else
53+
% Class-based app
54+
% App.Window's destructor deletes the figure.
55+
delete(testcase.App.Window)
56+
end % if
57+
end % nested function
58+
end % function
59+
60+
end % methods
61+
62+
methods (Test)
63+
% Functions in the Test section are the tests.
64+
% Before a function in this section runs, the functions defined in the TestMethodSetup section run.
65+
66+
%% Minimum quality check (MQC)
67+
% Check that models, scripts, functions, and classes run right out of the box.
68+
69+
function MQC_App_1(testcase)
70+
verifyWarningFree(testcase, @() target())
71+
function target()
72+
testcase.App = Vehicle1DPerformanceDesignApp_Basic; % !test-target
73+
end % nested function
74+
end % function
75+
76+
%% Other tests
77+
78+
function test_vehicle_mass(testcase)
79+
% Check that the parameter values are loaded as expected.
80+
testcase.App = Vehicle1DPerformanceDesignApp_Basic;
81+
sscval = testcase.App.VehicleMassUI.SimscapeValue;
82+
expected = value(sscval, "kg");
83+
actual = 2400;
84+
verifyEqual(testcase, expected, actual)
85+
end % function
86+
87+
function test_frontal_area(testcase)
88+
% Check that the parameter values are loaded as expected.
89+
testcase.App = Vehicle1DPerformanceDesignApp_Basic;
90+
sscval = testcase.App.FrontalAreaUI.SimscapeValue;
91+
expected = value(sscval, "m^2");
92+
actual = 0.9 * 1.921 * 1.624;
93+
verifyEqual(testcase, expected, actual, RelTol=0.01)
94+
end % function
95+
96+
end % methods
97+
98+
end % classdef

Components/Vehicle1D/Utility-Vehicle1D/Vehicle1DPerformanceDesignAppMain.m

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ function delete(App)
143143
App.SelectorUI.ModelFileFullPath = modelfile_fullpath;
144144
% Block path in the drop down uses " / " as the subsystem separator.
145145
App.SelectorUI.BlockPathDropDownUI.Value = replace(App.BlockPath, "/", " / ");
146+
147+
App.SelectorUI.GetParametersFromBlockCallback()
146148
end % if
147149

148150
Show(App.Window)
@@ -185,26 +187,71 @@ function delete(App)
185187

186188
function getParametersFromVehicleBlock(App)
187189
%%
190+
% This function collects parameters from the block in the model specified by
191+
% the block selector.
192+
% If a block parameter is a workspace variable, it must have been loaded
193+
% in the base workspace. If it's not loaded, the physical value UI component
194+
% shows an inline error.
188195

189196
App.ModelName = App.SelectorUI.ModelName;
190197
App.BlockPath = App.SelectorUI.BlockPath;
191198

192-
previous_parameters = App.Parameters;
193-
App.Parameters = setup_all_data(App);
199+
% Before updating UI components, turn off the plot auto-update because
200+
% all UI components whose value changes call auto-update,
201+
% which is unecessary and noticeably slows down the update.
202+
previous_auto_update_value = App.AutoUpdateUI.Value;
203+
App.AutoUpdateUI.Value = false;
194204

195-
if not(App.BlockIsReady)
196-
% There was an issue in getting parameters from the block.
197-
% Recover the previous state.
198-
App.Parameters = previous_parameters;
199-
App.BlockPath = "";
205+
% Full enum name is returned, e.g., "sdl.enum.VehicleParameterizationType.Regular".
206+
full_enum_name = get_param(App.BlockPath, "vehParamType");
207+
% Get the last part, which is the enum element name, e.g. "Regular".
208+
enum_element_name = extractAfter(full_enum_name, asManyOfPattern(wildcardPattern + "."));
200209

201-
return
210+
if enum_element_name ~= "Regular"
211+
id = App.errorID + ":InvalidBlockParameter";
212+
msg = LiteApp5.Utility.i18n("Only ""Regular"" Parameterization type for Longitudinal Vehicle block is supported.");
213+
214+
throw(MException(id, msg))
202215

203216
end % if
204217

205-
setParametersToUIComponents(App)
206-
auto_update_plot(App)
218+
App.VehicleMassUI.ValueEditFieldUI.Value = get_param(App.BlockPath, "M_vehicle");
219+
App.VehicleMassUI.UnitDropDownUI.MainDropDown.Value = get_param(App.BlockPath, "M_vehicle_unit");
220+
221+
% R_tireroll (tire rolling radius) is skipped because it is not used in the app.
222+
223+
App.TireRollingCoefficientUI.Value = get_param(App.BlockPath, "C_tireroll");
224+
225+
App.AirDragCoefficientUI.Value = get_param(App.BlockPath, "C_airdrag");
226+
227+
App.FrontalAreaUI.Value = get_param(App.BlockPath, "A_front");
228+
App.FrontalAreaUI.Unit = get_param(App.BlockPath, "A_front_unit");
229+
230+
App.GravitationalAccelerationUI.Value = get_param(App.BlockPath, "g");
231+
App.GravitationalAccelerationUI.Unit = get_param(App.BlockPath, "g_unit");
232+
233+
% !todo: Air density should be public in Longitudinal Vehicle block.
234+
% App.AirDensityUI.Value = get_param(App.BlockPath, "air_density");
235+
% App.AirDensityUI.Unit = get_param(App.BlockPath, "air_density_unit");
236+
237+
% Deselect the preset because parameters are read from the specified block.
238+
App.PresetUI.MainListBox.Value = {};
239+
240+
% -----------------------------------------------------------------------
241+
242+
% Synchronize the Parameters property based on the updated UI components
243+
% and update other UI components for the derived parameters.
244+
getParametersFromUIComponents(App)
245+
App.Parameters = update_states(App.Parameters);
246+
App.RoadLoadAUI.SimscapeValue = App.Parameters.RoadLoadA;
247+
App.RoadLoadCUI.SimscapeValue = App.Parameters.RoadLoadC;
248+
App.MaximumForceUI.SimscapeValue = App.Parameters.MaximumForce;
249+
App.MaximumClimbPowerUI.SimscapeValue = App.Parameters.MaximumClimbPower;
207250

251+
% Recover the previous auto-update state for the plot button.
252+
App.AutoUpdateUI.Value = previous_auto_update_value;
253+
254+
auto_update_plot(App)
208255
end % function
209256

210257
function setParametersToVehicleBlock(App)
@@ -264,14 +311,6 @@ function performancePlot(App, NameValuePair)
264311
function getParametersFromUIComponents(App)
265312
%%
266313

267-
if App.UseGUI
268-
id = App.errorID + "AppNotVisible";
269-
msg = "App must be visible before calling getParametersFromUIComponents";
270-
% When this assertion fails, the app is not visible yet.
271-
% Thus, show the error message in the Command Window.
272-
assert(App.Window.MainFigure.Visible == "on", id, msg)
273-
end % if
274-
275314
% Vehicle ---------------------------------------------------------------
276315

277316
App.Parameters.VehicleMass = App.VehicleMassUI.SimscapeValue;
@@ -771,31 +810,6 @@ function callback_AutoUpdate(App)
771810
App.UpdateButtonUI.MainButton.Enable = "on";
772811
end % if
773812
end % function
774-
775-
%{
776-
function callback_LoadParametersFromBlock(App)
777-
%%
778-
[App.Parameters, error_message] = getParametersFromBlock(App.Parameters, App.BlockPath);
779-
if error_message ~= ""
780-
% Do not issue an error and return from here.
781-
% Fallback data are loaded in case of an error.
782-
% if App.UseGUI && isprop(App, "Window") && isprop(App.Window, "MainFigure") && App.Window.MainFigure.Visible
783-
uialert(App.Window.MainFigure, error_message, "Alert")
784-
% else
785-
% % App is not visible.
786-
% warning("Vehicle1DPerformanceDesignAppMain:ErrorInGetParametersFromBlock", error_message);
787-
% end % if, App UI or Command Window
788-
end % if, error
789-
790-
App.Parameters = update_states(App.Parameters);
791-
792-
setParametersToComponents(App)
793-
794-
if App.AutoUpdateUI.Value
795-
performancePlot(App, ParentAxes=App.ParentAxes)
796-
end % if, propagation
797-
end % function
798-
%}
799813

800814
function setParametersToUIComponents(App, NameValuePairs)
801815
%%

Components/Vehicle1D/Utility-Vehicle1D/Vehicle1DPerformanceParameters.m

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@
305305
Param.MaximumForce = simscape.Value(val_F, "N");
306306
end % function
307307

308+
%{
308309
function ParamString = Stringify(Param)
309310
%%
310311
arguments (Output)
@@ -330,9 +331,14 @@
330331
end % for
331332
ParamString = join(line_str, newline);
332333
end % function
334+
%}
333335

334336
function Param = getParametersFromBlock(Param, BlockPath)
335337
%%
338+
% This function collects block parameters from the specified block and
339+
% stores the parameters as simscape.Value objects.
340+
% If a block parameter is a workspace variable, it is evaluated to get a numeric value.
341+
336342
arguments (Input)
337343
Param
338344
BlockPath (1,1) string = ""
@@ -381,7 +387,18 @@
381387
function sscval = get_simscape_value(name)
382388
v = double(block_properties(name));
383389
if isnan(v)
384-
v = evalin("base", block_properties(name));
390+
try
391+
v = evalin("base", block_properties(name));
392+
catch exception
393+
% This exception can happen when, for example, the block property is referring to
394+
% a workspace variable which is not loaded.
395+
id = Param.errorID + "EvalutionFailureForBlockProperty";
396+
msg = LiteApp5.Utility.i18n("The evaluation of the specified block property failed: ") + name + newline + ...
397+
LiteApp5.Utility.i18n("The property value was " + block_properties(name));
398+
399+
throw(MException(id, msg))
400+
401+
end % if
385402
end % if
386403
u = block_properties(name + "_unit");
387404
sscval = simscape.Value(v, u);

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ in the BEV model.
3737
alt="Screenshot of the simulation result plots"
3838
width="700">
3939

40-
BEV Project navigator App
40+
BEV Project Navigator App
4141

4242
<img src="Utility/screenshot-BEV-project-navigator-app.png"
4343
alt="Screenshot of the longitudinal vehicle performance design app"
@@ -212,4 +212,4 @@ vehicle system-level applications using abstract models.
212212

213213
See [`license.txt`](license.txt).
214214

215-
_Copyright 2020-2024 The MathWorks, Inc._
215+
_Copyright 2020-2025 The MathWorks, Inc._

0 commit comments

Comments
 (0)