Skip to content

Commit

Permalink
Merge branch 'feature/ardupilot-tunable-parameter-postprocessing' int…
Browse files Browse the repository at this point in the history
…o main
  • Loading branch information
ybeyer committed Jul 25, 2024
2 parents b2ae24e + 1f592d5 commit 1af9f26
Show file tree
Hide file tree
Showing 11 changed files with 545 additions and 52 deletions.
52 changes: 0 additions & 52 deletions simulink/mask_expression_handling/maskExprHandlingAdd2Block.m
Original file line number Diff line number Diff line change
Expand Up @@ -556,55 +556,3 @@ function maskExprHandlingAdd2Block(blk)
blk_libdata = blk_libdata((strcmp(blk, {blk_libdata.Block})));
end
end



function user_confirmation = getUserConfirmation(varargin)

% Input Parser
p = inputParser;
addOptional(p, 'prompt', 'Do you want to proceed?', @(a) ischar(a) || isstring(a));
parse(p, varargin{:});

prompt = p.Results.prompt;

user_choice = getUserChoice(prompt, {'yes', 'no'});

switch user_choice
case 1
user_confirmation = true;
case 2
user_confirmation = false;
end
end



function user_choice = getUserChoice(varargin)

% Input Parser
p = inputParser;
addRequired(p, 'prompt', @(a) ischar(a) || isstring(a));
addRequired(p, 'options', @(a) iscellstr(a) && numel(a) > 1);
parse(p, varargin{:})

prompt = p.Results.prompt;
options = p.Results.options;

question = sprintf('%s (%s): ', prompt, strjoin(options, '/'));

user_in = input(question, "s");

while true
idxs = find(strcmpi(user_in, options));

if isempty(idxs)
user_in = input('Wrong answer, please try again: ', "s");
elseif numel(idxs) == 1
user_choice = idxs;
break;
else
error('This should not happen and is a bug!')
end
end
end
33 changes: 33 additions & 0 deletions simulink/utilities/bdIsRoot.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
function is_bdroot = bdIsRoot(model)
% BDISROOT checks if the input is a handle or a path to a loaded top-level
% Simulink model (model root).
%
% Inputs:
% model Handle (numeric) or path (character vector).
% Multiple models: numeric array of handles or cell array of
% character vectors.
%
% Outputs:
% is_bdroot Boolean, indicating whether the input is a loaded top-level
% Simulink model (true) or not (false)

% Disclaimer:
% SPDX-License-Identifier: GPL-3.0-only
%
% Copyright (C) 2024 Jonas Withelm
% Copyright (C) 2024 TU Braunschweig, Institute of Flight Guidance
% *************************************************************************

is_bdroot = false;
try
bd = bdroot(model);
if isnumeric(bd)
is_bdroot = model == bd;
else
is_bdroot = strcmp(model, bd);
end
catch
% Model is not loaded or input is invalid for bdroot
end

end
141 changes: 141 additions & 0 deletions simulink/utilities/checkModelReqs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
function varargout = checkModelReqs(model, model_reqs)
% CHECKMODELREQS checks whether the Simulink model fulfills the model
% parameter requirements in 'model_reqs'. CheckModelReqs throws an error
% with a tabular overview of the parameters that have not fulfilled the
% requirements. The model must be loaded for usage.
%
% The parameter requirements must be provided in the form of a struct
% (model_reqs) with the required fields 'param' and 'value' and the
% optional field 'err_desc', whereby the values of the fields must be
% cell arrays, e.g.
% model_reqs.param{1} = 'TargetLang';
% model_reqs.value{1} = 'C++';
% model_reqs.err_desc{1} = 'Wrong target language';
%
% The value check can also be provided as a function handle to a function
% that must return a boolean as the check result, e.g.
% model_reqs.value{1} = @(a) strcmp(a, C++);
%
% The parameter requirements can also be provided with a parameter file.
% In this case, 'model_reqs' must be a path to the parameter file.
%
% Inputs:
% model Handle or path to a top-level Simulink model
% (model root)
% model_reqs Model requirements struct as specified above or
% a path to a model requirements file
%
% Outputs (optional):
% varargout{1} No error is thrown, but instead an boolean array with
% the indices of all failed parameter requirements is
% returned

% Disclaimer:
% SPDX-License-Identifier: GPL-3.0-only
%
% Copyright (C) 2024 Jonas Withelm
% Copyright (C) 2024 TU Braunschweig, Institute of Flight Guidance
% *************************************************************************

% ToDo:
% - change model_reqs to struct array instead of cell arrays?


% Input checks
err_msg = char.empty;

if nargin ~=2
error('MATLAB:checkModelReqs:inputError', ...
'Wrong number of input arguments!');
end

if ~bdIsRoot(model)
msg = sprintf(' - %s\n', 'expected input ''model'' to be a loaded top-level Simulink model');
err_msg = [err_msg, msg];
end

if ischar(model_reqs)
model_reqs = loadParams(model_reqs);
end

if ~all(isfield(model_reqs, {'param', 'value'}))
msg = sprintf(' - %s\n', 'expected input ''model_reqs'' to be of type struct with at least two fields named ''param'' and ''value''');
err_msg = [err_msg, msg];
elseif any(size(model_reqs.param) ~= size(model_reqs.value))
msg = sprintf(' - %s\n', '''model_reqs.param'' and ''model_reqs.value'' must have the same size');
err_msg = [err_msg, msg];
end

if ~isempty(err_msg)
err_title = sprintf('Input error');
error('MATLAB:checkModelReqs:inputError', ...
'\n%s:\n%s', err_title, err_msg);
end

has_err_desc = isfield(model_reqs, 'err_desc'); % ToDo: size check?


% Do model requirement checks
errs = {};
idxs = false(size(model_reqs.param));
for idx = 1:numel(model_reqs.param)

% ToDo:
% - Check that value is scalar and of type char?
% -> Scalar is usefull, char could be dismissed, because a function
% handle check could still succeed
% - Check that param is an actual param of the model, raise error if
% not
value = get_param(model, model_reqs.param{idx});

switch class(model_reqs.value{idx})
case 'function_handle'
is_ok = model_reqs.value{idx}(value);
case {'char', 'string'}
is_ok = strcmp(model_reqs.value{idx}, value);
otherwise
error('MATLAB:checkModelReqs:inputError', '''model_reqs.value{%i}'' not supported!', idx);
end

if ~is_ok
idxs(idx) = true;

err = repmat({char.empty}, 1, 4);
err(1) = model_reqs.param(idx);
err(3) = {value};
if has_err_desc
err(4) = model_reqs.err_desc(idx);
end
switch class(model_reqs.value{idx})
case 'function_handle'
err(2) = {func2str(model_reqs.value{idx})};
case {'char', 'string'}
err(2) = model_reqs.value(idx);
end
errs = [errs; err];
end
end


if ~isempty(errs)
header = {'Param:', 'Expected:', 'Actual:', char.empty};
if has_err_desc
header(4) = {'Description:'};
end

err_id = 'MATLAB:checkModelReqs:requirementsFailed';
err_title = 'Model parameter requirements failed for';
err_msg = printData(header, errs, 'headerstyle', 'bold', 'indent', 4, 'column_spacing', 2);

ME = MException(err_id, '\n%s:\n%s', err_title, err_msg);

if nargout ~= 1
throw(ME);
end
end

if nargout == 1
varargout{1} = idxs;
end

end
24 changes: 24 additions & 0 deletions utilities/getFileFromPath.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function [file] = getFileFromPath(file_path)
% GETFILEFROMPATH returns the file part from a full path to a file.
%
% Inputs:
% file_path full path to a file
%
% Outputs:
% file filename with extension
%
% See also:
% FILEPARTS

% Disclaimer:
% SPDX-License-Identifier: GPL-3.0-only
%
% Copyright (C) 2024 Jonas Withelm
% Copyright (C) 2024 TU Braunschweig, Institute of Flight Guidance
% *************************************************************************


[~, file_name, file_ext] = fileparts(file_path);
file = [file_name file_ext];

end
37 changes: 37 additions & 0 deletions utilities/getLink2File.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
function file_link = getLink2File(file, link_text)
% GETLINK2FILE returns a link to a file.
%
% This functions returns a link to a file which, when clicked, opens the
% URL using the 'open()' function.
%
% Inputs:
% file file
% link_text Displayed name of the link (optional)
%
% Outputs:
% file_link Link to the file
%
% See also:
% OPEN
% https://mathworks.com/help/matlab/matlab_prog/create-hyperlinks-that-run-functions.html

% Disclaimer:
% SPDX-License-Identifier: GPL-3.0-only
%
% Copyright (C) 2024 Jonas Withelm
% Copyright (C) 2024 TU Braunschweig, Institute of Flight Guidance
% *************************************************************************

if ~exist(file, 'file')
err_msg = sprintf('''%s'' is either not a file or can not be found!', file);
error('MATLAB:getLink2File:inputError', '\n%s', err_msg);
end

if nargin == 1
link_text = getFileFromPath(file);
end

file_link = sprintf('<a href = "matlab:open(''%s'')">%s</a>', file, link_text);

end

31 changes: 31 additions & 0 deletions utilities/getLink2URL.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
function url_link = getLink2URL(url, link_text)
% GETLINK2URL returns a link to an URL.
%
% This functions returns a link to an URL which, when clicked, opens the
% URL using the 'web()' function with the system browser.
%
% Inputs:
% url URL
% link_text Displayed name of the link (optional)
%
% Outputs:
% url_link Link to the URL
%
% See also:
% WEB
% https://mathworks.com/help/matlab/matlab_prog/create-hyperlinks-that-run-functions.html

% Disclaimer:
% SPDX-License-Identifier: GPL-3.0-only
%
% Copyright (C) 2024 Jonas Withelm
% Copyright (C) 2024 TU Braunschweig, Institute of Flight Guidance
% *************************************************************************

if nargin == 2
url_link = sprintf('<a href = "matlab:web(''%s'',''-browser'')">%s</a>', url, link_text);
else
url_link = sprintf('<a href = "matlab:web(''%1$s'',''-browser'')">%1$s</a>', url);
end

end
49 changes: 49 additions & 0 deletions utilities/getUserChoice.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
function user_choice = getUserChoice(varargin)
% GETUSERCHOICE allows the user to select one of the provided options via
% the command line.
%
% Inputs:
% prompt Prompt to be asked, character vector
% options Selection options to be provided, cell array of
% character vectors
%
% Outputs:
% user_choice Index of the selected option
%
% See also:
% GETUSERSELECTION, GETUSERCONFIRMATION

% Disclaimer:
% SPDX-License-Identifier: GPL-3.0-only
%
% Copyright (C) 2024 Jonas Withelm
% Copyright (C) 2024 TU Braunschweig, Institute of Flight Guidance
% *************************************************************************

% Input Parser
p = inputParser;
addRequired(p, 'prompt', @(a) ischar(a) || isstring(a));
addRequired(p, 'options', @(a) iscellstr(a) && numel(a) > 1);
parse(p, varargin{:})

prompt = p.Results.prompt;
options = p.Results.options;

question = sprintf('%s (%s): ', prompt, strjoin(options, '/'));

while true
user_in = input(question, "s");

idxs = find(strcmpi(user_in, options));

if isempty(idxs)
question = 'Wrong answer, please try again: ';
elseif numel(idxs) == 1
user_choice = idxs;
break;
else
error('Too many matches!');
end
end

end
Loading

0 comments on commit 1af9f26

Please sign in to comment.