From 4477052451de258c79001cf6bf2a0c24a96ee664 Mon Sep 17 00:00:00 2001 From: Alexandre Donze Date: Tue, 25 Jan 2022 21:41:45 +0100 Subject: [PATCH] 1.10.0 --- .gitignore | 2 +- @STL_Formula/STL_ApplyRec.m | 23 + .../STL_Eval_Structural_Sensitivity.m | 34 + .../calculate_structural_sensitivity.m | 454 +++ @STL_Formula/disp.m | 7 + @STL_Formula/private/generic_predicate.m | 39 +- @STL_Formula/tree_disp.m | 34 + CHANGELOG.md | 15 + Core/Algos/@BreachProblem/BreachProblem.m | 43 +- .../@BreachProblem/solve_adaptive_corners.m | 109 + Core/Algos/@BreachProblem/solve_corners.m | 6 +- Core/Algos/ComputeMorrisSensi.m | 12 +- Core/Algos/FalsificationProblem.m | 3 +- Core/BreachDomain.m | 5 +- Core/BreachOpenSystem.m | 29 +- Core/BreachRandomSys.m | 54 + Core/BreachRequirement.m | 166 +- Core/BreachSet.m | 213 +- Core/BreachSimulinkSystem.m | 146 +- Core/BreachSystem.m | 51 +- Core/BreachTraceSystem.m | 147 +- Core/ComputeTraj.m | 10 +- Core/CreateExternSystem.m | 4 +- Core/Gui/BreachGuiClass.m | 553 +-- Core/Gui/BreachProblemGui.m | 43 + Core/Gui/elems/slider_elem.m | 20 + Core/OutputGen/alw_monitor.m | 18 +- Core/OutputGen/postprocess_fcn_wrapper.m | 2 +- Core/OutputGen/req_monitor.m | 32 +- Core/OutputGen/stl_monitor.m | 182 +- Core/STL_ReadFile.m | 26 +- Core/SignalGen/BreachSignalGen.m | 4 +- Core/SignalGen/constant_signal_gen.m | 2 +- Core/SignalGen/cp_signal_gen.m | 2 +- Core/SignalGen/exponential_signal_gen.m | 2 +- Core/SignalGen/fixed_cp_signal_gen.m | 2 +- Core/SignalGen/from_file_pattern_signal_gen.m | 2 +- Core/SignalGen/from_workspace_signal_gen.m | 2 +- Core/SignalGen/merge_signal_gen.m | 2 +- Core/SignalGen/multi_pulse_signal_gen.m | 118 + Core/SignalGen/pulse_signal_gen.m | 2 +- Core/SignalGen/random_signal_gen.m | 4 +- Core/SignalGen/signal_gen.m | 12 + Core/SignalGen/sinusoid_signal_gen.m | 2 +- Core/SignalGen/spike_signal_gen.m | 2 +- Core/SignalGen/step_signal_gen.m | 2 +- Core/SignalGen/switch_signal_gen.m | 2 +- Core/SignalGen/time_shift_signal_gen.m | 3 +- Core/SignalGen/var_cp_signal_gen.m | 2 +- Core/SignalGen/var_step_signal_gen.m | 2 +- Core/m_src/ResetBreach.m | 12 +- Core/m_src/check_arg_is_cell.m | 2 + Core/m_src/check_sim_time.m | 33 + Core/m_src/cover.m | 10 +- Core/m_src/cover_complete.m | 55 + Core/m_src/list_manip.m | 86 + Core/m_src/rand_formula.m | 135 +- Doc/img/AFC_Internal_signals.svg | 1458 +++++++ Doc/img/AFC_PI.svg | 2483 ++++++++++++ Doc/img/AFC_top_level.svg | 3387 +++++++++++++++++ Doc/img/InputGenGUI.png | Bin 0 -> 67926 bytes Doc/img/InputGenGUI.svg | 1220 ++++++ Doc/index.html | 104 + .../+BrDemo/+InputGen/from_file_signal_gen.m | 55 +- .../+InputGen/multi_pulse_signal_gen.m | 15 + Examples/+BrDemo/AFC_5_3_MaxSat.m | 1 - Ext/Specs/Autotrans_spec.stl | 2 +- .../Autotrans_online/Autotrans_online.mdl | 1414 +++++-- Params/m_src/N2Nn.m | 4 +- Plots/BreachSamplesPlot.m | 16 +- Plots/BreachSignalsPlot.m | 403 +- README.md | 347 +- VERSION | 2 +- 73 files changed, 12770 insertions(+), 1125 deletions(-) create mode 100644 @STL_Formula/STL_ApplyRec.m create mode 100755 @STL_Formula/STL_Eval_Structural_Sensitivity.m create mode 100755 @STL_Formula/calculate_structural_sensitivity.m create mode 100644 @STL_Formula/tree_disp.m create mode 100755 Core/Algos/@BreachProblem/solve_adaptive_corners.m create mode 100644 Core/BreachRandomSys.m create mode 100644 Core/Gui/BreachProblemGui.m create mode 100644 Core/Gui/elems/slider_elem.m create mode 100644 Core/SignalGen/multi_pulse_signal_gen.m create mode 100644 Core/m_src/check_sim_time.m create mode 100644 Core/m_src/cover_complete.m create mode 100644 Core/m_src/list_manip.m create mode 100644 Doc/img/AFC_Internal_signals.svg create mode 100644 Doc/img/AFC_PI.svg create mode 100644 Doc/img/AFC_top_level.svg create mode 100644 Doc/img/InputGenGUI.png create mode 100644 Doc/img/InputGenGUI.svg create mode 100644 Doc/index.html create mode 100644 Examples/+BrDemo/+InputGen/multi_pulse_signal_gen.m diff --git a/.gitignore b/.gitignore index ffcde6e9..afd41e2d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ Examples/*.dat Examples/variablescmaes.mat slprj/ -Doc/ # Ignore everything in Ext... Ext/* @@ -41,3 +40,4 @@ docrun_backup.mat *.r2015a *_ert_rtw *.7z +*.slxc diff --git a/@STL_Formula/STL_ApplyRec.m b/@STL_Formula/STL_ApplyRec.m new file mode 100644 index 00000000..2c1cf44d --- /dev/null +++ b/@STL_Formula/STL_ApplyRec.m @@ -0,0 +1,23 @@ +function out = STL_ApplyRec(phi,func,n) +% STL_ApplyRec Recursively apply func to the phi and its subformulas + +if nargin<3 + n=inf; +end + +out = {func(phi)}; +if n>0 + switch (phi.type) + case 'predicate' + return; + + case{'not', 'always', 'eventually', 'historically', 'once'} + out1 = STL_ApplyRec(phi.phi,func,n-1); + out = [out out1] ; + + case {'and', 'or', '=>', 'until'} + out1 = STL_ApplyRec(phi.phi1,func,n-1); + out2 = STL_ApplyRec(phi.phi2,func,n-1); + out = [out out1 out2]; + end +end \ No newline at end of file diff --git a/@STL_Formula/STL_Eval_Structural_Sensitivity.m b/@STL_Formula/STL_Eval_Structural_Sensitivity.m new file mode 100755 index 00000000..189874e2 --- /dev/null +++ b/@STL_Formula/STL_Eval_Structural_Sensitivity.m @@ -0,0 +1,34 @@ +function is_sensitive = STL_Eval_Structural_Sensitivity(Sys, phi, P, traj1, traj2, inout, relabs, taus) + + +%% default parameters +if isfield(phi.params,'default_params') + pnames = fieldnames(phi.params.default_params); + for ip = 1:numel(pnames) + % if P doesn't define the parameter, use default + if FindParam(P,pnames{ip})> size(P.pts,1) + pval = phi.params.default_params.(pnames{ip}); + if isscalar(pval) + P = SetParam(P,pnames{ip},pval ); + else + P.(pnames{ip}) = pval; + end + end + end +end + +partition = []; +if (strcmp(inout, 'in')) + partition = get_in_signal_names(phi); +elseif (strcmp(inout, 'out')) + partition = get_out_signal_names(phi); +end + +[trajs_sensitive, time_values__] = ... + calculate_structural_sensitivity(Sys, phi, P, traj1, traj2, partition, relabs, taus); + +% TODO: Can we ignore time values here? +is_sensitive = any(trajs_sensitive); + + +end diff --git a/@STL_Formula/calculate_structural_sensitivity.m b/@STL_Formula/calculate_structural_sensitivity.m new file mode 100755 index 00000000..76014b90 --- /dev/null +++ b/@STL_Formula/calculate_structural_sensitivity.m @@ -0,0 +1,454 @@ +function [trajsSensitive, time_values__] = calculate_structural_sensitivity(Sys, phi, P, traj1, traj2, partition, relabs, t) + + +%% defines the parameter as global variables so that they are available for +% all subsequent computations + +global BreachGlobOpt; +if ~isempty(P.ParamList) + BreachGlobOpt.GlobVarsDeclare = ['global ', sprintf('%s ',P.ParamList{:})]; % contains parameters and IC values (can remove IC if phi is optimized) + eval(BreachGlobOpt.GlobVarsDeclare); % These values may be used in generic_predicate and GetValues +else + BreachGlobOpt.GlobVarsDeclare = ''; % contains parameters and IC values (can remove IC if phi is optimized) +end + +ii=1; +num_dim = size(P.pts,1); +eval_str = [P.ParamList(1:num_dim);num2cell(1:num_dim)]; +eval_str = sprintf('%s=P.pts(%d,ii);',eval_str{:}); +eval(eval_str); + +%% for each trajectory, compute values and times + +numTrajs = numel(traj1); +val__ = cell(1, numTrajs); +time_values__ = cell(1, numTrajs); + +if isstruct(traj1)||isa(traj1, 'matlab.io.MatFile') + traj1 = {traj1}; + traj2 = {traj2}; +end + +for ii=1:numTrajs % we loop on every traj in case we check more than one + if (Psize_pts(P)==1) + Pii = P; + else + Pii = Sselect(P, ii); + eval(eval_str); % needed, as parameters can change from one Pii to another + end + + % Ensures that traj.X and traj.time are double precision + traj.time = double(traj1{ii}.time); + traj.X = double(traj1{ii}.X); + + % Add information from the second traj aswell + assert(all(traj1{ii}.time == traj2{ii}.time)); + traj.X2 = double(traj2{ii}.X); + + % Robusthom doesn't like singular intervals - should be optimized one + % of these days ... + if exist('t','var') + time_values__{ii} = t; + if(numel(t)==1) + tn = find(traj.time>t,1); + if isempty(tn) + interval = [t t+1]; % Maybe not the best choice, but we have to make one ! + else + interval = [t traj.time(1,tn)]; + end + else + interval = [t(1) t(end)]; + end + trajsSensitive = GetValues(Sys, phi, Pii, traj, partition, relabs, interval); + + try + % if(numel(t)==1) % we handle singular times + % val__{ii} = val(1); + % else + if isfield(BreachGlobOpt, 'disable_robust_linear_interpolation')&&BreachGlobOpt.disable_robust_linear_interpolation + val__{ii} = interp1(time_values, val, t, 'previous'); + else + val__{ii} = interp1(time_values, val, t); + end +% end + catch % if val is empty + val__{ii} = NaN(1,numel(t)); + end + else + error('Not implemented yet'); + interval = [0 traj.time(1,end)]; + [val__ii, time_values__ii] = GetValues(Sys, phi, Pii, traj, partition, relabs, interval); + + val__{ii} = val__ii(time_values__ii<=traj.time(1,end)); + time_values__{ii} = time_values__ii(time_values__ii<=traj.time(1,end)); + + if (time_values__{ii}(end) < traj.time(end)) + vend__ = interp1(time_values__ii, val__ii,traj.time(1,end)); + time_values__{ii}(end+1) = traj.time(1,end); + val__{ii}(end+1)= vend__; + end + + end +end + +if(numTrajs==1) + val__ = val__{1}; + time_values__ = time_values__{1}; +else + if numel(t)==1 + val__ = cell2mat(val__); + time_values__ = cell2mat(time_values__); + end +end +end +%% + +function [trajsSensitive, time_values] = GetValues(Sys, phi, P, traj, partition, relabs, interval) +% trajsSensitive shows, for each time value, where the subformulas do NOT +% have the same value. 1 - not same value. 0 - same value. +global BreachGlobOpt; +eval(BreachGlobOpt.GlobVarsDeclare); + +switch(phi.type) + + case 'predicate' + time_values = GetTimeValues(traj, interval); + params = phi.params; + params.Sys = Sys; + params.P = P; + + % Create the second trajectory + traj2.time = traj.time; + traj2.X = traj.X2; + evalfn1 = @(t) phi.evalfn(0, traj, t, params); % will call generic_predicate + evalfn2 = @(t) phi.evalfn(0, traj2, t, params); % will call generic_predicate + + try % works if predicate can handle multiple time values + valarrayTraj1 = evalfn1(time_values); + valarrayTraj2 = evalfn2(time_values); + catch err %#ok + throw(err); + valarray = arrayfun(evalfn, time_values); + end + + trajsSensitive = (valarrayTraj1 ~= valarrayTraj2); + + case 'not' + % Negating does not affect sensitivity + [trajsSensitive, time_values] = GetValues(Sys, phi.phi, P, traj, partition, relabs, interval); + + case 'or' + [trajsSensitive1, time_values1] = GetValues(Sys, phi.phi1, P, traj, partition, relabs, interval); + [trajsSensitive2, time_values2] = GetValues(Sys, phi.phi2, P, traj, partition, relabs, interval); + + % Sensitivity either in first traj OR second traj gives sensitivity + % of disjunction + [trajsSensitive, time_values] = StaticSensitivity(time_values1, trajsSensitive1, time_values2, trajsSensitive2); + + case 'and' + [trajsSensitive1, time_values1] = GetValues(Sys, phi.phi1, P, traj, partition, relabs, interval); + [trajsSensitive2, time_values2] = GetValues(Sys, phi.phi2, P, traj, partition, relabs, interval); + + % Sensitivity either in first traj OR second traj gives sensitivity + % of conjunction + [trajsSensitive, time_values] = StaticSensitivity(time_values1, trajsSensitive1, time_values2, trajsSensitive2); + + case 'andn' + error('not implemented'); + + case '=>' + error('not implemented'); + + case 'always' + I___ = eval(phi.interval); + I___ = max([I___; 0 0]); + I___(1) = min(I___(1), I___(2)); + next_interval = I___+interval; + [trajsSensitive1, time_values] = GetValues(Sys, phi.phi, P, traj, partition, relabs, next_interval); + + [trajsSensitive, time_values] = TimedSensitivity(time_values, trajsSensitive1, I___); + + case 'av_eventually' + error('Not implemented'); + + case 'eventually' + 5; + I___ = eval(phi.interval); + I___ = max([I___; 0 0]); + I___(1) = min(I___(1), I___(2)); + next_interval = I___+interval; + [valarray1, time_values1] = GetValues(Sys, phi.phi, P, traj, partition, relabs, next_interval); + + switch phi.semantics + case 'max' + if(I___(end)~=inf) + time_values1 = [time_values1 time_values1(end)+I___(end)]; + valarray1 = [valarray1 valarray1(end)]; + end + [time_values, valarray] = RobustEv(time_values1, valarray1, I___); + case 'add' + [time_values, valarray] = RobustAlways(time_values1, -valarray1, I___); + valarray = -valarray; + case 'vbool_v1' + [time_values, valarray] = RobustAlways_v1(time_values1, -valarray1, I___); + valarray = -valarray; + case 'MARV' + % On this level, MARV is just standard robustness, since + % MARV only applies to top-level "always"-operator. + if(I___(end)~=inf) + time_values1 = [time_values1 time_values1(end)+I___(end)]; + valarray1 = [valarray1 valarray1(end)]; + end + [time_values, valarray] = RobustEv(time_values1, valarray1, I___); + case 'constant' + if(I___(end)~=inf) + time_values1 = [time_values1 time_values1(end)+I___(end)]; + valarray1 = [valarray1 valarray1(end)]; + end + [time_values, valarray] = RobustEv(time_values1, valarray1, I___); + otherwise + error('Unknown objective function!'); + end + + case 'once' + I___ = eval(phi.interval); + I___ = max([I___; 0 0]); + I___(1) = min(I___(1), I___(2)); + + next_interval = interval-[I___(1)+I___(2), I___(1)]; + next_interval(1) = max(0, next_interval(1)); + + [trajsSensitive1, time_values1] = GetValues(Sys, phi.phi, P, traj, partition, relabs, next_interval); + + % Flipping time, taking into account constant interpolation with + % previous + Tend__ = time_values1(end)+1; + past_time_values1 = fliplr(Tend__-[time_values1 Tend__]); + past_valarray1 = fliplr([trajsSensitive1(1) trajsSensitive1]); + + [past_valarray, past_time_values] = TimedSensitivity(past_time_values1, past_valarray1, I___); + + % Flipping back + time_values = fliplr(Tend__-[past_time_values Tend__]); + trajsSensitive = fliplr([past_valarray(1) past_valarray]); + + case 'historically' + I___ = eval(phi.interval); + I___ = max([I___; 0 0]); + I___(1) = min(I___(1), I___(2)); + + next_interval = interval-[I___(1)+I___(2), I___(1)]; + next_interval(1) = max(0, next_interval(1)); + + [trajsSensitive1, time_values1] = GetValues(Sys, phi.phi, P, traj, partition, relabs, next_interval); + + % Flipping time, taking into account constant interpolation with + % previous + Tend__ = time_values1(end)+1; + past_time_values1 = fliplr(Tend__-[time_values1 Tend__]); + past_valarray1 = fliplr([trajsSensitive1(1) trajsSensitive1]); + + [past_valarray, past_time_values] = TimedSensitivity(past_time_values1, past_valarray1, I___); + + % Flipping back + time_values = fliplr(Tend__-[past_time_values Tend__]); + trajsSensitive = fliplr([past_valarray(1) past_valarray]); + + case 'until' + 5; + I___ = eval(phi.interval); + I___ = max([I___; 0 0]); + I___(1) = min(I___(1), I___(2)); + interval1 = [interval(1), I___(2)+interval(2)]; + interval2 = I___+interval; + + [valarray1, time_values1] = GetValues(Sys, phi.phi1, P, traj, partition, relabs, interval1); + [valarray2, time_values2] = GetValues(Sys, phi.phi2, P, traj, partition, relabs, interval2); + if(I___(end)~=inf) + time_values1 = [time_values1 time_values1(end)+I___(end)]; + valarray1 = [valarray1 valarray1(end)]; + time_values2 = [time_values2 time_values2(end)+I___(end)]; + valarray2 = [valarray2 valarray2(end)]; + end + [time_values, valarray] = RobustUntil(time_values1, valarray1, time_values2, valarray2, I___); +end + + +end + +function time_values = GetTimeValues(traj,interval) +%GETTIMEVALUES provides time points belonging to traj.time strictly +% included in interval plus the bounds of interval. +% +% Note: for now it does not deal correctly with operations on time, e.g. +% x[t-a] of x[ g(t) ] where g is some function +% +% Also if we wanted to deal correctly with open or closed intervals that +% would be the place to look into. For now, the interpretation is rather +% that of closed intervals. +% + +if(interval(1)==interval(end)) + time_values = interval(1); + return ; +end + +% first time instant +ind_ti = find(traj.time>=interval(1),1); +if isempty(ind_ti) + if ~isempty(traj.time) + time_values = [traj.time(1,end) traj.time(1,end)+1]; + else + time_values = []; + end + return +end + +if(traj.time(1,ind_ti)==interval(1)) + time_values = traj.time(1,ind_ti); + ind_ti = ind_ti+1; +else + time_values = interval(1); +end + +% Last time instant +if(interval(end)==inf) + time_values = [time_values traj.time(1,ind_ti:end)]; +else + ind_tf = find(traj.time >= interval(end),1); + if isempty(ind_tf) + time_values = [time_values traj.time(1,ind_ti:end) interval(end)]; + elseif(traj.time(1,ind_tf)==interval(end)) + time_values = [time_values traj.time(1,ind_ti:ind_tf)]; + else + time_values = [time_values traj.time(1,ind_ti:ind_tf-1) interval(end)]; + end +end + +end + +function [valarray, time_values] = StaticSensitivity(time_values1, valarray1, time_values2, valarray2) +% Like robustAndPlus, but for sensitivity instead of robustness + +% Store all time instances that exist in the two time arrays time_values1 +% and time_values2 +time_values = union(time_values1, time_values2); + +% Create the valarray that will contain sensitivity values +valarray = zeros(size(time_values)); + +% Handle cases if time values are nonexistent! +if isempty(time_values1) + time_values = time_values2; + valarray = valarray2; + return +end + +if isempty(time_values2) + time_values = time_values1; + valarray = valarray1; + return +end + +% Loop over all times +idx1new = 1; +idx2new = 1; +for k = 1:length(time_values) + % Find the index we need in time_values1 + if idx1new == numel(time_values1) + % Do nothing + elseif time_values1(idx1new+1) <= time_values(k) + idx1new = idx1new + 1; + end + + % Find the index we need in time_values2 + if idx2new == numel(time_values2) + % Do nothing + elseif time_values2(idx2new+1) <= time_values(k) + idx2new = idx2new + 1; + end + + val1 = valarray1(idx1new); + val2 = valarray2(idx2new); + + % If EITHER is sensitive, the output is sensitive + valarray(k) = val1 || val2; + +end + +end + +function [trajsSensitive, time_values] = TimedSensitivity(time_values, valarray, I___) +% Like RobustAlways, but for sensitivity values instead of robustness +% values + +time_values = time_values - I___(1); +I___ = I___ - I___(1); + +startIdxNew = 1; +endIdxNew = 1; + +indicesToRemove = []; + +for valIndex = 1:length(valarray) + thisTime = time_values(valIndex); + + % Start time is currentTime + first element of I___ + startTime = thisTime + I___(1); + + % End time is startTime + second element of I___ + endTime = startTime + I___(2); + + % New getting partialTime and partialValarray + for startCounter = startIdxNew:numel(time_values) + if time_values(startCounter) >= startTime + startIdxNew = startCounter; + break; + end + end + + for endCounter = endIdxNew:numel(time_values) + if time_values(endCounter) - endTime > 1e-10 + endIdxNew = max(endCounter-1, 1); + break; + end + end + + if endCounter == numel(time_values) + endIdxNew = endCounter; + end + + % There is no point beyond the start point + % => Set end index to same as start index + if endIdxNew < startIdxNew + endIdxNew = startIdxNew; + end + + timeIntervalIndexNew = startIdxNew:endIdxNew; + partialTimeNew = time_values(timeIntervalIndexNew); + partialValarrayNew = valarray(timeIntervalIndexNew); + + partialRob = PartialTimedSensitivity(partialTimeNew, partialValarrayNew); + trajsSensitive(valIndex) = partialRob; + + if valIndex > 2 + if time_values(valIndex) == time_values(valIndex - 1) ... + && valarray(valIndex) == valarray(valIndex - 1) + indicesToRemove = [indicesToRemove valIndex]; %#ok<*AGROW> + end + end + +end +% +% % Remove subsequent indices that are identical in both time and value +% valarray(indicesToRemove) = []; +% time_values(indicesToRemove) = []; + +end + +function partialSensitivity = PartialTimedSensitivity(time_values, valarray) + +partialSensitivity = any(valarray); + +end + diff --git a/@STL_Formula/disp.m b/@STL_Formula/disp.m index 9eb35dca..f8c3f5d1 100644 --- a/@STL_Formula/disp.m +++ b/@STL_Formula/disp.m @@ -31,6 +31,13 @@ % Synopsis: st = form_string(phi, opt) % +if opt==2 + opt = -2; +elseif opt==-2 + st = phi.id; + return +end + switch(phi.type) case 'predicate' if(opt == 0 || ~isempty(regexp(phi.id,'.+__$', 'once'))) diff --git a/@STL_Formula/private/generic_predicate.m b/@STL_Formula/private/generic_predicate.m index d6f1592e..919aaf44 100644 --- a/@STL_Formula/private/generic_predicate.m +++ b/@STL_Formula/private/generic_predicate.m @@ -55,7 +55,12 @@ lval = abs(ltr(val, dt__)); sval = sign(val); val = sval.*min([rval; lval]); - end + end + if isfield(BreachGlobOpt, 'NormalizePredicates') + if BreachGlobOpt.NormalizePredicates + val = normalize_rob(val); + end + end end return; end @@ -84,19 +89,10 @@ '\{(.+?)\}[.+?]']); SigList = unique(cat(2,tokens{:})); -% JOHAN ADDED -% To make sure that "alw_" cannot be extracted as a predicate, -% we do this: -% alwIdx = find(strcmp(SigList, 'alw_')); -% if ~isempty(alwIdx) -% SigList(alwIdx) = []; -% end -% END JOHAN ADDED for ii_var = 1:numel(SigList) pcurr = SigList{ii_var}; i_var = FindParam(Sys, pcurr); - - + % test if current variable is found at the beginning of the predicate [start_idx, end_idx, ~, matches, tokens] = regexp(fn_, ['^' pcurr '\[(.+?)\]']); @@ -192,8 +188,25 @@ rval = abs(rtr(val, dt__)); lval = abs(ltr(val,dt__)); sval = sign(val); - val = sval.*(rval+lval)/2; - end + val = sval.*(rval+lval)/2; + end +end +if isfield(BreachGlobOpt, 'NormalizePredicates') + val = normalize_rob(val); end + end + + +function val = normalize_rob(val) + % normalize values into the range [-1, +1] by scaling by + % max(abs(min),abs(max)) + scaling_factor = max(abs(min(val)), abs(max(val))); + if scaling_factor == 0 + % If all values are 0, scaling_factor = 0 + % Avoid division by zero by just returning val as it is + return + end + val = val/scaling_factor; +end \ No newline at end of file diff --git a/@STL_Formula/tree_disp.m b/@STL_Formula/tree_disp.m new file mode 100644 index 00000000..65703532 --- /dev/null +++ b/@STL_Formula/tree_disp.m @@ -0,0 +1,34 @@ +function [st, st_ids, not_expanded] = tree_disp(phi,l, l_max) + phis= get_children(phi); + prefix= ''; + if l>0 + prefix = [repmat(' ', 1, l-1) '|-']; + end + if nargin<3 + l_max =inf; + end + + st_id = get_id(phi); + if isempty(phis) + st = {[prefix disp(phi,0)]}; + st_ids = {st_id}; + not_expanded = {[]}; + elseif numel(phis)==1 + [st1, st_ids1, not_expanded1] = tree_disp(phis{1}, l+1, l_max); + st = [ {[prefix disp(phi,2)]}; st1]; + st_ids = [ st_id; st_ids1]; + not_expanded = [{[]};not_expanded1]; + elseif l>l_max + st = {[prefix st_id]} ; + st_ids = {st_id}; + not_expanded={phi}; + else + [st1, st_ids1, not_expanded1] = tree_disp(phis{1}, l+1, l_max); + [st2, st_ids2, not_expanded2] = tree_disp(phis{2}, l+1, l_max); + + st = [ {[prefix disp(phi,2)]}; st1;st2]; + st_ids = [ st_id; st_ids1;st_ids2]; + not_expanded = [{[]} ;not_expanded1;not_expanded2]; + end + +end \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dd91d652..37fc99c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +# Release 1.10.0 +- updated README.md +- **really** updated README.md +- like, now, it might be worth reading +- like, it even has an example of BreachSystem with a custom sim function +- and more details about BreachTraceSystem for monitoring data +- though there had to be some fixes in those two classes +- also minor changes in demo files +- plus minor things I don't remember + +# Release 1.9.1 + +- Fixed demo BrDemo.from_file_signal_gen +- BreachTraceSystem new method GenTraceIdx + # Release 1.9.0 - New solver: snobfit diff --git a/Core/Algos/@BreachProblem/BreachProblem.m b/Core/Algos/@BreachProblem/BreachProblem.m index fc18eab6..58045fa8 100644 --- a/Core/Algos/@BreachProblem/BreachProblem.m +++ b/Core/Algos/@BreachProblem/BreachProblem.m @@ -119,10 +119,18 @@ end + % callbacks + + properties + callback_obj % called after each objective computation + freq_update=1 % affects display and callbacks + is_paused = false + end + + % misc options properties - display = 'on' - freq_update = 1 + display = 'on' use_parallel = 0 max_time = inf time_start = tic @@ -501,6 +509,20 @@ function set_stochastic_params(this, sparams, sdomains) solver_opt.start_function_values = []; solver_opt= varargin2struct_breach(solver_opt, varargin{:}); + this.display = 'off'; + this.solver_options = solver_opt; + end + + function solver_opt = setup_adaptive_corners(this, varargin) + % Adaptive corners will shut down if no new falsification happens in + % (relative_threshold)*(num_corners) consecutive simulations. + this.solver = 'adaptive_corners'; + solver_opt.lb = this.lb; + solver_opt.ub = this.ub; + solver_opt.relative_threshold = 0.25; + solver_opt.num_corners = 100; % Arbitrary, make sure to change + solver_opt= varargin2struct_breach(solver_opt, varargin{:}); + this.display = 'off'; this.solver_options = solver_opt; end @@ -835,7 +857,10 @@ function set_stochastic_params(this, sparams, sdomains) res = struct('bestRob',[],'bestSample',[],'nTests',[],'bestCost',[],'paramVal',[],'falsified',[],'time',[]); res.bestSample = xbest; res.bestRob = fbest; - + + case 'adaptive_corners' + res = this.solve_adaptive_corners(); + otherwise res = feval(this.solver, problem); this.add_res(res); @@ -956,7 +981,7 @@ function SaveInCache(this) end - % check the MIP options for suppoted solvers and change the this.params + % check the MIP options for supported solvers and change the this.params function setup_mixed_int_optim(this, method) if ~exist('method')||isempty(method) method = 'map_enum_to_int'; @@ -1116,6 +1141,13 @@ function SetupDiskCaching(this, varargin) % update status if ~rem(this.nb_obj_eval,this.freq_update) this.display_status(); + % callback + if ~isempty(this.callback_obj) + e.name ='obj_computed'; + e.values.fval = fval; + e.values.nb_obj_eval=this.nb_obj_eval; + this.callback_obj(this, e); + end end end @@ -1182,7 +1214,8 @@ function SetupDiskCaching(this, varargin) function b = stopping(this) b = (this.time_spent >= this.max_time) ||... (this.nb_obj_eval>= this.max_obj_eval) || ... - (this.num_consecutive_constraints_failed >= this.max_consecutive_constraints_failed); + (this.num_consecutive_constraints_failed >= this.max_consecutive_constraints_failed)||... + this.is_paused; end %% Misc methods diff --git a/Core/Algos/@BreachProblem/solve_adaptive_corners.m b/Core/Algos/@BreachProblem/solve_adaptive_corners.m new file mode 100755 index 00000000..527acb56 --- /dev/null +++ b/Core/Algos/@BreachProblem/solve_adaptive_corners.m @@ -0,0 +1,109 @@ +function res = solve_adaptive_corners(this, varargin) + +BrC = BreachSet(this.params); +for ip = 1:numel(this.params) + BrC.SetDomain(this.params{ip}, this.BrSys.GetDomain(this.params{ip})); +end + +num_corners = min(this.max_obj_eval,this.solver_options.num_corners); + +% Creates BreachSet with one param per group +sigs = this.BrSys.InputGenerator.GetAllSignalsList(); +grouparams = this.params; +groupinputs_reps = {}; +ig=1; +for is = 1:numel(sigs) + groupin = intersect(this.BrSys.expand_param_name([sigs{is} '_']), this.params); + if ~isempty(groupin) + groupinputs{ig} = groupin; + groupinputs_reps{ig} = [sigs{is} '_group']; + grouparams = setdiff(grouparams, groupinputs{ig}); + ig = ig+1; + end +end +if isempty(grouparams) + BrC_group = BreachSet(groupinputs_reps); +else + BrC_group = BreachSet([grouparams groupinputs_reps]); % adds remaining params to group params +end + +% Sample group BreachSet +gparams= BrC_group.GetParamList(); +for ig = 1:numel(gparams) + BrC_group.SetDomain(gparams{ig}, BreachDomain('enum', [1 2], [1 2])); +end +BrC_group.CornerSample(num_corners); + +% Extract concrete corners +X0 = zeros(numel(this.params), size(BrC_group.P.pts, 2)); +if ~isempty(grouparams) % TEST ME! + for ig = 1:numel(grouparams) + idx = strcmp(this.params, grouparams{ig}); + which_corn = BrC_group.GetParam(grouparams{ig}); + corn_vals = [this.lb(idx) this.ub(idx)]; + X0(idx,:) = arrayfun(@(c)(corn_vals(c)), which_corn); + end +end +for ig = 1:numel(groupinputs_reps) + which_corn = BrC_group.GetParam(groupinputs_reps{ig}); + for ip = 1:numel(groupinputs{ig}) + idx = strcmp(this.params, groupinputs{ig}{ip}); + corn_vals = [this.lb(idx) this.ub(idx)]; + X0(idx,:) = arrayfun(@(c)(corn_vals(c)), which_corn); + end +end +if size(X0,2) this.solver_options.relative_threshold*num_corners + fprintf(['Iter ' num2str(xCounter) ': ' ... + 'No new falsified reqs for ' ... + num2str(samplesSinceLastFalsification) ... + ' samples - stopping adaptive_corners falsification ...\n']); + break + end + + end + + % Create a return structure similar to solve_corners.m + [fbest, ibest] = min(min(allFval)); + res = struct('BrSys', this.BrSys, 'X0',X0(:, 1:xCounter),'x',X0(:,ibest),'f', fbest, 'fval', allFval,'cval',allCval); + +end + + +end \ No newline at end of file diff --git a/Core/Algos/@BreachProblem/solve_corners.m b/Core/Algos/@BreachProblem/solve_corners.m index 48e8497a..6ed5dd9d 100644 --- a/Core/Algos/@BreachProblem/solve_corners.m +++ b/Core/Algos/@BreachProblem/solve_corners.m @@ -12,7 +12,11 @@ if this.solver_options.group_by_inputs % Creates BreachSet with one param per group - sigs = this.BrSys.InputGenerator.GetAllSignalsList(); + try + sigs = this.BrSys.InputGenerator.GetAllSignalsList(); + catch + sigs = {}; + end grouparams = this.params; groupinputs_reps = {}; ig=1; diff --git a/Core/Algos/ComputeMorrisSensi.m b/Core/Algos/ComputeMorrisSensi.m index 8ca41127..35231eea 100644 --- a/Core/Algos/ComputeMorrisSensi.m +++ b/Core/Algos/ComputeMorrisSensi.m @@ -4,7 +4,6 @@ % Note: if B is a BreachSimulinkSystem with no traces, we compute the % Morris samples and corresponding traces and stores them in B. If B % already contains Morris samples and traces they are not re-computed. - if nargin < 4 randomSeed = 1; end @@ -46,9 +45,14 @@ [res{ir}.mu, res{ir}.mustar, res{ir}.sigma, ... res{ir}.sigmastar, res{ir}.EE] = ... EEffects(res{ir}.rob, B.P.D, opt.size_grid); - %res{objFunctionCounter, ir}.R = R; - %fprintf(['\nSensitivities for ' R.req_monitors{ir}.name]); - %display_morris_result(res{objFunctionCounter, ir}); + + % Also add the 'D' matrix to res, so that we later on can check which + % parameter was changed at which simulation + res{ir}.D = B.P.D; end end + + + + diff --git a/Core/Algos/FalsificationProblem.m b/Core/Algos/FalsificationProblem.m index 6fc26b2a..86bfbfc5 100644 --- a/Core/Algos/FalsificationProblem.m +++ b/Core/Algos/FalsificationProblem.m @@ -139,6 +139,7 @@ function SaveInCache(this) if this.BrSys.UseDiskCaching FileSave = [this.BrSys.DiskCachingRoot filesep 'FalsificationProblem_Runs.mat']; varname = this.whoamI; + warning('off','MATLAB:Figure:FigureSavedToMATFile'); if ~evalin('base', ['exist(''' varname ''', ''var'')']) assignin('base', varname,this); evalin('base', ['save(''' FileSave ''',''' varname ''');']); @@ -146,7 +147,7 @@ function SaveInCache(this) else evalin('base', ['save(''' FileSave ''',''' varname ''');']); end - + warning('on','MATLAB:Figure:FigureSavedToMATFile'); end end diff --git a/Core/BreachDomain.m b/Core/BreachDomain.m index ffd37c4d..626007b0 100644 --- a/Core/BreachDomain.m +++ b/Core/BreachDomain.m @@ -58,7 +58,10 @@ end case {'enum'} this.type = type; - if isnumeric(domain)&& size(domain, 1) ==1 + if isnumeric(domain)&& (size(domain, 1) ==1|| size(domain, 2) ==1) + if size(domain, 2) ==1 + domain = domain'; + end this.enum = domain; this.domain = [min(domain) max(domain)]; else diff --git a/Core/BreachOpenSystem.m b/Core/BreachOpenSystem.m index 8d6527d5..1e5d7a56 100644 --- a/Core/BreachOpenSystem.m +++ b/Core/BreachOpenSystem.m @@ -33,7 +33,7 @@ function Sim(this,tspan,U) this.CheckinDomainParam(); if this.use_precomputed_inputs % Input generator drives the thing - ig_params = this.InputGenerator.GetSysParamList(); + ig_params = this.InputGenerator.GetParamList(); all_pts_u = this.InputGenerator.GetParam(ig_params); this.SetParam(ig_params, all_pts_u); end @@ -52,8 +52,8 @@ function Sim(this,tspan,U) if isnumeric(U) DimU = this.InputMap.Count(); - if size(U, 2)~=DimU+1; - err_msg= fprintf('Input must be an array with %d columns, first one being time.',DimU); + if size(U, 2)~=DimU+1 + err_msg= sprintf('Input must be an array with %d columns, first one being time.',DimU); error(err_msg); end Us.t = U(:,1); @@ -187,6 +187,12 @@ function SetInputGen(this, IG, varargin) end end + % if IG is a BreachTraceSystem with no index list, generate it + if isempty(IG.GetSysParamList) + IG.GenTraceIdx('input_trace_idx'); + end + + this.InputGenerator = IG; % Adds parameters for new input generator @@ -198,8 +204,7 @@ function SetInputGen(this, IG, varargin) this.SignalRanges = []; this.P = CreateParamSet(this.Sys); this.P.epsi(:,:) = 0; - - + % Sets the new input function for ComputeTraj % FIXME?: tilde? this.Sys.init_u = @(~, pts, tspan) (InitU(this,pts,tspan)); @@ -216,7 +221,7 @@ function SetInputGen(this, IG, varargin) % Copy or init ParamSrc - %% Init param sources, if not done already + %% Init param sources, if not done already for ip = IG.P.DimX+1:numel(IG.P.ParamList) p =IG.P.ParamList{ip}; if IG.ParamSrc.isKey(p) @@ -230,7 +235,6 @@ function SetInputGen(this, IG, varargin) if opt.SetInputGenTime this.SetTime(IG.GetTime()); end - % Restore env and prop parameters if ~isempty(PropParams) @@ -244,6 +248,14 @@ function SetInputGen(this, IG, varargin) % Final checkin this.CheckinDomain(); + % if IG is a trace domain, use_precomputed_inputs is true by + % default + if isa(IG, 'BreachTraceSystem') + this.use_precomputed_inputs = true; + else + this.use_precomputed_inputs = false; + end + end function [params, idx] = GetPlantParamList(this) @@ -371,8 +383,7 @@ function SetDomainCfg(this, cfg) else val = this.GetParam(p); end - - + this.SetDomain(p,typ,dom); this.SetParam(p, val); [~, found] = FindParam(IG.P, p); diff --git a/Core/BreachRandomSys.m b/Core/BreachRandomSys.m new file mode 100644 index 00000000..2595a9e2 --- /dev/null +++ b/Core/BreachRandomSys.m @@ -0,0 +1,54 @@ +classdef BreachRandomSys < BreachSignalGen +%BreachRandomSys Creates a random system from control point signal +%generator + + methods + function this = BreachRandomSys(sigs, methods, ntraces) + if isnumeric(sigs) + nsigs = sigs; + sigs = {}; + for isig=1:nsigs + sigs{isig}= ['x' num2str(isig)]; + end + elseif ischar(sigs) + sigs= {sigs}; + end + nsigs=numel(sigs); + + if ~exist('methods','var')||isempty(methods) + methods= 'spline'; + end + + sg = random_signal_gen(sigs, methods); + this.InitSignalGen({sg}); + + if exist('ntraces','var') + %TODO + %this.SetParam(); + end + + end + + + function GenSim(this, n, seed, time) + % Computes n signals with seed + if nargin<2 + n=1; + end + if nargin<3 + seed = 0; + end + if nargin<4 + time = 0:.01:5; + end + + seed_params = this.expand_param_name('seed'); + num_seed_val = numel(seed_params)*n; + values = reshape(seed+1:seed+num_seed_val, numel(seed_params), n); + this.SetParam(seed_params, values); + this.Sim(time); + end + + + end +end \ No newline at end of file diff --git a/Core/BreachRequirement.m b/Core/BreachRequirement.m index 44ef96d8..8a3995dc 100644 --- a/Core/BreachRequirement.m +++ b/Core/BreachRequirement.m @@ -24,27 +24,44 @@ function this = BreachRequirement(req_monitors, postprocess_signal_gens, precond_monitors) this = this@BreachTraceSystem({}, [], {'data_trace_idx_'}); - if nargin>0 - % Adds requirement monitors, at least one - this.req_monitors = {}; - this.AddReq(req_monitors); - - % Add output gens - this.postprocess_signal_gens={}; - if exist('postprocess_signal_gens', 'var')&&~isempty(postprocess_signal_gens) - this.AddPostProcess(postprocess_signal_gens); - end - - % precondition requirements - this.precond_monitors = {}; - if exist('precond_monitors', 'var')&&~isempty(precond_monitors) - this.AddPreCond(precond_monitors); + % Adds requirement monitors, at least one + this.req_monitors = {}; + + if nargin>=1 + if strcmp(req_monitors,'random') + switch nargin + case 2 + this.AddRandReq(postprocess_signal_gens); + postprocess_signal_gens = {}; + case 3 + this.AddRandReq(postprocess_signal_gens, precond_monitors); + postprocess_signal_gens = {}; + precond_monitors = {}; + otherwise + this.AddRandReq(); + end + else + this.AddReq(req_monitors); end - - % Reset signal map and figure out what signals are required input signals - this.ResetSigMap(); + else + this.AddRandReq(); + end + + % Add output gens + this.postprocess_signal_gens={}; + if exist('postprocess_signal_gens', 'var')&&~isempty(postprocess_signal_gens) + this.AddPostProcess(postprocess_signal_gens); + end + + % precondition requirements + this.precond_monitors = {}; + if exist('precond_monitors', 'var')&&~isempty(precond_monitors) + this.AddPreCond(precond_monitors); end + % Reset signal map and figure out what signals are required input signals + this.ResetSigMap(); + end function AddReq(this, req_monitors) @@ -52,11 +69,31 @@ function AddReq(this, req_monitors) [~, monitors] = get_monitors(req_monitors); for ifo = 1:numel(monitors) this.AddOutput(monitors{ifo}); + monitors{ifo}.R = this; end this.req_monitors = [this.req_monitors monitors]; this.signals_in = this.get_signals_in(); end + function AddRandReq(this, n, Ops) + % Adds n random stl formula with given operators + if nargin == 1 + st_phi = rand_formula(1); + this.AddReq(st_phi); + else + if nargin<2 + n = 1; + end + if ~exist('Ops','var')||isempty(Ops) + Ops = {'and', 'ev', 'evI', 'alw'}; + end + st_phi = rand_formula(n,Ops); + this.AddReq(st_phi); + end + + end + + function AddPostProcess(this, postprocess_signal_gens) if ~iscell(postprocess_signal_gens) @@ -168,6 +205,29 @@ function ResetSimulations(this) this.BrSet =[]; end + function isSensitive = ... + evalStructuralSensitivity(this, traj_index1, traj_index2, this_monitor) + + X1 = this.GetSignalValues(this_monitor.signals_in, traj_index1); + X2 = this.GetSignalValues(this_monitor.signals_in, traj_index2); + + if all(all(X1 == X2)) + isSensitive = 0; + return + end + + idx_par_req = FindParam(this.P, this_monitor.params); + + % We only take p_in and time from traj1 - assume they are same + % as traj2 + p_in = this.P.traj{traj_index1}.param(1, idx_par_req)'; + time = this.P.traj{traj_index1}.time; + + + isSensitive = ... + this_monitor.get_structural_sensitivity(time, X1, X2, p_in); + end + function [global_val, traces_vals, traces_vals_precond, traces_vals_vac] = Eval(this, varargin) % BreachRequirement.Eval returns evaluation of the requirement - % compute it for all traces available and returns min (implicit @@ -190,14 +250,14 @@ function ResetSimulations(this) % evalTrace new= this.getBrSet(varargin{:}); if new - num_traj = numel(this.P.traj); - traces_vals = nan(num_traj, numel(this.req_monitors)); - traces_vals_vac = nan(num_traj, numel(this.req_monitors)); - traces_vals_precond = nan(num_traj, numel(this.precond_monitors)); + num_eval = this.GetNbParamVectors();% numel(this.P.traj); + traces_vals = nan(num_eval, numel(this.req_monitors)); + traces_vals_vac = nan(num_eval, numel(this.req_monitors)); + traces_vals_precond = nan(num_eval, numel(this.precond_monitors)); % eval pre conditions if ~isempty(this.precond_monitors) - for it = 1:num_traj + for it = 1:num_eval for ipre = 1:numel(this.precond_monitors) req = this.precond_monitors{ipre}; traces_vals_precond(it, ipre) = eval_req(this,req,it); @@ -207,10 +267,10 @@ function ResetSimulations(this) % eval requirement execTimesForThisReq = zeros(1, numel(this.req_monitors)); - for it = 1:num_traj + for it = 1:num_eval currentTime = datestr(now, 'HH:MM:ss'); - if num_traj > 30 && (mod(it, 10) == 0) - fprintf(['*** START traj ' num2str(it) '/' num2str(num_traj) ' at ' currentTime '\n']); + if num_eval > 30 && (mod(it, 10) == 0) + fprintf(['*** START traj ' num2str(it) '/' num2str(num_eval) ' at ' currentTime '\n']); end if any(traces_vals_precond(it,:)<0) @@ -231,7 +291,7 @@ function ResetSimulations(this) % Display the nSlowest slowest specifications nSlowest = 5; - if (numel(execTimesForThisReq) > nSlowest) && (num_traj > 30) + if (numel(execTimesForThisReq) > nSlowest) && (num_eval > 30) fprintf([' Finished all trajs, ' num2str(nSlowest) ' slowest specs (out of ' num2str(numel(this.req_monitors)) '): ']); [sortedExecTimes, sortedSpecIndex] = sort(execTimesForThisReq, 'descend'); for slowestCounter = 1:nSlowest @@ -333,7 +393,7 @@ function ResetSimulations(this) end end for ia = 1:numel(F.Axes) - F.update_legend(F.Axes(ia)); + F.update_legend(F.Axes(ia).ax); end @@ -489,6 +549,7 @@ function ResetSimulations(this) end end end + function [X, idxR] = GetSignalValues(this,varargin) % GetSignalValues if not found, look into BrSet nb_traj = 0; @@ -576,16 +637,39 @@ function ResetSimulations(this) end end - function PlotRobustSat(this, varargin) - this.BrSet.PlotRobustSat(varargin{:}); + function [time, rob] = GetRobustSat(this,req,trace_num, expr) + if nargin <= 1 + req = this.req_monitors{1}; + elseif isnumeric(req) + req = this.req_monitors{req}; + elseif ischar(req) + req = this.get_req_from_name(req); + end + assert(isa(req, 'stl_monitor')); + + if nargin <= 2 + trace_num = 1; + end + traj = this.P.traj{trace_num}; + t = traj.time; + idx_par_req = FindParam(this.P, req.params); + p_in = traj.param(1, idx_par_req); + Xin = this.GetSignalValues(req.signals_in,trace_num); + req.init_tXp(t,Xin,p_in); + phi_tmp = STL_Formula('phi_tmp__', expr); + IA_flag = false; + [time,rob] = req.get_standard_rob(phi_tmp,t,IA_flag); + end - function req = get_req_from_name(this, req_name) + function [req, idx_req] = get_req_from_name(this, req_name) req = []; + idx_req = 0; for ir = 1:numel(this.precond_monitors) if strcmp(this.precond_monitors{ir}.name, req_name) req = this.precond_monitors{ir}; + idx_req = -ir; return; end end @@ -593,6 +677,7 @@ function PlotRobustSat(this, varargin) for ir = 1:numel(this.req_monitors) if strcmp(this.req_monitors{ir}.name, req_name) req = this.req_monitors{ir}; + idx_req = ir; return; end end @@ -1148,8 +1233,9 @@ function Concat(this,other,fast) B.SetupParallel(); end - B.Sim(); - + if isa(B, 'BreachSystem') + B.Sim(); + end % initialize or reset traces num_pts = size(B.P.pts,2); @@ -1159,6 +1245,8 @@ function Concat(this,other,fast) itrajs = 1:num_pts; end + % Note: for requirements with no signal output, we could do + % without trajR, but will see later... for it =1:num_pts trajR = struct(); trajR.param = zeros(1,this.Sys.DimX); @@ -1169,11 +1257,14 @@ function Concat(this,other,fast) else trajR.param = [trajR.param B.P.pts(idxB_paramR,it)']; end - trajR.time = B.P.traj{itrajs(it)}.time; + if B.hasTraj() + trajR.time = B.P.traj{itrajs(it)}.time; + else + trajR.time = [0 1]; % some default time, not sure where else to pick a time vector + end trajR.X = NaN(this.Sys.DimX, numel(trajR.time)); this.AddTrace(trajR); end - end function [val, val_vac, traj] = pareval_req(this, req, traj, it) @@ -1213,12 +1304,12 @@ function Concat(this,other,fast) end function [val, val_vac] = eval_req(this, req, it) - val_vac = NaN; - + val_vac = NaN; time = this.P.traj{it}.time; idx_sig_req = FindParam(this.P, req.signals); idx_par_req = FindParam(this.P, req.params); p_in = this.P.traj{it}.param(1, idx_par_req)'; + if ~isempty(req.signals_in) Xin = this.GetSignalValues(req.signals_in, it); else @@ -1241,6 +1332,7 @@ function Concat(this,other,fast) if ~isempty(idx_sig_req) [val , this.P.traj{it}.time, Xout, val_vac] ... = this.evalRequirement(req, time, Xin, p_in); + this.P.traj{it}.X( idx_sig_req,:) = Xout; else [val, ~, ~, val_vac] = this.evalRequirement(req, time, Xin, p_in); diff --git a/Core/BreachSet.m b/Core/BreachSet.m index fcf3b0bd..b9d879fa 100644 --- a/Core/BreachSet.m +++ b/Core/BreachSet.m @@ -99,21 +99,34 @@ function SetP(this, P) this.sigMapInv = containers.Map(); this.AliasMap = containers.Map(); - this.EpsGridMapObj = containers.Map('UniformValues',false); - this.DeltaGridMapObj = containers.Map('KeyType','char','ValueType','int32'); - + this.EpsGridMapObj = containers.Map(); + this.DeltaGridMapObj = containers.Map(); + + if nargin>=1 && ischar(Sys) + Sys= {Sys}; + end + + switch nargin case 0 return; case 1 if isaSys(Sys) - this.P = CreateParamSet(Sys); + this.P = CreateParamSet(Sys); elseif iscell(Sys) % assumes parameter names Sys = CreateSystem({}, Sys, zeros(1, numel(Sys))); this.P = CreateParamSet(Sys); end case 2 - this.P = CreateParamSet(Sys, params); + if isaSys(Sys) + this.P = CreateParamSet(Sys,params); + elseif iscell(Sys) % assumes parameter names + ranges = params; + params = Sys; + Sys = CreateSystem({}, Sys, zeros(1, numel(Sys))); + this.P = CreateParamSet(Sys,params,ranges); + this.SetParamRanges(params,ranges); + end case 3 this.P = CreateParamSet(Sys, params, ranges); end @@ -241,40 +254,100 @@ function SetDomain(this, params, type, domain, enum) end function CheckinDomain(this) - % BreachSet.CheckinDomain() Enforce parameters and signals to - % adhere to their domains + % BreachSet.CheckinDomain() Enforce parameters to adhere to their domains this.CheckinDomainParam(); this.CheckinDomainTraj(); end + function CheckinDomainTraj(this) + % BreachSet.CheckinDomainTraj() Enforce signals to adhere to their domains + + if this.hasTraj() + for itraj = 1:numel(this.P.traj) + for i=1:this.P.DimX + if ~isequal(this.Domains(i).type, 'double')||~isempty(this.Domains(i).domain) + this.P.traj{itraj}.X(i,:) = this.Domains(i).checkin(this.P.traj{itraj}.X(i,:)); + end + end + end + end + end + function CheckinDomainParam(this) pts = this.P.pts; if numel(this.Domains)< size(pts,1) this.Domains(size(pts,1)) = BreachDomain(); end - for i =this.P.DimX+1:size(pts,1) + for i=this.P.DimX+1:size(pts,1) if ~isequal(this.Domains(i).type, 'double')||~isempty(this.Domains(i).domain) pts(i,:) = this.Domains(i).checkin(pts(i,:)); end + end + this.P.pts = pts; + end + + function Bg = GridFilter(this, delta) + % Bg = this.GridFilter(delta) + % + % delta is a number of sample per dimensions, either vector or scalar + % + + [params, idx_params] = this.GetVariables(); + if ~isempty(params) + if isscalar(delta) + delta = repmat(delta, 1, numel(params)); + elseif numel(delta)~=numel(params) + error('delta should be the same size as the number of variable parameters in the set.'); + end + %Bg = BreachSet(params); + for ip = 1:numel(params) + p = params{ip}; + + this_domain = this.Domains(idx_params(ip)+this.P.DimX); + if ~isequal(this_domain.type,'double') % shall strikes back at me when double is not the only non integer domain... + grid_domain(ip) = this_domain; + else + dom = this_domain.domain; + dom = linspace(dom(1),dom(2), delta(ip)); % delta samples in dim ip + grid_domain(ip) = BreachDomain('enum',dom); + end + % end - - this.P.pts = pts; - end - function CheckinDomainTraj(this) - % BreachSet.CheckinDomainTraj() Enforce signals to adhere to their domains - - if this.hasTraj() - for itraj = 1:numel(this.P.traj) - for i=1:this.P.DimX - if ~isempty(this.Domains(i).domain) - this.P.traj{itraj}.X(i,:) = this.Domains(i).checkin(this.P.traj{itraj}.X(i,:)); - end - end + pts = this.GetParam(params); + bg_params = [params {'count' 'idx'}]; + Bg = BreachSet(bg_params); + Bg.SetDomain(bg_params, [grid_domain BreachDomain('int'), BreachDomain('int')]); + for i_pts = 1:size(pts,2) + pt = pts(:,i_pts); + for i_dim=1:numel(params) + if ~isequal(grid_domain(i_dim).type, 'double')||~isempty(grid_domain(i_dim).domain) + pt(i_dim) = grid_domain(i_dim).checkin(pt(i_dim)); % is a grid point now end end + % pt is now a grid pts, we add it to the map + hash = DataHash(pt); + if Bg.DeltaGridMapObj.isKey(hash) + grid_pt = Bg.DeltaGridMapObj(hash); + grid_pt.count = grid_pt.count+1; + grid_pt.idx(end+1) = i_pts; + else + grid_pt.pt = pt; + grid_pt.count = 1; + grid_pt.idx = i_pts; + end + Bg.DeltaGridMapObj(hash) = grid_pt; + end + grid_pts = Bg.DeltaGridMapObj.values; + num_pts = numel(grid_pts); + pts = zeros(numel(bg_params), num_pts); + for i_pt= 1:num_pts + pts(:, i_pt) = [grid_pts{i_pt}.pt; grid_pts{i_pt}.count ; grid_pts{i_pt}.idx(1)]; end + Bg.SetParam(bg_params,pts); + end + %% Params function SetParam(this, params, values, is_spec_param) @@ -284,9 +357,15 @@ function SetParam(this, params, values, is_spec_param) % several samples and there is only one value, set this value to % all samples. Otherwise, returns an error. + if nargin==2 + values = params; + params = this.GetParamList(); + end + + if (~exist('is_spec_param', 'var')) is_spec_param = false; - end + end ip = FindParam(this.P, params); i_not_sys = find(ip>this.P.DimP); @@ -340,6 +419,15 @@ function SetParam(this, params, values, is_spec_param) this.P.Xf = saved_Xf; end this.P = SetParam(this.P, params, values(:, idx(2,:))); + + elseif ischar(is_spec_param)&&strcmp(is_spec_param, 'append') + + new_values = [GetParam(this.P, params) values]; + this.P.pts = [this.P.pts repmat(this.P.pts(:,end),1, size(values, 2))]; + this.P.epsi= [this.P.epsi repmat(this.P.epsi(:,end),1, size(values, 2))]; + this.P.selected = zeros(1, size(new_values, 2)); + this.P = SetParam(this.P, params, new_values); + else % legacy, i.e., not combine version if num_values==1 || num_values == num_pts this.P = SetParam(this.P, params, values); @@ -357,6 +445,18 @@ function SetParam(this, params, values, is_spec_param) end + function AddParam(this, params,values) + % short for SetParam(..., 'append') + + if nargin == 2 + values = params; + params = this.GetParamList; + end + this.SetParam(params, values, 'append'); + + end + + function SetParamCfg(this, list_cfg) % SetParamCfg applies a cfg structure to set parameters. Struct % must have *char* fields params and values @@ -442,7 +542,12 @@ function SetParamGenItem(this, pg) % create/update domain of input parameters this.SetParam(pg.params, pg.p0, true); - this.SetDomain(pg.params, pg.domain); + if ~isempty(pg.domain) + this.SetDomain(pg.params, pg.domain); + else + domain = repmat(BreachDomain, 1, numel(pg.params)); + this.SetDomain(pg.params, domain); + end % update domain of output parameters if ~isempty(pg.domain_out) @@ -484,6 +589,10 @@ function ApplyParamGens(this, params) end function values = GetParam(this, params, ip) + if nargin==1||isempty(params) + params= this.GetParamList; + end + values = GetParam(this.P,params); if exist('ip', 'var') values = values(:, ip); @@ -521,7 +630,14 @@ function ApplyParamGens(this, params) end end end - + + function RemoveDuplicateParams(this) + params = this.GetVariables(); + [~, i1, ~] = GetUParam(this,params,'stable'); + this.P = Sselect(this.P, i1); + end + + function ResetParamSet(this) % ResetParamSet remove samples and keeps one in the domain this.P = SPurge(this.P); @@ -1089,6 +1205,11 @@ function SampleDomain(this, params, num_samples, method, opt_multi, max_num_samp domains = this.Domains(idx_param); domains = num2cell(domains); % convert array to cell + if isempty(domains) + error('sample:empty_domain', 'Domain to sample is empty or undefined.'); + end + + if ~exist('method')||isempty(method) method = 'rand'; end @@ -1261,7 +1382,8 @@ function PseudoRandomSample(this, nb_sample) end end - %% Concatenation, ExtractSubset - needs some additional compatibility checks... + %% Concatenation, ExtractSubset - needs some additional compatibility checks... + function Concat(this, other, fast) if nargin<=2 fast = false; @@ -1289,6 +1411,38 @@ function SavedTrajectorySample(this, paramValues) %% Plot parameters + function ax= PlotPts(this, params, ax, varargin) + % Simple plot function. + if ~exist('params','var') + params = this.GetParamList(); + end + + if ~exist('ax','var') + ax = gca; + end + + if isempty(varargin) + varargin = {'bx'}; + end + + switch numel(params) + case 1 + values = this.GetParam(params); + axes(ax); + plot(values, 0*values, varargin{:}); + + case 2 + values = this.GetParam(params); + axes(ax); + plot(values(1,:), values(2,:), varargin{:}); + otherwise + params =params(1:3); + values = this.GetParam(params); + axes(ax); + plot3(values(1,:), values(2,:), values(3,:), varargin{:}); + end + end + function PlotParams(this, varargin) % Plot parameters gca; @@ -1815,7 +1969,9 @@ function SortbySat(this) end end end - + +%% Signatures + function [signature, signals, params] = GetSignature(this, signal_list, param_list) % GetSignature returns information about signals and parameters @@ -2047,6 +2203,8 @@ function SortbySat(this) end end end + + %% Stuff function ExportToExcel(this, excel_file) [summary, traces] = this.ExportTracesToStruct(); @@ -2201,8 +2359,7 @@ function ExportToExcel(this, excel_file) varargout{1} = st; end end - - + %% Misc function s= isSignal(this,params) idx_s = FindParam(this.P, params); diff --git a/Core/BreachSimulinkSystem.m b/Core/BreachSimulinkSystem.m index d76aa449..e042a6eb 100644 --- a/Core/BreachSimulinkSystem.m +++ b/Core/BreachSimulinkSystem.m @@ -49,7 +49,7 @@ InitBreach(); if nargin ==0 - return; + return; end if exist('p0', 'var')&&iscell(p0) @@ -209,18 +209,39 @@ function StopParallel(this) end end + function ME=EnableFastRestart(this) + mdl_breach = this.Sys.mdl; + try + load_system(mdl_breach); + set_param(mdl_breach, 'FastRestart', 'on'); + save_system(mdl_breach); + ME=0; + catch ME + warning('BreachSimulinkSystem:no_fast_restart', ['Did not manage to enable fast restart for ' this.Sys.mdl]); + end + end + + %% Interface creation function [sig_in, sig_out, sig_fw, params, sig_build_params] = CreateInterface(this, mdl, params, p0, signals) - %% Copy the model + %% Checks model file + if ~isfile(mdl) + [~,mdl] = fileparts(mdl); + end + try + load_system(mdl); + catch + error('BreachSimulinkSystem:not_a_simulink_model','%s does not exists or is not a valid Simulink filename',mdl); + end + %% Copy the model % Get Breach directory global BreachGlobOpt breach_dir = BreachGlobOpt.breach_dir; breach_data_dir = [breach_dir filesep 'Ext' filesep 'ModelsData' ]; % Give it a name - mdl_breach = [mdl '_breach']; - load_system(mdl); + mdl_breach = [mdl '_breach']; close_system(mdl_breach,0); save_system(mdl,[breach_data_dir filesep mdl_breach]); @@ -1150,106 +1171,6 @@ function Sim(this, tspan, U) end end end - -% function sig_log = FindLoggedSignals(this) -% % -% % converts a simulink output to a data structure Breach can handle -% % -% -% %Run the model for time 0 to check proper initialization and collect signal names -% tspan = evalin('base', 'tspan;'); -% assignin('base','tspan',[0 eps]); -% assignin('base','t__',0); -% assignin('base','u__',zeros(1, numel(this.Sys.InputList))); -% -% simout = sim(this.Sys.mdl); -% assignin('base','tspan',tspan); -% -% %% Outputs and scopes -% Vars = simout.who; -% lenVars = numel(Vars); -% sig_log = {}; -% -% for iV = 1:lenVars -% Y = get(simout,Vars{iV}); -% if ~isempty(Y) -% -% if ~strcmp(Vars{iV}, 'tout')&&~strcmp(Vars{iV},'logsout')&&(isstruct(Y)) -% for iS=1:numel(Y.signals) -% signame = Y.signals(iS).label; -% if ~ismember(signame,sig_log) -% -% nbdim = size(double(Y.signals(iS).values),2); -% if (nbdim==1) -% sig_log = {sig_log{:} signame }; -% else -% for idim = 1:nbdim -% signamei = [signame '_' num2str(idim) '_']; -% sig_log = {sig_log{:} signamei}; -% end -% end -% end -% end -% end -% end -% end -% -% logs = simout.get('logsout'); -% -% if ~isempty(logs) -% logs_names = logs.getElementNames(); -% -% %% logs -% for ilg = 1:numel(logs_names) -% if ~(ismember(logs_names{ilg}, sig_log)) -% signame = logs_names{ilg}; -% if ~ismember(signame,sig_log) -% -% sig = logs.getElement(signame); -% % JOHAN CHANGE -% try -% if sig.numElements > 1 -% sig = get(sig,1); -% end -% catch -% % Do nothing -% end -% -% try -% nbdim = size(sig.Values.Data,2); -% catch -% % Sometimes, this doesn't work -% nbdim = length(fieldnames(sig.Values)); -% end -% -% % NOTE! -% % Do we want to split multidimensional signals -% % or not? -% % For logged signals, currently we do NOT! -% sig_log = {sig_log{:} signame}; -% -% % Alternatively, if we WANT to split them, use -% % the code below INSTEAD: -% -% % naming multidimensional signal= name_signal_i_ -% % if nbdim==1 -% % sig_log = {sig_log{:} signame}; -% % else -% % for idim =1:nbdim -% % signamei = [signame '_' num2str(idim) '_']; -% % sig_log = {sig_log{:} signamei}; -% % end -% % end -% % END JOHAN CHANGE -% -% -% -% -% end -% end -% end -% end -% end function U = InitU(this,pts,tspan) % Computes input values @@ -1265,22 +1186,7 @@ function Sim(this, tspan, U) end end - - % Old function Sim -% function Sim(this, tspan, U) -% switch nargin -% case 1 -% Sim@BreachOpenSystem(this); -% case 2 -% Sim@BreachOpenSystem(this, tspan); -% case 3 -% Sim@BreachOpenSystem(this, tspan, U); -% end -% if this.use_parallel == 0 % don't autosave in parallel mode -% %save_system(this.Sys.mdl); -% end -% end - + %% Misc function S = GetSignature(this, varargin) S = GetSignature@BreachOpenSystem(this, varargin{:}); diff --git a/Core/BreachSystem.m b/Core/BreachSystem.m index e5aa04b9..2a41a9c8 100644 --- a/Core/BreachSystem.m +++ b/Core/BreachSystem.m @@ -4,7 +4,7 @@ % It combines a system structure (Sys) with a parameter set (P) % into one object so that basic operations can be done in one % command instead of several and with fewer arguments. BreachSystem - % class is derivated from BreachSet. Type help BreachSet to view + % class is derived from BreachSet. Type help BreachSet to view % properties and methods of the parent class. % % BreachSystem Properties @@ -35,7 +35,7 @@ methods - %% Constructor + %% Constructor function this = BreachSystem(varargin) InitBreach; this.Specs = containers.Map(); @@ -44,8 +44,7 @@ switch nargin case 0 % do nothing - case 1 % Should be a Sys structure - + case 1 % Should be a Sys structure inSys = varargin{1}; if isaSys(inSys) this.Sys = inSys; @@ -189,22 +188,14 @@ function ResetSampling(this) function SetTime(this,tspan) if ischar(tspan) % if time is an expression, test it in base try - T= evalin('base', tspan); + tspan = evalin('base', tspan); catch - error('BreachSystem:SetTime:undef', 'Cannot evaluate time.expression %s', tspan); - end - elseif isscalar(tspan) % standard case - tspan = [0 tspan]; - if tspan(end)<0 - error('BreachSystem:SetTime:neg_time', 'Cannot set negative time.') + error('BreachSystem:SetTime:undef', 'Cannot evaluate time expression %s', tspan); end - this.Sys.tspan = tspan; else - this.Sys.tspan = tspan; - end - this.Sys.tspan = tspan; + this.P.Sys.tspan = check_sim_time(tspan); + end end - function time = GetTime(this) time = this.Sys.tspan; end @@ -212,7 +203,9 @@ function SetTime(this,tspan) function Sim(this,tspan) % BreachSystem.Sim(time) Performs a simulation from the parameter % vector(s) defined in P - evalin('base', this.InitFn); + if ~isempty(this.InitFn) + evalin('base', this.InitFn); + end this.CheckinDomainParam(); if nargin==1 if this.hasTraj() @@ -227,7 +220,9 @@ function Sim(this,tspan) if this.verbose>=1 this.dispTraceStatus(); end - end + end + + %% Signals Enveloppe @@ -925,7 +920,16 @@ function AddOutput(this, output) % Add parameters pdoms = {}; - [params, ipar] =setdiff(output.params, this.P.ParamList, 'stable'); + if ~isempty( output.params_out) + params = union(output.params, output.params_out, 'stable'); + else + params = output.params; + end + + p0 = [output.p0 nan(numel(output.params_out),1)]; + if ~isempty(params) + [params, ipar] = setdiff(params, this.P.ParamList, 'stable'); + end if ~isempty(params) for par = params if output.domains.isKey(par{1}) @@ -935,7 +939,7 @@ function AddOutput(this, output) end end - this.Sys.p = [this.Sys.p ;output.p0(ipar)']; + this.Sys.p = [this.Sys.p ; p0(ipar)']; this.Sys.ParamList = [this.Sys.ParamList params]; this.Sys.DimP = this.Sys.DimP+numel(params); @@ -1058,7 +1062,8 @@ function assignin_ws_p0(this) end - %% GUI +%% GUI + function new_phi = AddSpecGUI(this) signals = this.Sys.ParamList(1:this.Sys.DimX); new_phi = STL_TemplateGUI('varargin', signals); @@ -1098,9 +1103,7 @@ function TrajGUI(this) BreachTrajGui(this,args); end - - - + %% Experimental function report = Analysis(this) diff --git a/Core/BreachTraceSystem.m b/Core/BreachTraceSystem.m index 666f64d3..fe3e61c4 100644 --- a/Core/BreachTraceSystem.m +++ b/Core/BreachTraceSystem.m @@ -2,10 +2,6 @@ % BreachTraceSystem a BreachSystem class to handle traces with no % simulator - properties - pts_map = containers.Map() % keeps track of pts - first one if pts has duplicates - end - methods % constructor - takes signal names and an optional trace function this = BreachTraceSystem(signals, trace, params) @@ -14,12 +10,16 @@ return; end - if isscalar(signals) && isnumeric(signals) + if ischar(signals) + signal_names = {signals}; + elseif isscalar(signals) && isnumeric(signals) ndim = signals; signal_names = cell(1,ndim); for is = 1:ndim signal_names{is} = ['x' num2str(is)]; end + + elseif isstruct(signals)&&all(isfield(signals, {'time', 'outputs', 'inputs'})) trace1 = signals; signal_names = [trace1.outputs.names, trace1.inputs.names]; @@ -28,12 +28,12 @@ trace1 = signals; signal_names = trace1.signals.names; elseif all(isfield(signals, {'time', 'X'})) % traj, but no signal names - trace1 = signals; - ndim = size(trace1.X,1); - signal_names = cell(1,ndim); - for is = 1:ndim - signal_names{is} = ['x' num2str(is)]; - end + trace1 = signals; + ndim = size(trace1.X,1); + signal_names = cell(1,ndim); + for is = 1:ndim + signal_names{is} = ['x' num2str(is)]; + end end elseif ischar(signals) @@ -63,7 +63,6 @@ elseif isa(signals,'Simulink.SimulationOutput') [time, X, signal_names] = simout2X(signals); trace = [time' X']; - % default signals should be a cell array of strings else signal_names = signals; @@ -92,9 +91,9 @@ end - function nb_traces= CountTraces(this) - % CountTraces counts number of traces - + function nb_traces= CountTraces(this) + % CountTraces counts number of traces + if isfield(this.P,'traj') nb_traces = numel(this.P.traj); else @@ -102,10 +101,11 @@ end end - function AddTrace(this, trace) - % Add a trace, either from file or from array - % TODO checks dimensions of signals and data + function AddTrace(this, trace, params) + % Add a trace, either from file or from array + % TODO checks dimensions of signals and data + signals = this.GetSignalNames(); if ischar(trace) traj = load_traj(trace); elseif isa(trace,'Simulink.SimulationOutput') @@ -117,12 +117,11 @@ function AddTrace(this, trace) else traj.param = zeros(1, size(trace,2)+1); end - elseif isstruct(trace) + elseif isstruct(trace) if all(isfield(trace,{'time', 'X'})) traj= trace; - elseif all(isfield(trace,{'time', 'outputs', 'inputs'})) % reading one struct obtained from a SaveResult + elseif all(isfield(trace,{'time', 'outputs', 'inputs'})) % reading one struct obtained from a SaveResult traj.time= trace.time; - signals = this.GetSignalNames(); traj.X = zeros(numel(signals),numel(traj.time)); for isig = 1:numel(signals) idx_sig = find(strcmp(trace.inputs.names, signals{isig}),1); @@ -138,40 +137,53 @@ function AddTrace(this, trace) end end - elseif all(isfield(trace,{'time', 'signals'})) % reading one struct obtained from a SaveResult + elseif all(isfield(trace,{'time', 'signals'})) % reading one struct obtained from a SaveResult traj.time= trace.time; signals = this.GetSignalNames(); traj.X = zeros(numel(signals),numel(traj.time)); for isig = 1:numel(signals) idx_sig = find(strcmp(trace.signals.names, signals{isig}),1); - if isempty(idx_sig) - error('BreachTraceSystem:signal_not_found', 'Signal %s not found', signals{isig}); - traj.X(isig,:) = trace.signals.values(idx_sig,:); - end + if isempty(idx_sig) + error('BreachTraceSystem:signal_not_found', 'Signal %s not found', signals{isig}); + end + traj.X(isig,:) = trace.signals.values(idx_sig,:); end end elseif isnumeric(trace) - traj.X = trace(:, 2:end)'; - traj.time = trace(:,1)'; - if size(trace,1) >=1 - traj.param = trace(1,2:end); - else - traj.param = zeros(1, size(trace,2)+1); + try + traj.X = trace(:, 2:end)'; + traj.time = trace(:,1)'; + traj.param = this.Sys.p'; + if size(trace,1) >=1 + traj.param(1:this.Sys.DimX) = trace(1,2:end); + else + traj.param(1:this.Sys.DimX) = zeros(1, size(trace,2)+1); + end + catch + error('BreachTraceSystem:wrong_trace', 'Problem with trace format. Should be of size (N,%d)', this.P.DimX+1); end + elseif isa(trace, 'matlab.io.MatFile') traj = trace; end - nb_traces =this.CountTraces(); if ~isfield(traj, 'param')&&~isa(traj, 'matlab.io.MatFile') - traj.param = [this.Sys.p']; + traj.param = this.Sys.p'; + end + if exist('params', 'var') + num_p =this.P.DimP-this.P.DimX; + if numel(params)~= num_p + error('BreachTraceSystem:wrong_param', 'Wrong number of parameters (last argument), should be %d', this.P.DimP-this.P.DimX); + else + traj.param(this.DimX+1:end) = reshape(params, 1, num_p); + end + end new_pts = traj.param'; if nb_traces == 0 - this.pts_map(DataHash(new_pts)) = 1; Pnew = CreateParamSet(this.Sys); Pnew.epsi(:,:) = 0; Pnew.traj={traj}; @@ -184,21 +196,14 @@ function AddTrace(this, trace) % add pts and epsi this.P.pts(:,end+1) = new_pts; this.P.epsi(:,end+1) = this.P.epsi(:,end); - % checks if new_pts exists - key = DataHash(new_pts); - if this.pts_map.isKey(key) % do not add traj - pts_idx = this.pts_map(key); - this.P.traj_ref(end+1) = this.P.traj_ref(pts_idx); - else % add traj - this.P.traj{end+1} = traj; - this.P.traj_ref(end+1) = numel(this.P.traj); - end + this.P.traj{end+1} = traj; + this.P.traj_ref(end+1) = numel(this.P.traj); end - % FIXME still need to get rid of legacy useless Xf field... - if isa(traj, 'matlab.io.MatFile') % avoid loading matfile for Xf + % FIXME still need to get rid of legacy useless Xf field... + if isa(traj, 'matlab.io.MatFile') % avoid loading matfile for Xf Xf= zeros(1,this.P.DimX); - else + else Xf = traj.X(:,end); end if isfield(this.P, 'Xf') @@ -208,8 +213,46 @@ function AddTrace(this, trace) end end + function GenTraceIdx(this, name) + % GenTraceIdx generate unique index for traces + + if ~exist('name','var')||isempty(name) + name = 'trace_idx'; + end + + [~, name_exists] = FindParam(this.Sys, name); + num_traces = this.CountTraces(); + + if num_traces>=0&&~name_exists + for it = 1:num_traces + pts = this.P.pts(:,it); % WARNING: assumes no traj_ref trick... + traj = this.P.traj{it}; + traj.param= [traj.param it]; + if it == 1 % create new Sys (add trace_idx param) + this.Sys.ParamList = [this.Sys.ParamList name]; + this.Sys.DimP = this.Sys.DimP+1; + this.Sys.p = [this.Sys.p; 1]; + Pnew = CreateParamSet(this.Sys); + Pnew.epsi = [this.P.epsi(:,1) ; 0 ]; + Pnew.traj={traj}; + Pnew.traj_ref = 1; + Pnew.traj_to_compute = []; + Pnew.pts(1:Pnew.DimP,1) = [pts; 1]; + else + % add pts and epsi + Pnew.pts(:,end+1) = [pts; it]; + Pnew.epsi(:,end+1) = [this.P.epsi(:,end); 0]; + Pnew.traj{end+1} = traj; + Pnew.traj_ref(end+1) = numel(this.P.traj); + end + end + this.P = Pnew; + this.Domains(end+1)= BreachDomain('int'); + end + end + function AddRandomTraces(this,n_traces, n_samples, amp, end_time) - % AddRandomTraces Initially used to test monitoring algo + % AddRandomTraces Initially used to test monitoring algo if ~exist('n_traces', 'var') n_traces= 1; end @@ -234,11 +277,11 @@ function AddRandomTraces(this,n_traces, n_samples, amp, end_time) end end - + function Sim(varargin) - % BreachTraceSystem.Sim(varargin) does nothing - traces are added - % using AddTrace method - + % BreachTraceSystem.Sim(varargin) does nothing - traces are added + % using AddTrace method + end function varargout = disp(this) diff --git a/Core/ComputeTraj.m b/Core/ComputeTraj.m index b6c141bf..9f81fef8 100644 --- a/Core/ComputeTraj.m +++ b/Core/ComputeTraj.m @@ -82,10 +82,6 @@ P0 = Sys.init_fun(P0); end -if isfield(P0, 'init_fun') - P0 = P0.init_fun(P0); -end - % if no trajectories to compute, we return the param set itself if(isfield(P0, 'traj_to_compute') && isempty(P0.traj_to_compute)) if isfield(P0, 'traj')&&isfield(P0, 'traj_ref') @@ -162,10 +158,7 @@ rfprintf(['Computed ' num2str(ii) '/' num2str(numel(ipts)) ' simulations of ' model]) end end - - if ischar(tspan) - tspan = evalin('base', tspan); - end + icount = 0; for ii = ipts iref = P0.traj_ref(ii); @@ -209,7 +202,6 @@ end Pf.traj_to_compute = []; -% Pf.traj_ref = 1:numel(Pf.traj); % fill field traj_ref (one to one mapping) case 'Simulink' model = Sys.mdl; diff --git a/Core/CreateExternSystem.m b/Core/CreateExternSystem.m index d3dc6d8c..9861fbfa 100644 --- a/Core/CreateExternSystem.m +++ b/Core/CreateExternSystem.m @@ -59,11 +59,9 @@ end end + Sys.type = 'Extern'; if exist('simfn','var') - Sys.type = 'Extern'; Sys.sim = simfn; - else - Sys.type = 'traces'; end Sys.tspan= 0:.1:1; Sys.Dir = pwd; diff --git a/Core/Gui/BreachGuiClass.m b/Core/Gui/BreachGuiClass.m index ef711b9b..2b5d295d 100644 --- a/Core/Gui/BreachGuiClass.m +++ b/Core/Gui/BreachGuiClass.m @@ -2,7 +2,7 @@ %% Functional properties - title + title uimap output=1 error_msg @@ -11,7 +11,7 @@ %% Default data field properties data_gui - end + end %% statics helpers @@ -21,117 +21,125 @@ if isfield(cfg,field) value = cfg.(field); else - cfg.(field)= value; + cfg.(field)= value; end end end - + methods + %% Constructors function this = BreachGuiClass(title) this.uimap = containers.Map(); if ~exist('title', 'var')||isempty(title) - title = 'GuiClass'; - end - this.title = title; - - %% Creates separators - hs1= this.create_separator('hsep.05'); - hs1.h = 0.05; - - hs2= this.create_separator('hsep.1'); - hs2.h = 0.1; - - hs25 = this.create_separator('hsep.25'); - hs25.h = 0.25; - - hs3= this.create_separator('hsep.5'); - hs3.h = 0.5; - - ws1= this.create_separator('wsep.05'); - ws1.w = 0.05; - - ws2= this.create_separator('wsep.1'); - ws2.w = 0.1; - - this.create_separator('wsep.5', .5,1); - - this.create_separator('fullsep', 1, 1); - %% create scaling invisible button - button_scale = this.create_button('button_scale'); - this.set_by_id('button_scale', 'enable', 'off', 'Position', [0 0 this.wunit this.hunit]); - - - %% Creates default ok and cancel buttons - - button_ok = this.create_button('button_ok','Ok',@(o,e)(this.button_ok_callback(o))); - button_cancel = this.create_button('button_cancel','Cancel',@(o,e)(this.button_cancel_callback())); - - button_ok.w = 0.5; - button_ok.wleft = 0.025; - button_cancel.w = 0.5; - button_cancel.wright = 0.025; - - this.create_group('ok_group', {{'button_cancel', 'button_ok'}; {'hsep.25'}}); - this.create_group('group_ok', {{'button_cancel', 'button_ok'}; {'hsep.25'}}); - - this.reset_top_fig(); - -% this.layout = {{'ok_group'}}; -% this.set_layout(); - + title = 'GuiClass'; + end + this.title = title; + + %% Creates separators + hs1= this.create_separator('hsep.05'); + hs1.h = 0.05; + + hs2= this.create_separator('hsep.1'); + hs2.h = 0.1; + + hs25 = this.create_separator('hsep.25'); + hs25.h = 0.25; + + hs3= this.create_separator('hsep.5'); + hs3.h = 0.5; + + ws1= this.create_separator('wsep.05'); + ws1.w = 0.05; + + ws2= this.create_separator('wsep.1'); + ws2.w = 0.1; + + this.create_separator('wsep.5', .5,1); + + this.create_separator('fullsep', 1, 1); + %% create scaling invisible button + button_scale = this.create_button('button_scale'); + this.set_by_id('button_scale', 'enable', 'off', 'Position', [0 0 this.wunit this.hunit]); + + + %% Creates default ok and cancel buttons + + button_ok = this.create_button('button_ok','Ok',@(o,e)(this.button_ok_callback(o))); + button_cancel = this.create_button('button_cancel','Cancel',@(o,e)(this.button_cancel_callback())); + + button_ok.w = 0.5; + button_ok.wleft = 0.025; + button_cancel.w = 0.5; + button_cancel.wright = 0.025; + + this.create_group('ok_group', {{'button_cancel', 'button_ok'}; {'hsep.25'}}); + this.create_group('group_ok', {{'button_cancel', 'button_ok'}; {'hsep.25'}}); + + this.reset_top_fig(); + this.disable_resizable(); + % this.layout = {{'ok_group'}}; + % this.set_layout(); + + end + + function this = zcallback(this, id, o,e) + % Default/main callback function - does nothing for now + disp(['event from elem:' id]) + disp(e) + disp(o) end function e = create_ui(this,id,g) e = gui_elem(); - e.hdle = g; + e.hdle = g; this.uimap(id)= e; end - + function e = create_separator(this, id,w,h) - if nargin<4 - h=1; - end - if nargin<3 - w=1; - end - e = gui_elem(); - e.w = w; - e.h = h; - this.uimap(id)= e; - - end - - function e = create_axes(this, id, w,h) - if nargin<4 h=1; end if nargin<3 w=1; end + e = gui_elem(); + e.w = w; + e.h = h; + this.uimap(id)= e; + end + + function e = create_axes(this,id, w,h) + + if nargin<4 + h=4; + end + if nargin<3 + w=1; + end e = axes_elem(); e.w = w; e.h = h; - + e.wleft =.1; % internal margins e.wright =.06; e.htop =.5; e.hbot = .5; - - e.hdle = axes(); - this.uimap(id)= e; + + e.hdle = axes(); + this.uimap(id)= e; end - + function e = create_button(this, id, string, callback, w,h) - if nargin < 4 - callback = @(o,e)(0); + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); end - if nargin < 3 - string = [id ': Push Button']; + + if nargin < 3 + string = [id ': Push Button']; end g = uicontrol('Parent',this.hdle,... @@ -143,29 +151,65 @@ 'Callback', callback ... ); - e = button_elem(); + e = button_elem(); if nargin<5 - w =1; + w =1; end if nargin<6 - h =1; - end + h =1; + end + e.w=w; + e.h=h; + + e.hdle = g; + this.uimap(id)= e; + + end + + function e = create_slider(this, id, string, callback, w,h) + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); + end + + if nargin < 3 + string = [id ': Push Button']; + end + + g = uicontrol('Parent',this.hdle,... + 'Style','slider',... + 'String', string,... + 'FontName', this.font_name,... + 'FontSize', this.font_size,... + 'visible', 'off',... + 'Callback', callback ... + ); + + e = slider_elem(); + if nargin<5 + w =1; + end + if nargin<6 + h =1; + end e.w=w; e.h=h; - e.hdle = g; + e.hdle = g; this.uimap(id)= e; end function e = create_checkbox(this, id, string, callback, w,h) - if nargin < 3 - string = [id ': Check Box']; + + if nargin < 3 + string = [id ': Check Box']; end - if nargin <4 - callback = @(o,e)(0); + + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); end + g = uicontrol('Parent',this.hdle,... 'Style','checkbox',... 'String', string ,... @@ -174,29 +218,31 @@ 'Callback', callback,... 'visible', 'off'); - e = checkbox_elem(); + e = checkbox_elem(); if nargin<5 - w =1; + w =1; end if nargin<6 - h =1; - end + h =1; + end e.w=w; e.h=h; - e.hdle = g; + e.hdle = g; this.uimap(id)= e; - + end - + function e = create_radio(this,id, string,callback, w,h) - + if nargin < 3 string = [id ': Check Box']; end - if nargin <4 - callback = @(o,e)(0); + + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); end - + + g = uicontrol('Parent',this.hdle,... 'Style','radiobutton',... 'String', string ,... @@ -205,30 +251,33 @@ 'Callback', callback,... 'visible', 'off'); this.create_ui(id,g); - + e = radio_elem(); if nargin<5 - w =1; + w =1; end if nargin<6 - h =1; - end + h =1; + end e.w=w; e.h=h; - e.hdle = g; - this.uimap(id)= e; + e.hdle = g; + this.uimap(id)= e; end - + function e = create_popup(this,id,string,callback, w,h) - + if nargin < 3 string = [id ': Check Box']; end - if nargin <4 - callback = @(o,e)(0); + + + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); end - + + g = uicontrol('Parent',this.hdle,... 'Style','popupmenu',... 'String', string ,... @@ -237,32 +286,36 @@ 'Callback', callback,... 'visible', 'off'); this.create_ui(id,g); - + e = popup_elem(); if nargin<5 - w =1; + w =1; end if nargin<6 - h =1; - end + h =1; + end e.w=w; e.h=h; e.htop = .15; - e.hdle = g; - this.uimap(id)= e; + e.hdle = g; + this.uimap(id)= e; end function e = create_listbox(this,id,string,callback, w,h) - + if nargin < 3 string = {}; end - if nargin <4 - callback = @(o,e)(0); + + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); end - + + + + g = uicontrol('Parent',this.hdle,... 'Style','listbox',... 'String', string ,... @@ -271,30 +324,32 @@ 'Callback', callback,... 'visible', 'off'); this.create_ui(id,g); - + e = listbox_elem(); if nargin<5 - w =1; + w =1; end if nargin<6 - h = 2; - end + h = 2; + end e.w=w; e.h=h; - e.hdle = g; - this.uimap(id)= e; + e.hdle = g; + this.uimap(id)= e; end - + function e = create_table(this,id, data, callback, w,h) if nargin<3 data = {'',[]}; end - if nargin <4 - callback = []; + + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); end - + + g = uitable('Parent',this.hdle,... 'FontName', this.font_name,... 'FontSize', this.font_size,... @@ -304,18 +359,18 @@ set(g,'CellEditCallback', callback); end - e = table_elem(); + e = table_elem(); if nargin<5 - w =1; + w =1; end if nargin<6 - h =1; - end + h =1; + end e.w=w; - e.h=h; - e.hdle = g; - this.uimap(id)= e; - + e.h=h; + e.hdle = g; + this.uimap(id)= e; + end function e = create_edit(this,id, string, callback, w,h) @@ -323,10 +378,11 @@ if nargin<3 string = ''; end - if nargin <4 - callback = []; + + if ~exist('callback','var')||isempty(callback) + callback = @(o,e)(this.zcallback(id,o,e)); end - + g = uicontrol('Parent',this.hdle,... 'Style','edit',... 'FontName', this.font_name,... @@ -337,20 +393,20 @@ set(g,'Callback', callback); end - e = edit_elem(); + e = edit_elem(); if nargin<5 - w =1; + w =1; end if nargin<6 - h =1; - end + h =1; + end e.w=w; - e.h=h; - e.hdle = g; + e.h=h; + e.hdle = g; this.uimap(id)= e; - + end - + function e = create_text(this,id, string, w,h) if nargin<3 @@ -366,26 +422,26 @@ 'HorizontalAlignment', 'left',... 'visible', 'off'... ); -% 'BackgroundColor', [0.831; 0.816;0.784]... - - e = text_elem(); + % 'BackgroundColor', [0.831; 0.816;0.784]... + + e = text_elem(); if nargin<4 - w =1; + w =1; end if nargin<5 - h =1; - end + h =1; + end e.w=w; e.h=h; e.htop = .15; - e.hdle = g; + e.hdle = g; this.uimap(id)= e; - - end + + end function e = create_panel(this, id, string, layout) if nargin<3 - string = [id ' panel']; + string = [id ' panel']; end p = uipanel('Parent',this.hdle, ... @@ -401,24 +457,24 @@ e.h = h; this.uimap(id)= e; - end - + end + function e = create_group(this, id, layout) [w, h] = get_layout_sz(this, layout); - e = group_elem(layout); + e = group_elem(layout); e.w = w; - e.h = h; + e.h = h; this.uimap(id)= e; end - - %% Callbacks + + %% Callbacks function button_ok_callback(this, hobj) set(hobj, 'String', 'Please wait...') drawnow; close(this.hdle); end - + function button_cancel_callback(this) this.output=[]; close(this.hdle); @@ -428,36 +484,36 @@ function button_cancel_callback(this) %% Layout properties - layout % cell of cells of dimension n x 1 where n is number of rows + layout % cell of cells of dimension n x 1 where n is number of rows font_name = 'Arial' font_size = 11 max_char = 80 - hdle % handle to GUI top dialog window + hdle % handle to GUI top dialog window wunit = 500 - hunit = 50 + hunit = 50 + end methods function resize_callback(this,o,e) - % Empty for now + % Empty for now end function reset_top_fig(this) - this.hdle = figure('Name',this.title, ... - 'Resize', 'on',... + this.hdle = figure('Name',this.title, ... 'Toolbar', 'none',.... 'Menubar', 'none',... 'NumberTitle','off',... 'SizeChangedFcn', @(o,e)(this.resize_callback(o,e))); end - - function set_layout(this,layout, parent, w0,h0,fit) - %% Arguments + + function set_layout(this,layout, parent, w0,h0,fit) + %% Arguments if nargin < 6 - fit = 'fit'; % fits parent figure to layout size and sets units to Normalized, no rescaling + fit = 'fit'; % fits parent figure to layout size and sets units to Normalized, no rescaling end if nargin<5 @@ -467,9 +523,9 @@ function set_layout(this,layout, parent, w0,h0,fit) if nargin<4 w0 = 0; end - + if nargin<3 - parent = this; + parent = this; end if nargin<2 @@ -477,7 +533,7 @@ function set_layout(this,layout, parent, w0,h0,fit) end - %% Get scale + %% Get scale if strcmp(fit, 'fit') if isempty(this.layout) scale = [1 1]; @@ -491,7 +547,7 @@ function set_layout(this,layout, parent, w0,h0,fit) end this.set_for_all('Units', 'pixels'); - + wunit = this.wunit; hunit = this.hunit; @@ -509,7 +565,7 @@ function set_layout(this,layout, parent, w0,h0,fit) % get hmax for current row hmax = 0; for ei = 1:numel(rowcurr) - try + try e = this.uimap(rowcurr{ei}); catch error('element %s not found',rowcurr{ei}); @@ -522,7 +578,7 @@ function set_layout(this,layout, parent, w0,h0,fit) for ei = 1:numel(rowcurr) e = this.uimap(rowcurr{ei}); he = e.h; % height of current elememt - h = hcur+(hmax-he)*hunit; + h = hcur+(hmax-he)*hunit; e.disp_in(this, parent, w, h, wunit, hunit); w = w + e.w*wunit; end @@ -538,7 +594,7 @@ function set_layout(this,layout, parent, w0,h0,fit) pos = old_pos; pos(4) = hmax; pos(3) = wmax; - + % Make sure position of top left corner does not change hpos_old = old_pos(2)+old_pos(4); % pixel h position pos(2) = hpos_old-hmax; @@ -550,16 +606,16 @@ function set_layout(this,layout, parent, w0,h0,fit) % fit parent size, preserve scale and top position old_pos = get(parent.hdle,'Position'); - pos = old_pos; + pos = old_pos; pos(4) = hmax; pos(3) = wmax; - + % Make sure position of top left corner does not change hpos_old = old_pos(2)+old_pos(4); % pixel h position pos(2) = hpos_old-hmax; set(parent.hdle, 'Position', pos); this.layout = layout; - + end end @@ -567,13 +623,13 @@ function set_layout(this,layout, parent, w0,h0,fit) function set_for_all(this, varargin) values = this.uimap.values(); for ei = 1:numel(values) - e = values{ei}; - if ~isempty(e.hdle) - set(e.hdle,varargin{:}); - end + e = values{ei}; + if ~isempty(e.hdle) + set(e.hdle,varargin{:}); + end end end - + function set_for_all_layout(this,layout, varargin) for ih = size(layout,1):-1:1 % along rows rowcurr = layout{ih}; @@ -585,19 +641,28 @@ function set_for_all_layout(this,layout, varargin) end end end - + + function enable_resizable(this) + set(this.hdle,'Resize', 'on'); + this.set_for_all('Units', 'Normalized'); + end + + function disable_resizable(this) + set(this.hdle,'Resize', 'off'); + end + function set_by_id(this, id, varargin) - e = this.uimap(id); - set(e.hdle, varargin{:}); + e = this.uimap(id); + set(e.hdle, varargin{:}); end function out= get_by_id(this, id, varargin) - e = this.uimap(id); - out = get(e.hdle, varargin{:}); + e = this.uimap(id); + out = get(e.hdle, varargin{:}); end function [w, h] = get_layout_sz(this, layout) - % get layout size in layout units + % get layout size in layout units w=0; h=0; for ih = size(layout,1):-1:1 % along rows @@ -614,32 +679,32 @@ function set_by_id(this, id, varargin) error('Element %s not found',rowcurr{ei}); end hmax = max([hmax, e.h]); - wrow = wrow+e.w; + wrow = wrow+e.w; end - w = max([w, wrow]); + w = max([w, wrow]); h = h+hmax; end end - + function set_w(this,id,w) e = this.uimap(id); e.w = w; this.uimap(id)=e; end - + function set_h(this,id,h) e = this.uimap(id); e.h = h; this.uimap(id)=e; end - + %% Misc function txt =truncate_txt(this, txt) if numel(txt)>this.max_char txt = [txt(1:this.max_char) '...']; end end - + end %% Templates @@ -647,44 +712,94 @@ function set_h(this,id,h) methods %% A template for a button. Replace truc with some label. - function this = button_truc(this, mode) + function this = button_template(this, mode,name,string,callback,w,h) + % Names + label = ['button_' name]; + if ~exist('string','var')||isempty('string') + if isfield(this.data_gui, name) + string = this.data_gui.(name).string; + else + w = name; + end + string = name; + end + + % sizes + if ~exist('w', 'var')||isempty(w) + if isfield(this.data_gui, name) + w = this.data_gui.(name).w; + else + w = 1; + end + + end + if ~exist('h', 'var')||isempty(h) + if isfield(this.data_gui, name) + h = this.data_gui.(name).h; + else + h = 1; + end + end + + % Resolve call + switch mode + case 'create' + this.create_button(label, string, callback, w,h); + case 'callback' + callback(o,e); % for manual call of the callback function I guess + case 'update' + if isfield(this.data_gui, name) + this.set_by_id(label, 'String', this.data_gui.(name).string); + end + end + + + end + + %% Template for a slider + function this = slider_template(this, mode) % Global variables label = 'button_truc'; string = 'Truc'; % sizes - w = 1; - h = 1; + if ~exist('w', 'var')||isempty(w) + w = 1; + end + if ~exist('h', 'var')||isempty(h) + h = 1; + end % Resolve call switch mode case 'create' - create_button_truc() + create_this() case 'callback' - callback_button_truc(); - update_button_truc(); + callback_this(); case 'update' - update_button_truc(); - end + update_this(); + end % Sub functions - function create_button_truc() - this.data_gui.truc.num_clicked = 0; - this.create_button(label, string, @(hObj,evt) (button_truc(this, 'callback')), w,h); + function create_this() % create and initializes elements + this.data_gui.truc.num_clicked = 0; + this.create_button(label, string, @(hObj,evt) (button_truc(this, 'callback')), w,h); end - function callback_button_truc() - this.data_gui.truc.num_clicked = this.data_gui.truc.num_clicked+1; + function callback_this() + % modifies this.data_gui + this.data_gui.truc.num_clicked = this.data_gui.truc.num_clicked+1; + + % calls relevant update functions + update_this(); end - function update_button_truc() + function update_this() % modifies itself based on data_gui this.set_by_id(label, 'String', sprintf('Truc: %g', this.data_gui.truc.num_clicked)) end end - - end diff --git a/Core/Gui/BreachProblemGui.m b/Core/Gui/BreachProblemGui.m new file mode 100644 index 00000000..b14785d1 --- /dev/null +++ b/Core/Gui/BreachProblemGui.m @@ -0,0 +1,43 @@ +classdef BreachProblemGui < BreachGuiClass + properties + pb + end + + + methods + function this = BreachProblemGui(pb) + + this.pb=pb; + this.pb.callback_obj = @(o,e)(this.zcallback('pb',o,e)); + this.create_axes('ax_main',2,8); + this.create_button('button_stop','Stop'); + this.create_button('button_resume','Start/Resume'); + layout = {{'ax_main'}; + {'button_resume', 'button_stop'}}; + this.set_layout(layout); + this.enable_resizable(); + + end + + function zcallback(this,id,o,e) + + switch id + case 'button_stop' + this.pb.is_paused = 1; + + case 'button_resume' + this.pb.is_paused = 0; + this.pb.solve(); + + case 'pb' + ax=this.uimap('ax_main').hdle; + axes(ax); + plot(1:this.pb.nb_obj_eval, this.pb.obj_log); + drawnow + end + + end + + end + +end \ No newline at end of file diff --git a/Core/Gui/elems/slider_elem.m b/Core/Gui/elems/slider_elem.m new file mode 100644 index 00000000..9f9d3a6e --- /dev/null +++ b/Core/Gui/elems/slider_elem.m @@ -0,0 +1,20 @@ +classdef slider_elem < gui_elem + + methods + function disp_in(this, gui, elem_parent, w, h, wunit, hunit) + % draw slider with margins + + we = this.w; + he = this.h; + + wpos = w+this.wleft*wunit; + hpos = h+this.hbot*hunit; + wsz = (we-this.wright-this.wleft)*wunit; + hsz = (he-this.htop-this.hbot)*hunit; + + set(this.hdle,'Parent',elem_parent.hdle, 'Position', [wpos hpos wsz hsz], 'visible', 'on'); + + end + end +end + diff --git a/Core/OutputGen/alw_monitor.m b/Core/OutputGen/alw_monitor.m index a570b3a2..f9893a94 100644 --- a/Core/OutputGen/alw_monitor.m +++ b/Core/OutputGen/alw_monitor.m @@ -10,7 +10,7 @@ this.subphi = get_children(this.formula); this.subphi = this.subphi{1}; this.signals = {[this.formula_id '_violation'],... - [this.formula_id '_quant_sat']}; + [this.formula_id '_quant_sat']}; this.interval = get_interval(formula); this.init_P(); @@ -30,6 +30,22 @@ end + function is_sensitive = ... + get_structural_sensitivity(this, time, X1, X2, p) + + % init for given time + this.init_tXp(time, X1, p); + traj1 = this.P.traj{1}; + this.init_tXp(time, X2, p); + traj2 = this.P.traj{1}; + + idx = this.get_time_idx_interval(time, p); + + is_sensitive = ... + STL_Eval_Structural_Sensitivity(this.Sys, this.formula, ... + this.P0, traj1, traj2, this.inout, this.relabs, time(idx)); + end + function [v, t, Xout] = eval(this, t, X,p) [t, Xout] = this.computeSignals(t, X,p); idx = this.get_time_idx_interval(t,p); diff --git a/Core/OutputGen/postprocess_fcn_wrapper.m b/Core/OutputGen/postprocess_fcn_wrapper.m index 1f2dc19b..df495ea4 100644 --- a/Core/OutputGen/postprocess_fcn_wrapper.m +++ b/Core/OutputGen/postprocess_fcn_wrapper.m @@ -1,4 +1,4 @@ -classdef postprocess_fcn_wrapper < output_gen +classdef postprocess_fcn_wrapper < signal_gen properties fun end diff --git a/Core/OutputGen/req_monitor.m b/Core/OutputGen/req_monitor.m index 54e023aa..44a94b84 100644 --- a/Core/OutputGen/req_monitor.m +++ b/Core/OutputGen/req_monitor.m @@ -1,9 +1,29 @@ -classdef req_monitor < output_gen +classdef req_monitor < signal_gen properties name + R % BreachRequirement object end methods + function this = req_monitor(name, signals, params, p0) + if nargin ==0 + this.name = 'req_null'; + else + this.name = name; + if exist('params', 'var') + this.params = params; + end + + if exist('signals', 'var') + this.signals_in = signals; + end + + if exist('p0', 'var') + this.p0 = p0; + end + end + end + function [t, Xout] = computeSignals(t, Xin, pin) Xout=[]; end @@ -11,10 +31,10 @@ function status = set_mode(this, flag1, flag2) status = 0; end - - end - methods (Abstract) - eval(this, t, X,p) - end + + function [v,t,X] = eval(this, t,X,p) + v =0; + end + end end \ No newline at end of file diff --git a/Core/OutputGen/stl_monitor.m b/Core/OutputGen/stl_monitor.m index ed18017e..583b56b1 100644 --- a/Core/OutputGen/stl_monitor.m +++ b/Core/OutputGen/stl_monitor.m @@ -1,5 +1,5 @@ classdef stl_monitor < req_monitor - + % req_monitor wrapper for class STL_Formula properties P0 P @@ -33,6 +33,8 @@ end this.formula_id = get_id(this.formula); this.name = get_id(this.formula); + %this.params_out = {['rho_' this.name]}; + %this.params_out_domain = BreachDomain(); % collect signals and params names [this.signals_in, this.params, this.p0] = STL_ExtractSignals(this.formula); @@ -59,8 +61,7 @@ function set_out_signal_names(this, sigs) function sigs_out = get_out_signal_names(this) sigs_out = get_out_signal_names(this.formula); end - - + function status = set_mode(this, flag1, flag2) input_signals = get_in_signal_names(this.formula); if ~isempty(input_signals) @@ -226,7 +227,7 @@ function plot_implicant(this, ax, id) plot(sample.time, sample.value, 'x', 'Color',color); end t0 = this.P.traj{1}.time; - set(ax, 'XLim', [0 t0(end)]); + set(ax, 'XLim', [t0(1) t0(end)]); end @@ -246,18 +247,41 @@ function init_tXp(this, t, X, p) end end - function [time, rob] = get_standard_rob(this, phi, time) - switch this.inout - case {'in','out'} - switch this.relabs - case {'rel','abs'} - [rob, time] = STL_Eval_IO(this.Sys, phi, this.P0, this.P.traj{1}, this.inout, this.relabs, time); - otherwise - [rob, time] = STL_Eval_IO(this.Sys, phi, this.P0, this.P.traj{1}, this.inout, 'rel', time); - end - otherwise - [rob, time] = STL_Eval(this.Sys, phi, this.P0,this.P.traj{1},time); + function [time, rob] = get_standard_rob(this, phi, time, IA_flag) + + if nargin<4 + IA_flag = true; end + if IA_flag + switch this.inout + case {'in','out'} + switch this.relabs + case {'rel','abs'} + [rob, time] = STL_Eval_IO(this.Sys, phi, this.P0, this.P.traj{1}, this.inout, this.relabs, time); + otherwise + [rob, time] = STL_Eval_IO(this.Sys, phi, this.P0, this.P.traj{1}, this.inout, 'rel', time); + end + otherwise + [rob, time] = STL_Eval(this.Sys, phi, this.P0,this.P.traj{1},time); + end + else + [rob, time] = STL_Eval(this.Sys, phi, this.P0,this.P.traj{1},time); + end + end + + function is_sensitive = ... + get_structural_sensitivity(this, time, X1, X2, p) + + % init for given time + this.init_tXp(time, X1, p); + traj1 = this.P.traj{1}; + this.init_tXp(time, X2, p); + traj2 = this.P.traj{1}; + + % evaluate sensitivity at time 0 + is_sensitive = ... + STL_Eval_Structural_Sensitivity(this.Sys, this.formula, ... + this.P0, traj1, traj2, this.inout, this.relabs, 0); end function varargout = disp(this) @@ -268,15 +292,15 @@ function init_tXp(this, t, X, p) st_pred = []; preds = STL_ExtractPredicates(phi); for ip = 1:numel(preds) - id = get_id(preds(ip)); - status(ip)= STL_CheckID(id); + id{ip} = get_id(preds(ip)); + status(ip)= STL_CheckID(id{ip}); end if any(status==1) st_pred = ' where \n'; for ip = 1:numel(preds) if status(ip)==1 - st_pred = sprintf([ st_pred '%s := %s \n' ],id,disp(preds(ip))); + st_pred = sprintf([ st_pred '%s := %s \n' ],id{ip},disp(preds(ip))); end end end @@ -291,8 +315,18 @@ function init_tXp(this, t, X, p) end end - end + + function assign_params(this, p) + if nargin==1 + p = GetParam(this.P0, this.params); + end + % assign_params fetch parameters and assign them in the current context + for ip = 1:numel(this.params) + assignin('caller', this.params{ip},p(ip)); + end + end + end methods (Access=protected) function [phi, diag_map] = diag(this, phi, rob, diag_map, flag) @@ -396,15 +430,109 @@ function init_tXp(this, t, X, p) end end - function assign_params(this, p) - if nargin==1 - p = GetParam(this.P, this.params); - end - % assign_params fetch parameters and assign them in the current context - for ip = 1:numel(this.params) - assignin('caller', this.params{ip},p(ip)); + function [mnu, diag_map] = get_mnu(this, phi, rob, diag_map, flag) + + in_implicant = diag_map(get_id(phi)); + samples = in_implicant.getSignificantSamples(); + + psis = get_children(phi); + switch(get_type(phi)) + case 'predicate' + signal_names = STL_ExtractSignals(phi); + for i=1:length(signal_names) + signal_name = signal_names{i}; + signal = rob(signal_name); + if(~diag_map.isKey(signal_name)) + out_implicant = BreachImplicant; + intervals = in_implicant.getIntervals(); + for j=1:length(intervals) + interval = intervals(j); + out_implicant = out_implicant.addInterval(interval.begin, interval.end); + end + samples = in_implicant.getSignificantSamples(); + for j=1:length(samples) + sample = samples(j); + value = interp1(signal.times, signal.values, sample.time, 'previous'); + out_implicant = out_implicant.addSignificantSample(sample.time, value); + end + diag_map(signal_name) = out_implicant; + end + end + + case 'not' + signal = rob(get_id(psis{1})); + if(flag) + [implicant] = BreachDiagnostics.diag_not_t(signal, in_implicant, samples); + else + [implicant] = BreachDiagnostics.diag_not_f(signal, in_implicant, samples); + end + diag_map(get_id(psis{1})) = implicant; + [psis{1}, diag_map] = this.diag(psis{1}, rob, diag_map, ~flag); + case 'or' + signal1 = rob(get_id(psis{1})); + signal2 = rob(get_id(psis{2})); + if(flag) + [implicant1, implicant2] = BreachDiagnostics.diag_or_t(signal1, signal2, in_implicant, samples); + else + [implicant1, implicant2] = BreachDiagnostics.diag_or_f(signal1, signal2, in_implicant, samples); + end + diag_map(get_id(psis{1})) = implicant1; + diag_map(get_id(psis{2})) = implicant2; + [psis{1}, diag_map] = this.diag(psis{1}, rob, diag_map, flag); + [psis{2}, diag_map] = this.diag(psis{2}, rob, diag_map, flag); + case 'and' + signal1 = rob(get_id(psis{1})); + signal2 = rob(get_id(psis{2})); + if(flag) + [implicant1, implicant2] = BreachDiagnostics.diag_and_t(signal1, signal2, in_implicant, samples); + else + [implicant1, implicant2] = BreachDiagnostics.diag_and_f(signal1, signal2, in_implicant, samples); + end + diag_map(get_id(psis{1})) = implicant1; + diag_map(get_id(psis{2})) = implicant2; + [psis{1}, diag_map] = this.diag(psis{1}, rob, diag_map, flag); + [psis{2}, diag_map] = this.diag(psis{2}, rob, diag_map, flag); + case '=>' + signal1 = rob(get_id(psis{1})); + signal2 = rob(get_id(psis{2})); + if(flag) + [implicant1, implicant2] = BreachDiagnostics.diag_implies_t(signal1, signal2, in_implicant, samples); + else + [implicant1, implicant2] = BreachDiagnostics.diag_implies_f(signal1, signal2, in_implicant, samples); + end + diag_map(get_id(psis{1})) = implicant1; + diag_map(get_id(psis{2})) = implicant2; + [psis{1}, diag_map] = this.diag(psis{1}, rob, diag_map, flag); + [psis{2}, diag_map] = this.diag(psis{2}, rob, diag_map, flag); + case 'always' + signal = rob(get_id(psis{1})); + I = this.get_interval(phi); + bound.begin = I(1); + bound.end = min(I(2),max(signal.times)); + if(flag) + [implicant] = BreachDiagnostics.diag_alw_t(signal, bound, in_implicant, samples); + else + [implicant] = BreachDiagnostics.diag_alw_f(signal, bound, in_implicant, samples); + end + + diag_map(get_id(psis{1})) = implicant; + [psis{1}, diag_map] = this.diag(psis{1}, rob, diag_map, flag); + case 'eventually' + signal = rob(get_id(psis{1})); + I = this.get_interval(phi); + bound.begin = I(1); + bound.end = min(I(2),max(signal.times)); + if(flag) + [implicant] = BreachDiagnostics.diag_ev_t(signal, bound, in_implicant, samples); + else + [implicant] = BreachDiagnostics.diag_ev_f(signal, bound, in_implicant, samples); + end + diag_map(get_id(psis{1})) = implicant; + [psis{1}, diag_map] = this.diag(psis{1}, rob, diag_map, flag); end - end + end + + function I = get_interval(this__, phi___) if nargin==1 diff --git a/Core/STL_ReadFile.m b/Core/STL_ReadFile.m index 9eae78f5..6d85f30b 100644 --- a/Core/STL_ReadFile.m +++ b/Core/STL_ReadFile.m @@ -1,6 +1,4 @@ function [props_names, props, signal_names, param_names, in_signal_names, out_signal_names] = STL_ReadFile(fname, onlyLoadLastFormula) - - %STL_READFILE reads formulas from a text file and loads them in the base %workspace % @@ -164,9 +162,7 @@ props = [props, {phi}]; %#ok<*AGROW> props_names = [props_names, {current_id}]; catch err - % JOHAN ADDED assignin('base', 'row_to_replace', num_line); - % END JOHAN ADDED fprintf(['ERROR: Problem with formula ' current_id ' at line ' ... int2str(num_line-1) '\n']); rethrow(err); @@ -202,10 +198,8 @@ phi = wrap_up(current_id, current_formula, new_params, in_signal_names, out_signal_names); props = [props, {phi}]; props_names = [props_names, {current_id}]; -catch err - % JOHAN ADDED - assignin('base', 'row_to_replace', num_line); - % END JOHAN ADDED +catch err + assignin('base', 'row_to_replace', num_line); fprintf(['ERROR: Problem with formula ' current_id ' at line ' ... int2str(num_line-1) '\n']); rethrow(err); @@ -225,13 +219,19 @@ % new_params % Note: will let function names, mex-files etc be overriden -params = {}; -[~,~, ~, matches, tokens] = regexp(disp(phi,0), '(\<\w+\>)'); -for im=1:numel(matches) - params{end+1} = tokens{im}{1}; -end +[~, params] = STL_ExtractSignals(phi); +% params = {}; +% [~,~, ~, matches, tokens] = regexp(disp(phi,0), '(\<\w+\>)'); +% for im=1:numel(matches) +% params{end+1} = tokens{im}{1}; +% end fn = fieldnames(new_params)'; +undef_params= setdiff(params, fn); +if not(isempty(undef_params)) + undefs = list_manip.to_string(undef_params); + warning('STL_ReadFile:undef_params', 'Parameter(s) %s appear in formula current_id but are undeclared, default to 0. ', undefs); +end for np = fn if ~any(strcmp(np{1},params)) new_params = rmfield(new_params, np{1}); diff --git a/Core/SignalGen/BreachSignalGen.m b/Core/SignalGen/BreachSignalGen.m index 970c84bf..e33a7f8a 100644 --- a/Core/SignalGen/BreachSignalGen.m +++ b/Core/SignalGen/BreachSignalGen.m @@ -114,10 +114,10 @@ function InitSignalGen(this, signalGenerators) idx_psg = FindParam(this.P, sg.params); p_isg = p(idx_psg); ns = numel(sg.signals); - X(cur_is:cur_is+ns-1, :) = sg.computeSignals(p_isg, tspan); + [X(cur_is:cur_is+ns-1, :), tspan]= sg.computeSignals(p_isg, tspan); cur_is = cur_is+ ns; end - + end function SetParam(this, params, values, varargin) diff --git a/Core/SignalGen/constant_signal_gen.m b/Core/SignalGen/constant_signal_gen.m index b5ea9f32..7653e1f6 100644 --- a/Core/SignalGen/constant_signal_gen.m +++ b/Core/SignalGen/constant_signal_gen.m @@ -33,7 +33,7 @@ end - function X = computeSignals(this,p, time) % compute the signals + function [X, time] = computeSignals(this,p, time) % compute the signals if numel(p) ~= numel(this.signals) error('Wrong number of parameters for computing constant signal.' ) end diff --git a/Core/SignalGen/cp_signal_gen.m b/Core/SignalGen/cp_signal_gen.m index a90ed96b..8c56f254 100644 --- a/Core/SignalGen/cp_signal_gen.m +++ b/Core/SignalGen/cp_signal_gen.m @@ -71,7 +71,7 @@ end - function X = computeSignals(this,p, time) % compute the signals + function [X, time] = computeSignals(this,p, time) % compute the signals if size(p,1) ==1 p = p'; diff --git a/Core/SignalGen/exponential_signal_gen.m b/Core/SignalGen/exponential_signal_gen.m index 144626e2..b8cce8ae 100644 --- a/Core/SignalGen/exponential_signal_gen.m +++ b/Core/SignalGen/exponential_signal_gen.m @@ -49,7 +49,7 @@ end - function X = computeSignals(this, p, time) % compute the signals + function [X, time] = computeSignals(this, p, time) % compute the signals if numel(p) ~= 3*numel(this.signals) error('Wrong number of parameters for computing exponential signal.' ) end diff --git a/Core/SignalGen/fixed_cp_signal_gen.m b/Core/SignalGen/fixed_cp_signal_gen.m index ba9b7f5b..4b0d5c08 100644 --- a/Core/SignalGen/fixed_cp_signal_gen.m +++ b/Core/SignalGen/fixed_cp_signal_gen.m @@ -66,7 +66,7 @@ end - function X = computeSignals(this,p,time) % compute the signals + function [X, time] = computeSignals(this,p,time) % compute the signals if size(p,1) ==1 p = p'; end diff --git a/Core/SignalGen/from_file_pattern_signal_gen.m b/Core/SignalGen/from_file_pattern_signal_gen.m index 34155635..454f1b59 100644 --- a/Core/SignalGen/from_file_pattern_signal_gen.m +++ b/Core/SignalGen/from_file_pattern_signal_gen.m @@ -10,7 +10,7 @@ [this.params,this.p0, this.pattern] = guess_filename_params(fname); end - function X= computeSignals(this, p, time) + function [X, time] = computeSignals(this, p, time) fname = sprintf(this.pattern,p); X = zeros(numel(this.signals), numel(time)); try diff --git a/Core/SignalGen/from_workspace_signal_gen.m b/Core/SignalGen/from_workspace_signal_gen.m index 233e43e0..b9a51592 100644 --- a/Core/SignalGen/from_workspace_signal_gen.m +++ b/Core/SignalGen/from_workspace_signal_gen.m @@ -13,7 +13,7 @@ end end - function X= computeSignals(this, p, time) + function [X, time]= computeSignals(this, p, time) X = zeros(numel(this.signals), numel(time)); for isig = 1:numel(this.signals) diff --git a/Core/SignalGen/merge_signal_gen.m b/Core/SignalGen/merge_signal_gen.m index d5738266..a4f8b466 100644 --- a/Core/SignalGen/merge_signal_gen.m +++ b/Core/SignalGen/merge_signal_gen.m @@ -38,7 +38,7 @@ end - function X = computeSignals(this,p, time) + function [X, time] = computeSignals(this,p, time) X = zeros(0, numel(time)); for isg = 1:numel(this.sgs) sg = this.sgs{isg}; diff --git a/Core/SignalGen/multi_pulse_signal_gen.m b/Core/SignalGen/multi_pulse_signal_gen.m new file mode 100644 index 00000000..089584e9 --- /dev/null +++ b/Core/SignalGen/multi_pulse_signal_gen.m @@ -0,0 +1,118 @@ +classdef multi_pulse_signal_gen < signal_gen + % multi_pulse_signal_gen A class derived from signal_gen to generate + % periodic pulse signals. multi_pulse can synchronize signals. + % + % pulse_signal_gen Methods + % pulse_signal_gen - constructor, takes signal names, and an optional p0. + % Each signal 'x' gets a 'x_base_value', 'x_pulse_period', + % 'x_pulse_width', 'x_pulse_amp' and 'x_pulse_delay' parameter, with default + % to 0, 1, 0.5, 1 and 0, respectively. + % + % See also signal_gen. + + methods + function this = multi_pulse_signal_gen(signals, p0) + if ischar(signals) + signals = {signals}; + end + this.signals = signals; + this.params = {}; + this.p0 = zeros( 5*numel(signals), 1 ); + for i_s = 1:numel(this.signals) + this.params = { this.params{:} [this.signals{i_s} '_base_value'] ... + [this.signals{i_s} '_pulse_period']... + [this.signals{i_s} '_pulse_width']... + [this.signals{i_s} '_pulse_amp']... + [this.signals{i_s} '_pulse_delay']}; + this.p0(5*(i_s-1)+1:5*i_s,1) = [0 1 0.5 1 0]; + end + + this.params = [this.params {'period','width','delay'}]; + for idx_signal = 1:numel(signals) % individual delays relative to period + this.params{end+1} = [signals{idx_signal} '_pulse_rel_delay']; + end + + if nargin==2 + this.p0 =p0; + else + p0 = zeros(numel(this.params),1); + p0(1:numel(this.p0),1) = this.p0; + this.p0 = p0; + end + + this.params_domain = repmat(BreachDomain(), 1, numel(this.params)); + this.signals_domain = repmat(BreachDomain(), 1, numel(this.signals)); + end + + function [X, time] = computeSignals(this,p, time) % compute the signals + nb_p = 5; + if size(p,1) ==1 + p = p'; + end + + %% Collect common parameters if required + num_signals = numel(this.signals); + + com_period = p(5*num_signals+1); + com_width = p(5*num_signals+2); + com_delay = p(5*num_signals+3); + rel_delays = p(5*num_signals+4:end); + + %% Compute pulses + X = repmat(p(1:nb_p: num_signals*nb_p), 1, numel(time)); + unshifted_pulse = @(T,d,t) sin(((2*pi)/T)*(t+eps)) > cos(pi*d); + advance = @(T,d) T*(0.25 - 0.5*d); + pulse = @(T,d,t) unshifted_pulse(T,d, t + advance(T,d)); + + for i_s = 0:numel(this.signals)-1 + pi_s = p(nb_p*i_s+1:nb_p*i_s+nb_p); + base = pi_s(1); + period = pi_s(2); + width = pi_s(3); + amp = pi_s(4); + delay = pi_s(5); + rel_delay= rel_delays(i_s+1); + + % adjust with common parameters if needed (if not 0, com + % takes over) + + if com_period + period = com_period; + end + if com_width + width = com_width; + end + + % for delay, it's additive, relative delay is periodic + % (if delay > 0.5, acts as negative delay, delay = 1.1 same as 0.1, etc) + delay = delay+com_delay; + delay = delay+period*(rem(rel_delay+.5,1)-.5); + + if width == 1 + X(i_s+1,:) = amp; + elseif width == 0 + X(i_s+1,:) = base; + elseif delay ==0 + X(i_s+1,:) = base + amp*pulse(period, width, time); + elseif delay>time(end) + X(i_s+1,:) = base; + elseif delay>0 + time_not_0 = time(time>= delay); + X(i_s+1, time>=delay) = base + amp*pulse(period, width, time_not_0-time_not_0(1)); + else + dt = time(2)-time(1); + time_shift = [time(1)+delay:dt:time(1)-dt time]; + pulse_s = base + amp*pulse(period, width, time_shift-delay); + X(i_s+1,:) = pulse_s(time_shift>=time(1)); + end + + end + + function type = getType(this) + type = 'pulse'; + end + end + + end +end + diff --git a/Core/SignalGen/pulse_signal_gen.m b/Core/SignalGen/pulse_signal_gen.m index 0dd314ea..9d41636a 100644 --- a/Core/SignalGen/pulse_signal_gen.m +++ b/Core/SignalGen/pulse_signal_gen.m @@ -36,7 +36,7 @@ end - function X = computeSignals(this,p, time) % compute the signals + function [X, time] = computeSignals(this,p, time) % compute the signals nb_p = 5; if numel(p) ~= nb_p*numel(this.signals) error('Wrong number of parameters for computing constant signal.' ) diff --git a/Core/SignalGen/random_signal_gen.m b/Core/SignalGen/random_signal_gen.m index 2348db4c..e6e74e4f 100644 --- a/Core/SignalGen/random_signal_gen.m +++ b/Core/SignalGen/random_signal_gen.m @@ -62,7 +62,7 @@ end if isempty(this.p0) - this.p0 = repmat( [0 0 1 -1 1] , 1, numel(signals)); + this.p0 = repmat( [0 0.1 1 -1 1] , 1, numel(signals)); end % domains @@ -70,7 +70,7 @@ end - function X = computeSignals(this,p, time) + function [X, time] = computeSignals(this,p, time) if size(p,1) ==1 p = p'; end diff --git a/Core/SignalGen/signal_gen.m b/Core/SignalGen/signal_gen.m index b8de6cc4..1638bdb5 100644 --- a/Core/SignalGen/signal_gen.m +++ b/Core/SignalGen/signal_gen.m @@ -13,10 +13,14 @@ % var_cp_signal_gen, pulse_signal_gen, step_signal_gen properties + signals_in signals % names of the signals it generates signals_domain % domains for signals. If empty, all double, unbounded params % parameters such as control points, etc params_domain % domains for parameters. If empty, all double, unbounded + params_out % signal_gen can also compute new parameters + params_out_domain + domains = containers.Map() % maps all of the above to their respective domains, supposedly (TODO) p0 % default values end @@ -125,6 +129,14 @@ function plot_enveloppe(this, signal, time, varargin) f = fill(t2, inBetween, 'k', 'FaceAlpha', 0.1); end end + function assign_params(this, p) + % assign_params fetch parameters and assign them in the current context + for ip = 1:numel(this.params) + assignin('caller', this.params{ip},p(ip)); + end + end + + end diff --git a/Core/SignalGen/sinusoid_signal_gen.m b/Core/SignalGen/sinusoid_signal_gen.m index 43daccec..038a17cf 100644 --- a/Core/SignalGen/sinusoid_signal_gen.m +++ b/Core/SignalGen/sinusoid_signal_gen.m @@ -29,7 +29,7 @@ end - function X = computeSignals(this, p, time) % compute the signals + function [X, time] = computeSignals(this, p, time) % compute the signals if numel(p) ~= 4*numel(this.signals) error('Wrong number of parameters for computing constant signal.' ) end diff --git a/Core/SignalGen/spike_signal_gen.m b/Core/SignalGen/spike_signal_gen.m index fca64e73..31ab07b3 100644 --- a/Core/SignalGen/spike_signal_gen.m +++ b/Core/SignalGen/spike_signal_gen.m @@ -68,7 +68,7 @@ end - function X = computeSignals(this, p, time) % compute the signals + function [X, time] = computeSignals(this, p, time) % compute the signals if numel(p) ~= 4*numel(this.signals) error('Wrong number of parameters for computing spike signal.' ) end diff --git a/Core/SignalGen/step_signal_gen.m b/Core/SignalGen/step_signal_gen.m index b58ed72d..7e198dde 100644 --- a/Core/SignalGen/step_signal_gen.m +++ b/Core/SignalGen/step_signal_gen.m @@ -38,7 +38,7 @@ params = this.params; end - function X = computeSignals(this,p, time) % compute the signals + function [X, time] = computeSignals(this,p, time) % compute the signals if numel(p) ~= 3*numel(this.signals) error('Wrong number of parameters for computing constant signal.' ) end diff --git a/Core/SignalGen/switch_signal_gen.m b/Core/SignalGen/switch_signal_gen.m index d67bb830..df410edc 100644 --- a/Core/SignalGen/switch_signal_gen.m +++ b/Core/SignalGen/switch_signal_gen.m @@ -36,7 +36,7 @@ end - function X = computeSignals(this, p, time) + function [X, time] = computeSignals(this, p, time) idx_sg = p(1); sg = this.sgs{idx_sg}; idx_p=this.sg_1st_param_idx(idx_sg); diff --git a/Core/SignalGen/time_shift_signal_gen.m b/Core/SignalGen/time_shift_signal_gen.m index 7b8008da..8a3caa86 100644 --- a/Core/SignalGen/time_shift_signal_gen.m +++ b/Core/SignalGen/time_shift_signal_gen.m @@ -4,8 +4,7 @@ methods function this= time_shift_signal_gen(sg) - this.sg.copy(); - + this.sg.copy(); end diff --git a/Core/SignalGen/var_cp_signal_gen.m b/Core/SignalGen/var_cp_signal_gen.m index 34aed706..d91c0ed3 100644 --- a/Core/SignalGen/var_cp_signal_gen.m +++ b/Core/SignalGen/var_cp_signal_gen.m @@ -113,7 +113,7 @@ end - function X = computeSignals(this,p, time) % compute the signals + function [X, time] = computeSignals(this,p, time) % compute the signals if size(p,1) ==1 p = p'; diff --git a/Core/SignalGen/var_step_signal_gen.m b/Core/SignalGen/var_step_signal_gen.m index 664782e3..17587c5b 100644 --- a/Core/SignalGen/var_step_signal_gen.m +++ b/Core/SignalGen/var_step_signal_gen.m @@ -79,7 +79,7 @@ end - function X = computeSignals(this,p, time) % compute the signals + function [X, time] = computeSignals(this,p, time) % compute the signals if size(p,1) ==1 p = p'; diff --git a/Core/m_src/ResetBreach.m b/Core/m_src/ResetBreach.m index 7ae19d29..9b69a68c 100644 --- a/Core/m_src/ResetBreach.m +++ b/Core/m_src/ResetBreach.m @@ -4,13 +4,17 @@ function ResetBreach(b) global BreachGlobOpt d = [BreachGlobOpt.breach_dir filesep 'Ext' filesep 'ModelsData']; if nargin<1 - b=0; + choice = questdlg('Remove models data files?'); + if strcmp(choice,'Yes') + b = 1; + end end -if b||questdlg('Remove models data files?') +if b try - rmdir([d filesep 'slprj'], 's'); + fprintf('Deleting all files and folders in %s ... \n', d); + rmdir([d filesep 'slprj'], 's'); rmdir([d filesep 'ParallelTemp'], 's'); - delete([d filesep '*.*']) + delete([d filesep '*.*']) end end diff --git a/Core/m_src/check_arg_is_cell.m b/Core/m_src/check_arg_is_cell.m index ba8b9c22..35a62735 100644 --- a/Core/m_src/check_arg_is_cell.m +++ b/Core/m_src/check_arg_is_cell.m @@ -20,5 +20,7 @@ % already a cell checks size if numel(arg)~=num_args error('check_arg_is_cell', 'Wrong number of element in argument cell.'); + else + arg_cell = arg; end end \ No newline at end of file diff --git a/Core/m_src/check_sim_time.m b/Core/m_src/check_sim_time.m new file mode 100644 index 00000000..2c5da63c --- /dev/null +++ b/Core/m_src/check_sim_time.m @@ -0,0 +1,33 @@ +function tspan = check_sim_time(tspan) +% tspan = check_sim_time(tspan) +% +% Checks/enforces the following requirements: +% - It must be a one dimensional array +% - tspan(end) should be positive +% - tspan can be a scalar, in which case it is treated as [0 t_in] +% - tspan must be strictly increasing. If not, try to sort it and +% remove duplicates (with a warning) +% - tspan(1) should be 0. Adds it with a warning if needed + +if ~all(diff(tspan)>0) + warning('check_sim_time:non_monotonic_time', 'Simulation time should be strictly monotonic, increasing. Will sort and continue.' ) + tspan = sort(unique(tspan)); +end + +if tspan(end)<0 + error('check_time:neg_time', 'Cannot set negative time.') +end + +if isscalar(tspan) % standard case + tspan = [0 tspan]; +end + +if size(tspan, 1)~=1 + tspan= tspan'; +end + +if tspan(1) ~= 0 + warning('check_sim_time:time_starts_at_non_zero', 'Simulation time should start at time 0. Adding 0 and trying to continue.') + tspan = [0 tspan]; +end +end diff --git a/Core/m_src/cover.m b/Core/m_src/cover.m index e99d7f1c..cd679796 100644 --- a/Core/m_src/cover.m +++ b/Core/m_src/cover.m @@ -9,11 +9,13 @@ grd = xmin:delta:xmax; -Gabove = repmat(grd', 1, size(x,2)); -Gbelow = Gabove(2:end,:); -Gbelow(end+1,:) = inf; +Glow = repmat(grd', 1, size(x,2)); +Gup = Glow(2:end,:); +Gup(end+1,:) = inf; X = repmat(x, size(grd,2),1); -Xin = (X>= Gabove)&(XGlow)&(XGlow)&(X2&&i<=n + l = [l(1:i-2) l(i) l(i-1) l(i+1:end)]; + end + end + + function l = move_down(l,i) + n = numel(l); + if i==2 + l = [l(i) l(1) l(i+1:end)]; + elseif i>2&&i<=n + l = [l(1:i-2) l(i) l(i-1) l(i+1:end)]; + end + end + + function l = remove_elem(l,i) + n=numel(l); + if i==n + l = l(1:i-1); + elseif i==1 + l = l(2:end); + elseif i>1&&i1 + for n = 2:numel(l) + st= [st sep l{n}]; + end + end + end + end + +end \ No newline at end of file diff --git a/Core/m_src/rand_formula.m b/Core/m_src/rand_formula.m index 9b833ce7..8b95099f 100644 --- a/Core/m_src/rand_formula.m +++ b/Core/m_src/rand_formula.m @@ -1,76 +1,97 @@ function [ st_phi, preds ] = rand_formula(n, op, preds) -%RAND_FORMULA Creates a random formula of size n, minimizing the height of the parse tree +%RAND_FORMULA Creates a random formula of size n, minimizing the height of the parse tree % % Synopsis: [ st_phi ] = rand_formula(n, op) -% +% % by default op is a subset {'and', 'ev', 'alw', 'until', 'evI', 'alwI', % 'untilI'} (contains all operators if not specified) -% -% returns the random formula with predicates mu1, ..., mun +% +% returns the random formula with predicates mu1, ..., mun - if nargin == 1 +if nargin == 1 op = {'or', 'and', 'ev', 'alw', 'until', 'evI', 'alwI', 'untilI'}; preds = {'mu'}; - end - - if nargin == 2 +end + +if nargin == 2 preds = {'mu'}; - end - - if (n==0) +end + +if (n==0) new_pred = genvarname('mu',{'mu', preds{:}}); preds = {'mu',preds{:}, new_pred}; st_phi = regexprep(new_pred, 'mu(\d+)', 'x$1[t]>0' ); return; - else - opi = op{randi(numel(op))}; - end - - I = [0 0]; - while I(1)==I(2) - I = sort(20*rand([1 2])); - end - - switch opi - case 'and' - [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); - [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); - st_phi = ['(' st_phi1 ') and (' st_phi2 ')']; - - case 'or' - [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); - [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); - st_phi = ['(' st_phi1 ') or (' st_phi2 ')']; - - case 'ev' - [st_phi1, preds] = rand_formula(n-1, op, preds); - st_phi = ['ev (' st_phi1 ')']; +else + opi = op{randi(numel(op))}; +end - case 'alw' - [st_phi1, preds] = rand_formula(n-1, op, preds); - st_phi = ['alw (' st_phi1 ')']; +I = [0 0]; +while I(1)==I(2) + I = sort(2*rand([1 2])); +end - case 'evI' - [st_phi1, preds] = rand_formula(n-1, op, preds); - st_phi = ['ev_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi1 ')']; - - case 'alwI' - [st_phi1, preds] = rand_formula(n-1, op, preds); - st_phi = ['alw_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi1 ')']; - - case 'until' - [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); - [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); - st_phi = ['(' st_phi1 ') until (' st_phi2 ')']; +switch opi - case 'untilI' - [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); - [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); - st_phi = ['(' st_phi1 ') until_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi2 ')']; + case 'and' + [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); + [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); + st_phi = ['(' st_phi1 ') and (' st_phi2 ')']; + + case 'or' + [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); + [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); + st_phi = ['(' st_phi1 ') or (' st_phi2 ')']; + + case 'not' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['not (' st_phi1 ')']; + + case 'ev' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['ev (' st_phi1 ')']; + + case 'alw' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['alw (' st_phi1 ')']; + + case 'evI' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['ev_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi1 ')']; + + case 'once' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['once (' st_phi1 ')']; + + case 'onceI' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['once_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi1 ')']; - end - if (strcmp(preds{1},'mu')) - preds = {preds{2:end}}; - end + case 'hist' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['hist (' st_phi1 ')']; + + case 'histI' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['hist_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi1 ')']; + + case 'alwI' + [st_phi1, preds] = rand_formula(n-1, op, preds); + st_phi = ['alw_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi1 ')']; + + case 'until' + [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); + [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); + st_phi = ['(' st_phi1 ') until (' st_phi2 ')']; + + case 'untilI' + [st_phi1, preds] = rand_formula(floor((n-1)/2), op, preds); + [st_phi2, preds] = rand_formula(ceil((n-1)/2), op, preds); + st_phi = ['(' st_phi1 ') until_[' num2str(I(1),3) ',' num2str(I(2),3) '] (' st_phi2 ')']; + +end +if (strcmp(preds{1},'mu')) + preds = {preds{2:end}}; +end end diff --git a/Doc/img/AFC_Internal_signals.svg b/Doc/img/AFC_Internal_signals.svg new file mode 100644 index 00000000..3435ecd9 --- /dev/null +++ b/Doc/img/AFC_Internal_signals.svg @@ -0,0 +1,1458 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/img/AFC_PI.svg b/Doc/img/AFC_PI.svg new file mode 100644 index 00000000..52e57eff --- /dev/null +++ b/Doc/img/AFC_PI.svg @@ -0,0 +1,2483 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/Doc/img/AFC_top_level.svg b/Doc/img/AFC_top_level.svg new file mode 100644 index 00000000..2a0a5290 --- /dev/null +++ b/Doc/img/AFC_top_level.svg @@ -0,0 +1,3387 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/img/InputGenGUI.png b/Doc/img/InputGenGUI.png new file mode 100644 index 0000000000000000000000000000000000000000..ecb22f2608d40959bd99251a9397626b41c8edfc GIT binary patch literal 67926 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 z zaHBkOPUv{RulU~RB}g@TOB788srfYERM3pHndaVcbZF6JqWL8h+Qa)nE&Z|2kYCMN z7FwN>oiW@*DJuM`G`(D$Z<+OStZ-!2_%onHY_ zcC_Od6H3(5G+Ta(D(uj5fV8ZO8N`=5r;og6B$OE$4%Y%#PoVwm=5_mq-u@%b?D*qN zxI=?J_@-Y42?wCRz<4&n@e$ox{j@Z#Z8PfI9%_WasgJ^NO`SyoSW;%_X_j%{YO8V( z*e05_Hb4qQ%c7N|c8DSG=GAG=m7k-gPB5wj4***HZy_Q^It3(9g;_BdH7)pfz$GDr zEhKjtB7PiXfZv7j=UJVaV??%^-_Hyz)MG{Hm*7OPyYta>QUY;&n#FHOuCHiii>O3r z1Fc#)!IA|C>YQbSX#y;t(6>pi;iVv4DB;6`s0396x>i z6`(iHy!xjCbwB=BdeauA_7(UgRFRt4gXu`Aqdc%|$YQV$aVCKXnfhN=InmJ7L1HQ| zAaLANLs(K;$qC{(^zwL?JIUobbr7bH%P&tG`GgXqMNCclfisjQf{uj_tfJozJ&>Kt zPLGf$jZ(EyzUbYM6O;WiszdX-2QD>>e-tV=M4;%^kue}_SzvU+BkW$f zDB`J}RD`I5yGWCo-4lt+8pU?{`e%#(#xu~_73rffp{wgd-hD?%nx{k0(ws9hhp~(JJ2Ktxi^~m! zgR&kZiYbwkL0Fyu;U%o4X5Sum_V`)z1UD1Wo(URNbEEmv7u&b$F0?wv6sy)hmM<_& zl_EYu+yXDX53G{~lirw`#m3pLJ_&!s#71V8YwT@PqHhFcwZ^Gv^RH*OsQ>f@u{YcQ z#5YoNnDD!^8S$O(_x4=K1LCc$$0^8P+{KuGe4rx4Pc};8{||4oq@P*FfVbzW8PSKr##7eP9f-75DStlepWyP@TY4JX_S0aBSI-7XWW|o zJtTn&v>5-7UF5Adu!}tNem%yWrwytkLDZTG9HzKZ_j@eGs6*NMk>nVpV7Guqx$3>e zn>6vDcK&>7l>caD6t8~dEb&)jDSbtkq(-a;sHU%;bNh+OIJe4R3T*SBRw|w@8EIxB zs@Lck|I1w38K!lKEg6g<|Hd2gb?muvk1f9itSAED|8ZbDU-SLW{Xw5c0u)9vH{L5Y zTJulv-6ePp_`N6ENMP&NAqr8m!UC@ol%iM@!_;@GQ`13W_5-XMo@cN-vkCX#m(5pS z{nxY(j5(UbL`j+#Zo_9%aZK000plBDM^l1Q8Np(?MMPKJs7^qBP3|k>W~P5b57R22 z0ZIwA^0GUK0)_hLqZBHcNI(H9OTOds`{$vSxa>X269Vt5sn*!b-dTlG{Q$bD>Vjx`$OdXUzt*AoRrcY#wiPEP@*Tw2-bW5jYA|ErM6f5YLLbF z@;MekAj{CFQlCxDmKQ6Xj~(;=%Z{m~&I=P_{Fo9W!~xL%R%`!OeW-@gWXDkHJzz;` zX~15!BoAAeGS5F;=6pXTBzS>2F6HX`r`b$I{{sgXmvT)Aan~FrB;l^4#Uc6M+h$tE zdBHRf%8Wkn(lrNs{W+{*KD)lnv{ALW!Ns;%X$)UaJ{JWjnRk`iK;O|7#$dTGI~yI- zR(hgXtI6F`Dx`k%`VhxeKy9OxA!q+9jPUwyWZF6YRpH?wzPfo7ezd~`o&z?EnXtaV zx(VWqwdJnAzX9*N`Pj06T)TdTH8*+TTS0ICVms#*%YRuv{+}%316pJC1Vt3nTr8#_FMdW87e8v^RYXxP9lL=q*L+ShuaNozwD-oSB$X{;HqQuERVh$^O zr4d(l^QMV16|tOiKaOcdajHf>3~)*&1WzyybbEN`qn{s#-&c(dGuUT0{9Z{Pr=itr zijQV6?64SdM;yH=i9;nRTWk@tvw#gye0AalNzQ_BV|?3m{7giBf>n=Uroi|i*6HBT zVR}vTe(8Ksjmwe}q5u8U#{pnjCcS@~_p8a6Pm0v_&U5RYG~+On9JTmt)tviIZ=)es zWG){m($Xhf_JDp@h#zP!Cs(;!?6^aH^_DtbRpp3RCG~L3ri4}?FVa7v*Aa73*k51t zt)|w}#)>v1i|@Z<5_~9|j(ViqgH%{plivyzleb+*t-(r*do8dmfXix%c&Hc{oymzq z$~8@9N>$+$^^ZiHRx_i<&z8E&fUvD9A9@YgqwHYQ3Kftwz&}vW2;~=$)1d^O1*HdR zFZbM&WgZrS_7@S`xZ|zH66x}EGvTQXQxwgK-tr&(q2j3d*tEpY{8(ZH#}}a7bNWaB z|2d0LY93z&w6F!>g~hSk`g9w7z}LsI2DMlPAQ{?)4)KmGS04Th9BP#3D(U}Bs=zmg zs4RE6IMT|9(D@%Vf-kRdevYUgAhk*i6zk|se-VodUvgU1KwlHpsb3;;mJW0OE>K_^ zN=uUfP#1|CBpFuEaLlpAeMX1XpOi*wjz-U1UN+tBBwATV#sgm=;kycN@gmFy3JsZU zcFWx#{1OlWL=VMK3eaJ$nxcBk)&kVvdT75E2I&|+ji$YM_BGS6SN?oqV`k72ZBLvJj}#4L5H22>3M zmfUF=e*#C-fvST@^TxI(lJrPaiU`Eh4lgSe{0Nw=Z;r3p_B);{5$N%oGaP`zn1c+= z-CI5xpZ8wXqGgxbFB=@+#8avuEz$bQ#<}YVC>rn}Fwl3SJCEm~aZ;=j8)147A z%zGzM%NlbTW_NsA&0^M0c+IDD+Y}iaYbG6k?_NLY(+)FpKgqT7?@7uivCZ8ltg$q+ z?zr3u!HBXz1h4&MQdK2iqg~xZ@xcZ653a+5)lkHAK`gy%{Ck%$!#wZ&`^|Gpx$x2U znk3B1ySnz_sB`9Wc9>BZ%tthPU?*yH_a@v`-P%eVsh#mT$(qi}i#c;E<3kzOJ=}L@z4Gj&LB56B zaP&FNl`V24Ev@w+chTI9O;yn(Rs8bPc$`7^qf3lT@dE11jN0N=>iDN>5;7SydXI%P z5Dk+pc_wl|g?XY@^?=PHZkql>ESq@Q1T&q3**)L&p$*)=jzd^u*S(9Ji*Ed)`ai#$ z*HUJ=9cAG<7*a>PSql%k_sxF{&CP`(X<4MS1Hxd{n}-I0!zIl}-bH9X(026HE=a?E zKKRvZ;H%!`_*41Ne05`ABXu6xmGIOd!NreJbUBEzq^rJBMO>@MRI@h)ttlG#l7V95 z9jjGygS~jQ=Os*66{p#7K1L&}uIo)#19`&e$it-(3Q8em5pKMR&-g3#&NbbTP=hK- z$I41>^%U`hJ(!l4M(oI}cnymWymezMxBYrpCg8u@{Q$07UxnuXq$NdibME`zu03oh zc7byEu(SKfoko{U<66Ezdw3;aD+6?Y{_-33A-BU1odess&kEQ`r^`Kuutn!OE2eM! z;2DM&U1uw(Xs@rMfo-G(!;C%dXSeUm1mPmvgHuXs#rbpchRWI&Y^08lf{K0)-_N)# z(-ae=&i?GWtVKkCivK><$PKhDTh>$t=A)Iie|&^E?-uZLWjKbH}G412%F(pU=T=FJSkE`UjtB=I6!e1Q-(*Yo1tik;Te= z8lO;zg!{{=b7)?Rs6@T=oejI&=j-UnB}I*5`Mre!IRaX?y-6_+S+OgRE%(S+3TP8DzJ}bHPReX!cFqg zJFN?GUzSfh3KB0FXxybA6J)}4eI#IKF}BPcOLdQ>7u?=Qd6%g*j*J`k9b*E9#Z@*G zaZBV`Pole7Qq%Jcx$9a(S+j80`>c{{C6Fr17QMJ&xrI#&!I)xZs-=U*3Yi$?t8*S< z{&YTJg%#%J#sYtFJ9|ZAC*V(VrdcW@=L&JVwl`ivdzNAiX`g{a`h)MR;5RFj?`62H5^S*TSQ-cC?w_gP~1 z7+V(fpD1YOuNL4-19drv8~xtJ;s$O0GkT(bR`i3RDkvx3c9W}6kwD1sjYz>LIwT`@ zqYf*N`ju06dp<@5*R{vS#mLIgFtXB4YV9R|s2BG#ELBjA?miVj{m1?8JCHLFD;=|$ zinGLnrGc@{W^9{>2ItOi&->}fKfruhP8>Q+h@qoroqft~hVumXeNahfX+(^B+LxyJ z_vr8`8<=7$;(Mt@RCGjg4&R(Li+i($Z0V3NVp!Ex0pY23JJ6*6Pp@Y2d>i@udsI?V zhZk(ZBql|*hs=1@JQQr4)*XDH@6Fmv>Bgsi;=6op&S8jeEjE z&7(qlVvg@s&nSCdn^=xQI9G(sB-1pr4I_Xc?~XvdYzFCy%=Y&Y1hgb z9cE=Zl2t;Il{T)AnvHdnz)c3j=iD#M{;a8RFSEOe(d~@TQfWLo;#B5jyUG!X?(3-; zDlV#R*-ufj@heI&-!EHryDia_G58R*3GM0n6XShD6Th7Ijxp((bJ;2E6>qY#lhw5lAmHS5KNOt$EunrVj`YDhIzb z;jg>4a`TtEy})01)b8Z*wS$b{soIBie{}vq3NvIWO#*8X@GTgdwBhz~A}Oz#{3aOW z9R2ylm2uTtiZ_DoN0QP7yg1+Vne8a7m`fVsECL38+*T+G>yn?31ij-sb0R-m~g6kHYfytehqdU zYpUzpu!D7$lc)l8d)4ybV5fZMhL%)t7iNm!OrPbq?ngE|47w)4yi)7EF$AyXTiWuoBk;6yTW?KEI+n9sQuv5QP@Z6weItCvgYEv*GSe} z_}Qi2q@r18ZVB){B=PRA882}_Y)56hyE8gug0TxJk)>mFI#rQdb^gB2_X&Q*#0a=z z+wSFaq({#WVlZ4*_8Orbb3?0ox@Rq_?p+8kn&=x}bYuK9)dErJYZy1I$#67L_QTeG za=XKcj1VSK(7nPdqj`0#1g@Tt?9pm>YxE<699gP~jr0{NRGSj4%**{=?pnS9txNASeL!(< z88nmLC-6|jx$;pC?Nn)5_dFc0WL;pSc201aTHd_)1gYv7B4VCt>{h6YdL-7>m{0rl z1MibeM5XVP6yCNTnt~XrGS|p0m$N@R8ce7u#FnQeSN6UkEV42!c?9Hmr7wh_UOZoM zYJSiexbOQgchujBTpFgBceY&6uUQCE@$%xi`?8H%CGr!)lO78lQ;ey=f-KzCI;}mR z8|kM7EXWMQ1)jrh3ayQNN#XK7{X%+#Y4j)Z!r2Y~x=9bI=1Rvb3#r2}MLW&esd3VX zA?`*#Z}X%o>UM~V#f{*KW6cuAwvGl)$`YKr;m}cV+NP|ZR*5jYX(;C-fe+kt19b;I zYOwwl-yXD_Apc;?)Q@==*{`-&<*}n|E2K{s6sTsnmc|x76z8X$nMXOwn0aUqKJ;qr zI*fVA9v{+9*;@qLHm>_?r}V{xL|h28e}t@E-MV!ut+>%WHbj-IDv=xvE)zHHT9=&U zhmup!f_*&2wY@x%v)tZh8h&gsqD8|VyGJuz%GY>(QIu*>iulw?xD1@cr2r!)Pl!cb zE^J+EJeBU}rVg<=#=vC#SZClBa-y=>+K06{Qw=eHib>MccegIsOK6#l*3Kfy9^EZj zie-x>bXyyc1t~-E)-e4-)>&6ty0`K^WD?tB7=t@SI3BIq2f74<4xXs7!ifrasR#$* zyhqH~+VBCzV?>~mWs=3{eO!ID59oqoomCZHpSI0ax3VivLH3*?yrw;vm0-R* z;b|<>k+O;NW-B>OULUeM&1A|-s9i;hU|r17EF}vrAQbL0i+K}aohQ@MT~6+z3nq9= zYVsYSR3-T;cWS%VU8n9!#aN!=%3j%sS=NlD9xH6Q)bJE4+DxXj@(lU48NS5%D^ISC zSmQ+g%tiU%{t)Y{dhsjtdEGvjM2|VmrU(RsbUCd;IA0e%7X7_EX@%o>M(9|*EmUbW zb#Qo362nNR!=ZD-?ob1N5vdz0j=^1y0aYhZ=Yl0O0U znsi7?NEpCORwn}{7|2tTmz5>Z#w#mb*9Dt*4R3zN>NDaPJo(kcU_3@{4dW^ur3#X@ z??$z~pF~w6F1-7mBwQ>I>RUM|Q0!{kI~Z)(<`y2hup2>)Q{u9%){{_gC&O~D>K4+> zc~8<1ev-;u#eVstpt?CV(Ft*W%~Xd_o2$-`+)8x*x-ha&^X}G!&`HV_D=R~JP7$`W zoozr#QWMmi{AE9(3|1+xl@t^eSxSg@n_YuUv@Z2-w5({4zAlCCIr^$uY^h=Et0&ap zi%(LYMa&H9uF5l1G*xD@Ily7cesvnp2J@A@^?g5v86@%r8R9D)?-n_m43af@7}gp8 zc;sc5{m{tT%}rmIt<{-$G=ei&F|>GPU&;nXEdTwRxO&P0 zQ+un;C*_M#9IP}K<6o#m(o1Oy)42ZuZ#vlSw(z(F=?mv-`g!Mv-?eTQPSjM+6E!Yu zlCy+lO@h`8PP>0Zeqoy0yRi?I4k9Cvk>@$)b4t`(q;rsgc@4Tq;L7WEq}<$iaHbgJ$%KCF7-*{{By)kVmi zf_EJ?8T#kB@*`|bJk%1jkY+aRvN34ivQ#p8)U7|**~=R6-IgGi zvHrzLN9Za8<0oELe0f1_5Iz6YKsdT<&T%UJLp8?7R;l}gf5PUl&G%YCyycfyr$rNt zZ$#XR(HOD@lctE}kCiSB4f)j=aa8cbM;BUEW)Abu-anrwrEC|x*w3gNDe)(c{&NI0|V!NrDZV||qZ>6fe=tu0Xy2<)2)a?|* zx1o1~&TJHpCo#u7@49NBEB0fd|71dwB-E)^;Sl@TjZ4%vMK*E^PTFg^>f2I+xgD#m zX?aO!Tm^l8bV55m-~DNZo$$+;3@AizYg3;iHzsFJ*BDLA)l|#1wKgTNl$1b6&bf4I zs$Tdy`BDY{^~xz=8tw}Q%wfANshII@(##@XpAK&?2?s^^nj&jq+k+R%_nB74ATc<* zJqd|fM?ag{q<6+s1E2ge6kb31E1TDGI9E5~@?FA&r~ivcobDPl7SP?yPy4FG(N^dF zEI}BLLlqvR&BJUX`bRg8UfACVzNgn=;^$Je4SEaosp|RU)hw#{4)0u)#6_%X!hy+N z!#*ODr|8s~3OYmV2&+roK9+scD^u)?1E%Bd`8D;Ws3m1)O4dUUVH(uNM)6&2=aD!B zg2~ff{D4Y=`d5*aaXt9sL0>^XCS7|mvh=j5^3vIKZ%cmacp&|9D25fuZRr%Q>l!DI zUYaCbc-XEc`;El?(>3x5!x~dv(gG*lwZf?HHw(8h12c&_ZH&lbLiqiwk*1jy%Pzf= z`&7Vrue+vzERMgPJmWoYTkSYJ=EbggHo^3p4TKh`aFZtZ+MBaUo1SoCagkSjGuxpw7xSA zvl3`x8FmkG@oXEh@GWWRea$cBplhA&AyXoVOin{dUI>EEs@n4vo5o6y8xBkrG)VQt z`yfhdvPVUFmk#LHEPOTYR!R1Cz#I%6Y!51vhkXre^-cX0L!RtPPskTEJa5B!Vqz9<4)YYZm-PMlVf;||Jv?qW>2T{zYeTU1sgNN`-Oh( z0%#upgcuE1G?oGIUT8Y0-=OUYe@sXmlK;24`dKu{(HNh z{u`_jf4`;jNBZx-gE~Cs(*QmH-u|RK#r*frkUt7Ar&Wl&;h~1VJ?Bab|4Zwv=YEN# z@^w__ti1`IcJUG5Kkbs;Inc2BmCpgl!&euF9xMnVTs+j|NpokpAjocjF)(iWQf+H@ zASqA6`_vAZ4PH)T1v&&Rh2u|5KPeP;*8|HwSGc=o`$`(_i-qi#Cp4OuKG{ zd1)R9$IK1HziRkcnaAVn+`C8bL^4D%{Hk zDWdPhxx#6^s^7I4ltp9HSZl1}B1=4FEqfz8R4S@l)H~0D>XEY)arUfH>iOBj&jcA6 z??zB`Y&biPm%1?y_Z`|RhwvZWL)ey@O+C|OVZ53sV%**bj$f2X7D-h0^TC7|+0{24 z_I#bM1!W>r7S7sXd}upr3U^Xd;iX$ysGn3?IXmC26nSI^)iw7HGM9Q6cDtkHEHdS$ zsjc$tAefK*6fr(`rDw(GL5G2{pQ*WLd2*w(6?j>Ydy~p4E}iZ~op||c3!&zCD>8tY zE)q@*R>9%5bya|LfirH#d$(-^R?xwGNT`AZNQzOAhl>Fw*&{3GLt_&we~T?Xs_*{k-Sd>7YBYX~cHtC+Jx zXrca&thotn;mjI^OBZuN>FuQ#cZkW029#Q?4Hw@d8TEmA)=Mro3cq0;Y9yyzuRu;v75W<%gdZ*f&KaQ0N{6y zMeM>_brEcA9soT5v7hAX5G#_VMIC`9*FMm@=(9}f__D@Q@Tp$LNoi$eW$C}V=zMS9 zylLZn(!A)at1r+^QX&#i5!Y;rubRZpbu&|~s1D8T!K#i6s+Suzjy{jO1IT>GKn&km zmw$_e>RFzNl(mFjQ|`z7w6l0^FPiCZc{}Z(m4K;BgFChP$&JUFs)v5N8*Q`v;Z#NK zCvx@T^AORY&Ly4P+het6J|9Rkj==IS`T@Z2PbPV0KEVCRu)H2}f2jH5fjsyD0)eW4 ze0;TD@9D9uxuH4-#{FG%woq4N{Mo{(DgJ7JlB-bM-qvr!QnKqBt?k!jdGAWAbu}fp znh7Q@K938zBUju!@Nqu-VAds1Jfc-kW=Oj&&cD6Ad17uUel(X~C<)x%auFi^qCG5G zkkb#^6qvNGX?}3&#BKsuU+4JkAK^buN3b!%j^X9nD zCZ1V`pUVHKIMKz+2bnO$ti7;H6^AU}0_Rv`(G}QPMi<{W=nZnhq=MLscB{xqz-4;g z$1y)Q_X%;49etb^P#Kk~%7=|BlXS;gTE?erzok^i4GVA5QU~&S=eSD6jd(h%%0EJd z7=e_o#}gWgyedg~y^4xnwdTiz+Jvoa6R*Qhr0et1w2D_zOhm{V&3>w~{JkbJxgeft z6M$|lZ__8|NpN?05vH{8L8}aYPBTC++g^T_?Bz3*?ilBRzokS|{ zoe-Cq@1x;RaI-yK##B}GP(}WDsec=LsmYZ_e?^sE4J;k5QI>uX7EbThQSzZljRB0} z)=0Pjj<@88>(dMsFR6{oArR3J;~h_f>n5-#-XdQV6(FgFGvb9c;XX>&70qL-dkfEA zE0b${6SMTDRKQ%#fwC0S;r+A8`8{WlEeLU>{w>6*_t;E|q?535mr|O~U8wjKv@G=z zdGs&K{XpnMhWPB%OR3aV%gW>Ny#Nr)@{dn&QSYOl2UxoU?(;k~mA1?n+Co$ea~OXL zFCo8G^bstdZ(ic)09P(Ekw&d}+KO|uX^Vpvi@&x%in8Q?qzYh-WFNiHw&9|uiR4rs-w8wYFJQ6TRcKUKQ53=o|NZ#=wXFZ* zP=}l}WITEFxlQtA-|L)uR_@m!kW(ONyMo4F`?P1pkrLV0DzYgKm-MqCJ_II>$Nv{m zj{4-8bO0x*WMbje=O-u%!e#K4Ad(Btc!Rt`Y&{TBPa>r>)^STfya^)Oih6}jnmKo! z9b(0k%NIE@^vZa-{b6`x)qviKU2EXx1SiD&4Q!a-T-0Ci>a0Ao@62gx!ucfK*za34 zplkpNCro}qy^_&Po+g8ESi&B*e<}E$Tm{=-{qw=^Xe(VBOcz}zxnDFs4K_z}#tAQ! z22*wlKXlaan;6DoNA`m4tY0i&2|NeZ`UCHr45i|f6fBDEy-3#cyB2auh4f5%_Dms~ z5wn7+-!>(j7oz!1^!ERq=-J3eUiMM-{ojImROd$JTGzRHtScQ1uv=%7PYulAg?4lBd(KTPVsDkr+IhZCv^4G@~d@V6$t&GM9ZclJR_k&nFBAQeW{O zyUJ)O=bnKqP2ma~`$)Y@R=r*7PD408Zi)-!iA)>Zxox*U*`Elq=P|GFRVf z-?4JwRKK5VWt6rmky}6PNv7t*G6HpJ<%7#tRsGMvm21^poUr6ew4LG?ZW-5x@9U#o zb!y<$d^Jm|-{1N!tzU8Miz~mVSU#>_*d>0TW2oPdNAICq9f|3gIvm{d-x9u_k|hTM zYv|}}3FHj7*{drPZymbW`vhkjN7MFQVIx#q%e0LMNu-TmVa<`Mh-txcmxk_q4oDmo z%DLZg#BlRm2!fei-%}-`q<;lD{u-kuLNgtMg@vQ4q`qN_@9@_*m@~X2823S*@bztp zmrbuoYB?y$+bT8g*aTsWrFgup+c(FWJAax}Nc!z9#4B#x7LA&{+z}MzhG58;i<7|< z>JHCL-_X&R^;N31nN4ur?VM4lEZc~2JqsD5IXZ~t)UV5$S}&ILKga`cX|**(zt=|T zFun=ZAMyvq*9yX%w0<2{p&IVb+-#ZlKZ?87u%yy0OsAPsPBYzRs!>ztbe*zn@>Yt1 zTIw;Myrg1k%9sgW!pcO{xR}|PmoyD>vOzKL}qK& z>HO>KNu0M2?1N8<746?Vge7E+ z0qO0&^b+B^%6Cpc>?1=p*@oEPTK&N)c$Gsa(=W+AOc(9CaTVkFF5KJu=S2pr`o|k= z-~v_jaS}wiL+0j!1SQ7LFxix*ou;)k_(*K7;l7M0oEq+q4)EjQw7J)slOK1OVhC+y zWnx7;iLC0i)=FVAEff1!sZ&Hbck0Ga))y)FUX7OJ5owt6=qBG^26$CVk%RLV zLxpAwJ`T$6kp$L96rga5VQQN6`$G7S?vw~c1KWq?xzc=S?r6O?CERdO$}kzEQC5+~ z@x)2+tkPJFXHUGWh>i*w-oOjVOHnns^KU;d-G(16e>A$?Tt7Qs<82$}hlR%sRu8p< zyanFsG9BHE51lI~wvf*2V^XtmC>!V_j;ah@#sw-=dIsZ)>yr(YK%O9OqdGxd!(D;R z;Eh{}hsp6iXS|M^(H+Ky*F`!kxsu?Frt#l5+L81rpjSHBU8Pe1247z9a?swJ=S6!t zQ2IU9AE;aze@mSX65?&{-*ZEo#Lp!=6uc&+JP95i8L>8{4DpxlH{{kV1u=M_641wS{HsBTot2Kh`ca>|#Pi2Zir7F1y`V%X@MC>QEOo0-pb5`N8qD}+` zmM7B|#-i+3C@hUiFI!ulZqb7b2EvZaq`k*^p7^<|X6-d1t|-fpQH6BxFdMOU`GTE# zoJ1Y>GamD7N1&fh+gD#1_dYU{NWSNI0Z_&MEv|N`GRC2_$Wkurz&Ru$boaNt`~Kl$ zlbQOu)6+uTk32bRak9)T6wZv0wWK!w({B49z(K8H3RKW$U^_zRB}#mW=&vY(J!b8> zDp`?MnJ2>kB_j#La%GmU{4)dI&6L8WDU?O+^wHV&;Cc#FRs{UCqg-9jKU&JpXJ48c zVr2GY+a75AO(jne=R}Xjgyos?0?S^8QpJ*iC{`uKRe}e0EZw2ZO%$|U^U)hS6RuyV zrW^8|h~$7XRTr6)Z^_X)n|w%37GF7qquhmqogypWQbs1IwHH1$WRP6-OORW@oQO-#BAH+r^zr>Vx%a zg4u73F9V!ib2vn*J-Y8bO|M*Democ^nwB>!@5OvxlsP67u^~v7G$|V1bzcda*fdb*WP7Q|G*`v*A${9C5M|0DjT|dNy z|9)_dZ7ZCt;~N%FXf;wxiS?R_!VAFmH|2b;GeYq%k0-`=Uar%M70q=yR;@D-Bx0lf z^Qo|kjeq91&=M{a!5<<6oGC%qqZ^LLJtKlmMj)AGsmU>#68Y}ES+PJY5C^dQ{gTr> zO@iD2R1z4u{Vdz_PBum1H#ZE`mUb%_ zOF{nj_40%*kp_3tH|!bY1Trh|?k8e>jiC58PS&cn(amA#jk)yXt&WFe&}xFUZTg+~ zA^RpSQK!|W4NP;Qganp9A4+Cxromk>*jb78*<>a89aEwi!SF^7NZaABekeS){-Ij> z(|UwqkY^N|53Au`**oDsY30Q!NqW8LVt@0*JvD@}$1J~3Hapgd@!+fgg`I1l{OR+w zYC4A;ZWw_ylO5%|(C^1lQF@*)ZWRL zO-cpDSak`e&*${8`S?fgeu-|-8GPp1Wg*}3eV>N8$n$Zs@zeh6geE=Ev{s3#syF+o751MHiNA}Y3qBRxgT!@780pjB=5Atk zYCM`x?5!CcY{+M~Qo)#*@$0A?MZt2(i-E3X1B%?8vG7V>AdWisTF-qAZ)7fa^Sw50 zPhl*hos}Js*-2Kw^UsxNWc zd@|YMm1wu-f8?9LvYGkp-i0<#AB$`_X L=ys6q@O#qViLZJi literal 0 HcmV?d00001 diff --git a/Doc/img/InputGenGUI.svg b/Doc/img/InputGenGUI.svg new file mode 100644 index 00000000..31df1d49 --- /dev/null +++ b/Doc/img/InputGenGUI.svg @@ -0,0 +1,1220 @@ + + + + diff --git a/Doc/index.html b/Doc/index.html new file mode 100644 index 00000000..218452f4 --- /dev/null +++ b/Doc/index.html @@ -0,0 +1,104 @@ + + + + + List of scripts \ No newline at end of file diff --git a/Examples/+BrDemo/+InputGen/from_file_signal_gen.m b/Examples/+BrDemo/+InputGen/from_file_signal_gen.m index cd210bca..10a3d952 100644 --- a/Examples/+BrDemo/+InputGen/from_file_signal_gen.m +++ b/Examples/+BrDemo/+InputGen/from_file_signal_gen.m @@ -3,34 +3,47 @@ %% Create example files % BrDemo.InitAFC - -%% -% -BrAFC.SetParamRanges('Pedal_Angle_base_value', [0 61.1]); +Br0 = BrAFC.copy(); +BrFromFiles=BrAFC.copy(); %% -% -BrAFC.GridSample(3); -BrAFC.Sim() +% Creates 3 simulations using the default input generator +Br0.SetParamRanges('Pedal_Angle_base_value', [0 61.1]); +Br0.GridSample(3); +Br0.Sim() -%% Create files +%% Create files +% Files should be mat files with with a 'Time' array and a 'Pedal_Angle' +% and 'Engine_Speed' arrays of the same dimensions % -Pedal_Angle_values = BrAFC.GetSignalValues('Pedal_Angle'); -Time = BrAFC.GetTime(); -%% -% Files should be mat files with variables being arrays of size N x 2, the -% first column being time values and the second signal values. +Time = Br0.GetTime(); +Pedal_Angle_values = Br0.GetSignalValues('Pedal_Angle'); % this has three individual traces +Engine_Speed_values = Br0.GetSignalValues('Engine_Speed'); % this has three individual traces for ifile = 1:3 - Pedal_Angle = [Time' Pedal_Angle_values{ifile}(1,:)']; - save( [ 'AFC_input_data_' num2str(ifile) '.mat'], 'Pedal_Angle'); + Pedal_Angle = Pedal_Angle_values{ifile}(1,:)'; + Engine_Speed = Engine_Speed_values{ifile}(1,:)'; + filename = [ 'AFC_input_data_' num2str(ifile) '.mat']; + save(filename , 'Time', 'Pedal_Angle', 'Engine_Speed'); + filenames{ifile} = filename; end -%% Create signal generators -% -sg_pedal = from_file_signal_gen({'Pedal_Angle'}, 'AFC_input_data_*.mat', 'Pedal_Angle'); -sg_engine = constant_signal_gen('Engine_Speed'); -BrAFC.SetInputGen( {sg_pedal, sg_engine}); +%% Create signal generator reading files +% +sg = from_file_signal_gen({'Pedal_Angle', 'Engine_Speed'}, filenames); +BrFromFiles.SetInputGen(sg); %% -% BrAFC now reads pedal_angle input from files. \ No newline at end of file +% BrFromFile now reads inputs from files. It has one parameter named +% Pedal_Angle_file_idx which controls which file is read. + +BrFromFiles.SetParam('Pedal_Angle_file_idx', 2); % Computes using file 2 +BrFromFiles.Sim(); +BrFromFiles.PlotSignals({'Pedal_Angle', 'AF'}); + + %% + % + BrFromFiles.ResetSimulations(); + BrFromFiles.SetParam('Pedal_Angle_file_idx',[1 3]); % computes using file 1 and 3 + BrFromFiles.Sim(); + figure; BrFromFiles.PlotSignals({'Pedal_Angle', 'AF'}); \ No newline at end of file diff --git a/Examples/+BrDemo/+InputGen/multi_pulse_signal_gen.m b/Examples/+BrDemo/+InputGen/multi_pulse_signal_gen.m new file mode 100644 index 00000000..8d095fe7 --- /dev/null +++ b/Examples/+BrDemo/+InputGen/multi_pulse_signal_gen.m @@ -0,0 +1,15 @@ +%% Create generator +input_gen = multi_pulse_signal_gen({'In1', 'In2','In3'}); +InputGen = BreachSignalGen({input_gen}); % generator with 3 pulse signals +InputGen.PrintParams(); + +%% Nominal trace +figure; +InputGen.Sim() +InputGen.PlotSignals() + +%% Varying parameters +figure; +InputGen = BreachSignalGen({input_gen}); % generator with 3 pulse signals +InputGen.SetParam({'period','delay','In2_pulse_rel_delay','In3_pulse_rel_delay'}, [1.5, .5, 0.25, 0.5]); +InputGen.Sim();InputGen.PlotSignals(); diff --git a/Examples/+BrDemo/AFC_5_3_MaxSat.m b/Examples/+BrDemo/AFC_5_3_MaxSat.m index 5068fe5d..7ce84dcd 100644 --- a/Examples/+BrDemo/AFC_5_3_MaxSat.m +++ b/Examples/+BrDemo/AFC_5_3_MaxSat.m @@ -8,7 +8,6 @@ %% % Load some properties. - STL_ReadFile('AFC_simple_spec.stl'); diff --git a/Ext/Specs/Autotrans_spec.stl b/Ext/Specs/Autotrans_spec.stl index 4eee7c7f..723f4104 100644 --- a/Ext/Specs/Autotrans_spec.stl +++ b/Ext/Specs/Autotrans_spec.stl @@ -18,7 +18,7 @@ param t1=1 # Other formulas -param vmax=150, t1=1, rpm_min=4000, rpm_max = 5000 +param vmin= 50, vmax=150, t1=1, rpm_min=4000, rpm_max = 5000 speed_bnded := speed[t] < vmax RPM_bnded := RPM[t] < rpm_max diff --git a/Online/examples/Autotrans_online/Autotrans_online.mdl b/Online/examples/Autotrans_online/Autotrans_online.mdl index 916f8de5..5db41a8e 100644 --- a/Online/examples/Autotrans_online/Autotrans_online.mdl +++ b/Online/examples/Autotrans_online/Autotrans_online.mdl @@ -1,17 +1,22 @@ Model { Name "Autotrans_online" - Version 8.5 - MdlSubVersion 0 - SavedCharacterEncoding "ISO-8859-1" + Version 10.1 + SavedCharacterEncoding "UTF-8" GraphicalInterface { NumRootInports 2 Inport { Name "Throttle" BusObject "" + OutputFunctionCall "off" + SampleTime "-1" + UnitExpr "inherit" } Inport { Name "Brake" BusObject "" + OutputFunctionCall "off" + SampleTime "-1" + UnitExpr "inherit" } NumRootOutports 3 Outport { @@ -19,20 +24,23 @@ Model { BusObject "" BusOutputAsStruct "off" SignalName "speed" + UnitExpr "inherit" } Outport { Name "RPM" BusObject "" BusOutputAsStruct "off" SignalName "EngineRPM" + UnitExpr "inherit" } Outport { Name "gear" BusObject "" BusOutputAsStruct "off" + UnitExpr "inherit" } ParameterArgumentNames "" - ComputedModelVersion "1.312" + ComputedModelVersion "1.313" NumModelReferences 0 NumTestPointedSignals 3 TestPointedSignal { @@ -57,7 +65,43 @@ Model { MaxPoints 5000 Decimation 2 } + NumProvidedFunctions 0 + NumRequiredFunctions 0 + NumResetEvents 0 + HasInitializeEvent 0 + HasTerminateEvent 0 + PreCompExecutionDomainType "Unset" + IsExportFunctionModel 0 + IsArchitectureModel 0 + IsAUTOSARArchitectureModel 0 + NumParameterArguments 0 + NumExternalFileReferences 3 + ExternalFileReference { + Reference "simulink/Logic and Bit\nOperations/Compare\nTo Constant" + Path "Autotrans_online/Online STL Monitor/Stop when rob below" + SID "141" + Type "LIBRARY_BLOCK" + } + ExternalFileReference { + Reference "simulink/Logic and Bit\nOperations/Compare\nTo Constant" + Path "Autotrans_online/Online STL Monitor/Stops when rob above" + SID "140" + Type "LIBRARY_BLOCK" + } + ExternalFileReference { + Reference "simulink/Logic and Bit\nOperations/Compare\nTo Constant" + Path "Autotrans_online/Online STL Monitor/Stops when rob above1" + SID "158" + Type "LIBRARY_BLOCK" + } + OrderedModelArguments 1 } + LogicAnalyzerPlugin "on" + AnimationPlugin "on" + WebScopes_FoundationPlugin "on" + SLCCPlugin "on" + DiagnosticSuppressor "on" + NotesPlugin "on" Description "Modeling an Automatic Transmission Controller \n\nIn this example, Simulink(R) is used to model an a" "utomotive drivetrain. Stateflow(R)\nenhances the Simulink model with its representation of the transmission\ncontrol" " logic. Simulink provides a powerful environment for the modeling and\nsimulation of dynamic systems and processes. " @@ -67,6 +111,7 @@ Model { "s strength in this capacity by performing the function of gear\nselection in an automatic transmission. This functio" "n is combined with the\ndrivetrain dynamics in a natural and intuitive manner by incorporating a\nStateflow block in" " the Simulink block diagram.\n" + EnableAccessToBaseWorkspace on ScopeRefreshTime 0.035000 OverrideScopeRefreshTime off DisableAllScopes off @@ -76,6 +121,7 @@ Model { MinMaxOverflowArchiveMode "Overwrite" FPTRunName "Run 1" MaxMDLFileLineLength 120 + LastSavedArchitecture "glnxa64" Object { $PropName "BdWindowsInfo" $ObjectID 1 @@ -85,7 +131,7 @@ Model { $ObjectID 2 $ClassName "Simulink.WindowInfo" IsActive [1] - Location [120.0, 105.0, 1371.0, 843.0] + Location [3000.0, 397.0, 1371.0, 843.0] Object { $PropName "ModelBrowserInfo" $ObjectID 3 @@ -95,6 +141,7 @@ Model { Width [50] Height [50] Filter [11] + Minimized "Unset" } Object { $PropName "ExplorerBarInfo" @@ -107,30 +154,65 @@ Model { $ObjectID 5 $ClassName "Simulink.EditorInfo" IsActive [1] + IsTabbed [1] ViewObjType "SimulinkSubsys" LoadSaveID "148" - Extents [1337.0, 673.0] + Extents [1333.0, 602.0] ZoomFactor [1.43] Offset [-6.8839597902098149, 0.0] + SceneRectInView [-6.8839597902098149, 0.0, 932.16783216783222, 420.979020979021] + } + Object { + $PropName "DockComponentsInfo" + $ObjectID 6 + $ClassName "Simulink.DockComponentInfo" + Type "GLUE2:PropertyInspector" + ID "Property Inspector" + Visible [0] + CreateCallback "" + UserData "" + Floating [0] + DockPosition "Right" + Width [640] + Height [480] + Minimized "Unset" + } + WindowState "AAAA/wAAAAD9AAAAAgAAAAAAAAC9AAAB+PwCAAAAA/sAAAAWAEQAbwBjAGsAVwBpAGQAZwBlAHQAMwEAAAAxAAAB+AAAA" + "AAAAAAA+wAAABYARABvAGMAawBXAGkAZABnAGUAdAA0AAAAAAD/////AAAAAAAAAAD7AAAAUgBHAEwAVQBFADIAIAB0AHIAZQBlACAAYwBvAG0Ac" + "ABvAG4AZQBuAHQALwBHAEwAVQBFADIAIAB0AHIAZQBlACAAYwBvAG0AcABvAG4AZQBuAHQAAAAAAP////8AAABiAP///wAAAAEAAAAAAAAAAPwCA" + "AAAAfsAAABUAEcATABVAEUAMgA6AFAAcgBvAHAAZQByAHQAeQBJAG4AcwBwAGUAYwB0AG8AcgAvAFAAcgBvAHAAZQByAHQAeQAgAEkAbgBzAHAAZ" + "QBjAHQAbwByAAAAAAD/////AAABrAD///8AAAVbAAAClwAAAAEAAAACAAAAAQAAAAL8AAAAAA==" + Array { + Type "Cell" + Dimension 0 + PropName "PersistedApps" } + WindowUuid "665e94a9-b1c8-4cb3-8bc2-37ce05ddeb17" } + BDUuid "f5414001-8aab-46f3-8566-9478d25a31a9" } + HideAutomaticNames on Created "Tue Jun 02 16:12:01 1998" Creator "The MathWorks Inc." UpdateHistory "UpdateHistoryNever" ModifiedByFormat "%" LastModifiedBy "alex" ModifiedDateFormat "%" - LastModifiedDate "Mon Jun 13 15:45:35 2016" - RTWModifiedTimeStamp 387733519 - ModelVersionFormat "1.%" - ConfigurationManager "none" + LastModifiedDate "Tue Jun 01 14:41:20 2021" + RTWModifiedTimeStamp 544458989 + ModelVersionFormat "1.%" SampleTimeColors on SampleTimeAnnotations off LibraryLinkDisplay "none" WideLines on ShowLineDimensions off ShowPortDataTypes off + ShowAllPropagatedSignalLabels off + PortDataTypeDisplayFormat "AliasTypeOnly" + ShowEditTimeErrors on + ShowEditTimeWarnings on + ShowEditTimeAdvisorChecks off + ShowPortUnits off ShowDesignRanges off ShowLoopsOnError on IgnoreBidirectionalLines off @@ -139,22 +221,34 @@ Model { ShowSignalResolutionIcons on ShowViewerIcons on SortedOrder off - ExecutionContextIcon off + VariantCondition off ShowLinearizationAnnotations on + ShowVisualizeInsertedRTB on ShowMarkup on BlockNameDataTip off BlockParametersDataTip on BlockDescriptionStringDataTip off + BlockVariantConditionDataTip off ToolBar on StatusBar on BrowserShowLibraryLinks off + FunctionConnectors off BrowserLookUnderMasks on + MultiThreadCoSim "on" SimulationMode "accelerator" + SILPILModeSetting "automated" + SILPILSystemUnderTest "topmodel" + SILPILSimulationModeTopModel "normal" + SILPILSimulationModeModelRef "normal" + SimTabSimulationMode "accelerator" + CodeVerificationMode "software-in-the-loop (sil)" PauseTimes "5" NumberOfSteps 1 SnapshotBufferSize 10 SnapshotInterval 10 NumberOfLastSnapshots 0 + EnablePacing off + PacingRate 1 LinearizationMsg "none" Profile off ParamWorkspaceSource "MATLABWorkspace" @@ -164,7 +258,7 @@ Model { TryForcingSFcnDF off Object { $PropName "DataLoggingOverride" - $ObjectID 6 + $ObjectID 7 $ClassName "Simulink.SimulationData.ModelLoggingInfo" model_ "Autotrans_online" Array { @@ -180,27 +274,85 @@ Model { PropName "logAsSpecifiedByModelsSSIDs_" } } - RecordCoverage off - CovPath "/" - CovSaveName "covdata" - CovMetricSettings "dcmtr" - CovNameIncrementing off - CovHtmlReporting on - CovForceBlockReductionOff on - CovEnableCumulative on - covSaveCumulativeToWorkspaceVar on - CovSaveSingleToWorkspaceVar on - CovCumulativeVarName "covCumulativeData" - CovCumulativeReport off - CovReportOnPause on - CovModelRefEnable "Off" - CovExternalEMLEnable off - CovSFcnEnable off - CovBoundaryAbsTol 0.000010 - CovBoundaryRelTol 0.010000 - CovUseTimeInterval off - CovStartTime 0 - CovStopTime 0 + Object { + $PropName "InstrumentedSignals" + $ObjectID 8 + $ClassName "Simulink.HMI.InstrumentedSignals" + Array { + Type "Struct" + Dimension 3 + MATStruct { + UUID "76a3aead-342f-4846-8002-b5b5397d0511" + BlockPath_ "Online STL Monitor/Demux" + SID_ "137" + SubPath_ "" + OutputPortIndex_ [1.0] + LogicalPortIndex_ [0.0] + SignalName_ "" + SubSysPath_ "" + Decimation_ [1.0] + MaxPoints_ [0.0] + TargetBufferedStreaming_ [0.0] + IsFrameBased_ [0.0] + DomainType_ "" + Array { + Type "Struct" + Dimension 1 + MATStruct { + } + PropName "DomainParams_" + } + VisualType_ "" + } + MATStruct { + UUID "0aa188bf-e7bf-4a86-aa1a-862ee617c4ce" + BlockPath_ "Online STL Monitor/Demux" + SID_ "137" + SubPath_ "" + OutputPortIndex_ [2.0] + LogicalPortIndex_ [0.0] + SignalName_ "" + SubSysPath_ "" + Decimation_ [1.0] + MaxPoints_ [0.0] + TargetBufferedStreaming_ [0.0] + IsFrameBased_ [0.0] + DomainType_ "" + Array { + Type "Struct" + Dimension 1 + MATStruct { + } + PropName "DomainParams_" + } + VisualType_ "" + } + MATStruct { + UUID "f8e413b6-c88b-4214-be2a-6d940cce299d" + BlockPath_ "Online STL Monitor/Subtract" + SID_ "157" + SubPath_ "" + OutputPortIndex_ [1.0] + LogicalPortIndex_ [0.0] + SignalName_ "" + SubSysPath_ "" + Decimation_ [1.0] + MaxPoints_ [0.0] + TargetBufferedStreaming_ [0.0] + IsFrameBased_ [0.0] + DomainType_ "" + Array { + Type "Struct" + Dimension 1 + MATStruct { + } + PropName "DomainParams_" + } + VisualType_ "" + } + PropName "Persistence" + } + } ExtModeBatchMode off ExtModeEnableFloating on ExtModeTrigType "manual" @@ -224,25 +376,30 @@ Model { ExtModeAutoUpdateStatusClock off ShowModelReferenceBlockVersion off ShowModelReferenceBlockIO off + OrderedModelArguments on Array { Type "Handle" Dimension 2 Simulink.ConfigSet { - $ObjectID 7 - Version "1.15.0" + $ObjectID 9 + Version "20.0.1" + DisabledProps [] Description "* Simulation Target Description\nDefault S-Function target.\n" Array { Type "Handle" - Dimension 8 + Dimension 9 Simulink.SolverCC { - $ObjectID 8 - Version "1.15.0" + $ObjectID 10 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] StartTime "0.0" StopTime "1" AbsTol "1e-6" + AutoScaleAbsTol off FixedStep ".01" InitialStep "auto" - MaxNumMinSteps "-1" MaxOrder 5 ZcThreshold "auto" ConsecutiveZCsStepRelTol "10*128*eps" @@ -253,8 +410,7 @@ Model { MinStep "auto" MaxConsecutiveMinStep "1" RelTol "1e-3" - SolverMode "SingleTasking" - EnableConcurrentExecution off + EnableMultiTasking off ConcurrentTasks off Solver "ode5" SolverName "ode5" @@ -263,15 +419,24 @@ Model { ZeroCrossControl "UseLocalSettings" ZeroCrossAlgorithm "Nonadaptive" AlgebraicLoopSolver "TrustRegion" + SolverInfoToggleStatus off + IsAutoAppliedInSIP off SolverResetMethod "Fast" PositivePriorityOrder off AutoInsertRateTranBlk off SampleTimeConstraint "Unconstrained" InsertRTBMode "Whenever possible" + SampleTimeProperty [] + DecoupledContinuousIntegration off + MinimalZcImpactIntegration off + ODENIntegrationMethod "ode3" } Simulink.DataIOCC { - $ObjectID 9 - Version "1.15.0" + $ObjectID 11 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] Decimation "1" ExternalInput "" FinalStateName "xFinal" @@ -281,7 +446,7 @@ Model { LoadExternalInput off LoadInitialState off SaveFinalState off - SaveCompleteFinalSimState off + SaveOperatingPoint off SaveFormat "StructureWithTime" SignalLoggingSaveFormat "ModelDataLogs" SaveOutput on @@ -290,6 +455,8 @@ Model { DSMLogging on InspectSignalLogs off VisualizeSimOutput on + StreamToWorkspace off + StreamVariableName "streamout" SaveTime on ReturnWorkspaceOutputs off StateSaveName "xout" @@ -301,24 +468,36 @@ Model { OutputTimes "[]" ReturnWorkspaceOutputsName "out" Refine "1" + LoggingToFile off + DatasetSignalFormat "timeseries" + LoggingFileName "out.mat" + LoggingIntervals "[-inf, inf]" } Simulink.OptimizationCC { - $ObjectID 10 - Version "1.15.0" + $ObjectID 12 + Version "20.0.1" Array { Type "Cell" - Dimension 4 + Dimension 9 Cell "ZeroExternalMemoryAtStartup" Cell "ZeroInternalMemoryAtStartup" Cell "NoFixptDivByZeroProtection" Cell "OptimizeModelRefInitCode" + Cell "BooleansAsBitfields" + Cell "PassReuseOutputArgsAs" + Cell "PassReuseOutputArgsThreshold" + Cell "UseSpecifiedMinMax" + Cell "EfficientTunableParamExpr" PropName "DisabledProps" } + Description "" + Components [] BlockReduction off BooleanDataType off ConditionallyExecuteInputs on - InlineParams off + DefaultParameterBehavior "Tunable" UseDivisionForNetSlopeComputation "off" + GainParamInheritBuiltInType off UseFloatMulNetSlope off DefaultUnderspecifiedDataType "double" UseSpecifiedMinMax off @@ -329,9 +508,11 @@ Model { CachingGlobalReferences off GlobalBufferReuse on StrengthReduction off + AdvancedOptControl "" ExpressionFolding on BooleansAsBitfields off BitfieldContainerType "uint_T" + BitwiseOrLogicalOp "Same as modeled" EnableMemcpy on MemcpyThreshold 64 PassReuseOutputArgsAs "Structure reference" @@ -348,20 +529,40 @@ Model { NoFixptDivByZeroProtection off EfficientFloat2IntCast off EfficientMapNaN2IntZero on - OptimizeModelRefInitCode off LifeSpan "inf" MaxStackSize "Inherit from target" BufferReusableBoundary on SimCompilerOptimization "off" AccelVerboseBuild off + OptimizeBlockOrder "off" + OptimizeDataStoreBuffers on + BusAssignmentInplaceUpdate on + DifferentSizesBufferReuse off + UseRowMajorAlgorithm off + OptimizationLevel "level2" + OptimizationPriority "Balanced" + OptimizationCustomize on + LabelGuidedReuse off + MultiThreadedLoops off + DenormalBehavior "GradualUnderflow" + EfficientTunableParamExpr off } Simulink.DebuggingCC { - $ObjectID 11 - Version "1.15.0" + $ObjectID 13 + Version "20.0.1" + Array { + Type "Cell" + Dimension 1 + Cell "UseOnlyExistingSharedCode" + PropName "DisabledProps" + } + Description "" + Components [] RTPrefix "error" ConsistencyChecking "none" ArrayBoundsChecking "none" SignalInfNanChecking "none" + StringTruncationChecking "error" SignalRangeChecking "none" ReadBeforeWriteMsg "UseLocalSettings" WriteAfterWriteMsg "UseLocalSettings" @@ -384,12 +585,12 @@ Model { IgnoredZcDiagnostic "warning" SolverPrmCheckMsg "none" InheritedTsInSrcMsg "warning" - DiscreteInheritContinuousMsg "warning" MultiTaskDSMMsg "warning" MultiTaskCondExecSysMsg "none" MultiTaskRateTransMsg "error" SingleTaskRateTransMsg "none" TasksWithSamePriorityMsg "warning" + ExportedTasksRateTransMsg "none" SigSpecEnsureSampleTimeMsg "none" CheckMatrixSingularityMsg "none" IntegerOverflowMsg "none" @@ -405,18 +606,20 @@ Model { UnderSpecifiedDataTypeMsg "none" UnnecessaryDatatypeConvMsg "none" VectorMatrixConversionMsg "none" - InvalidFcnCallConnMsg "error" - FcnCallInpInsideContextMsg "UseLocalSettings" + FcnCallInpInsideContextMsg "warning" SignalLabelMismatchMsg "none" UnconnectedInputMsg "warning" UnconnectedOutputMsg "warning" UnconnectedLineMsg "warning" + UseOnlyExistingSharedCode "error" SFcnCompatibilityMsg "none" FrameProcessingCompatibilityMsg "error" UniqueDataStoreMsg "none" BusObjectLabelMismatch "warning" RootOutportRequireBusObject "warning" AssertControl "UseLocalSettings" + AllowSymbolicDim on + RowMajorDimensionSupport off ModelReferenceIOMsg "none" ModelReferenceMultiInstanceNormalModeStructChecksumCheck "error" ModelReferenceVersionMismatchMessage "none" @@ -426,27 +629,51 @@ Model { ModelReferenceSymbolNameMessage "warning" ModelReferenceExtraNoncontSigs "error" StateNameClashWarn "warning" - SimStateInterfaceChecksumMismatchMsg "warning" - SimStateOlderReleaseMsg "error" + OperatingPointInterfaceChecksumMismatchMsg "warning" + NonCurrentReleaseOperatingPointMsg "error" + ChecksumConsistencyForSSReuse "none" + PregeneratedLibrarySubsystemCodeDiagnostic "warning" + MatchCodeGenerationContextForUpdateDiagram "none" InitInArrayFormatMsg "warning" StrictBusMsg "ErrorLevel1" BusNameAdapt "WarnAndRepair" NonBusSignalsTreatedAsBus "none" + SymbolicDimMinMaxWarning "warning" + LossOfSymbolicDimsSimulationWarning "warning" + LossOfSymbolicDimsCodeGenerationWarning "error" + SymbolicDimsDataTypeCodeGenerationDiagnostic "error" BlockIODiagnostic "none" SFUnusedDataAndEventsDiag "warning" SFUnexpectedBacktrackingDiag "warning" SFInvalidInputDataAccessInChartInitDiag "warning" SFNoUnconditionalDefaultTransitionDiag "warning" SFTransitionOutsideNaturalParentDiag "warning" - SFUnconditionalTransitionShadowingDiag "warning" + SFUnreachableExecutionPathDiag "warning" SFUndirectedBroadcastEventsDiag "warning" SFTransitionActionBeforeConditionDiag "warning" SFOutputUsedAsStateInMooreChartDiag "error" + SFTemporalDelaySmallerThanSampleTimeDiag "warning" + SFSelfTransitionDiag "warning" + SFExecutionAtInitializationDiag "none" + SFMachineParentedDataDiag "warning" IntegerSaturationMsg "none" + AllowedUnitSystems "all" + UnitsInconsistencyMsg "warning" + AllowAutomaticUnitConversions on + RCSCRenamedMsg "warning" + RCSCObservableMsg "warning" + ForceCombineOutputUpdateInSim off + UnitDatabase "" + UnderSpecifiedDimensionMsg "none" + DebugExecutionForFMUViaOutOfProcess off + ArithmeticOperatorsInVariantConditions "warning" } Simulink.HardwareCC { - $ObjectID 12 - Version "1.15.0" + $ObjectID 14 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] ProdBitPerChar 8 ProdBitPerShort 16 ProdBitPerInt 32 @@ -455,6 +682,8 @@ Model { ProdBitPerFloat 32 ProdBitPerDouble 64 ProdBitPerPointer 32 + ProdBitPerSizeT 32 + ProdBitPerPtrDiffT 32 ProdLargestAtomicInteger "Char" ProdLargestAtomicFloat "None" ProdIntDivRoundTo "Undefined" @@ -471,6 +700,8 @@ Model { TargetBitPerFloat 32 TargetBitPerDouble 64 TargetBitPerPointer 32 + TargetBitPerSizeT 32 + TargetBitPerPtrDiffT 32 TargetLargestAtomicInteger "Char" TargetLargestAtomicFloat "None" TargetShiftRightIntArith on @@ -483,45 +714,94 @@ Model { TargetHWDeviceType "Specified" TargetUnknown off ProdEqTarget on + UseEmbeddedCoderFeatures on + UseSimulinkCoderFeatures on + HardwareBoardFeatureSet "EmbeddedCoderHSP" } Simulink.ModelReferenceCC { - $ObjectID 13 - Version "1.15.0" + $ObjectID 15 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] UpdateModelReferenceTargets "IfOutOfDateOrStructuralChange" + EnableRefExpFcnMdlSchedulingChecks on CheckModelReferenceTargetMessage "error" EnableParallelModelReferenceBuilds off ParallelModelReferenceErrorOnInvalidPool on ParallelModelReferenceMATLABWorkerInit "None" ModelReferenceNumInstancesAllowed "Multi" PropagateVarSize "Infer from blocks in model" + ModelDependencies "" ModelReferencePassRootInputsByReference on ModelReferenceMinAlgLoopOccurrences off PropagateSignalLabelsOutOfModel off SupportModelReferenceSimTargetCustomCode off } Simulink.SFSimCC { - $ObjectID 14 - Version "1.15.0" - SFSimOverflowDetection on + $ObjectID 16 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] + SimCustomSourceCode "" + SimCustomHeaderCode "" + SimCustomInitializer "" + SimCustomTerminator "" + SimReservedNameArray [] + SimUserSources "" + SimUserIncludeDirs "" + SimUserLibraries "" + SimUserDefines "" + SimCustomCompilerFlags "" + SimCustomLinkerFlags "" SFSimEcho off SimCtrlC on SimIntegrity on SimUseLocalCustomCode off SimParseCustomCode on + SimAnalyzeCustomCode off SimBuildMode "sf_incremental_build" SimGenImportedTypeDefs off + ModelFunctionsGlobalVisibility "on" + CompileTimeRecursionLimit 50 + EnableRuntimeRecursion on + MATLABDynamicMemAlloc on + MATLABDynamicMemAllocThreshold 65536 + CustomCodeFunctionArrayLayout [] + DefaultCustomCodeFunctionArrayLayout "NotSpecified" + CustomCodeUndefinedFunction "UseInterfaceOnly" } Simulink.RTWCC { $BackupClass "Simulink.RTWCC" - $ObjectID 15 - Version "1.15.0" + $ObjectID 17 + Version "20.0.1" Array { Type "Cell" - Dimension 1 + Dimension 16 Cell "IncludeHyperlinkInReport" + Cell "GenerateTraceInfo" + Cell "GenerateTraceReport" + Cell "GenerateTraceReportSl" + Cell "GenerateTraceReportSf" + Cell "GenerateTraceReportEml" + Cell "PortableWordSizes" + Cell "GenerateWebview" + Cell "GenerateCodeMetricsReport" + Cell "GenerateCodeReplacementReport" + Cell "GenerateMissedCodeReplacementReport" + Cell "GenerateErtSFunction" + Cell "CreateSILPILBlock" + Cell "CodeExecutionProfiling" + Cell "CodeProfilingSaveOptions" + Cell "CodeProfilingInstrumentation" PropName "DisabledProps" } + Description "" SystemTargetFile "grt.tlc" + HardwareBoard "None" + ShowCustomHardwareApp off + ShowEmbeddedHardwareApp off TLCOptions "" GenCodeOnly off MakeCommand "make_rtw" @@ -530,11 +810,10 @@ Model { PackageName "" TemplateMakefile "grt_default_tmf" PostCodeGenCommand "" - Description "" GenerateReport off - SaveLog off RTWVerbose on RetainRTWFile off + RTWBuildHooks [] ProfileTLC off TLCDebug off TLCCoverage off @@ -546,10 +825,15 @@ Model { CustomInclude "" CustomSource "" CustomLibrary "" + CustomDefine "" + CustomBLASCallback "" + CustomLAPACKCallback "" + CustomFFTCallback "" CustomInitializer "" CustomTerminator "" Toolchain "Automatically locate an installed toolchain" BuildConfiguration "Faster Builds" + CustomToolchainOptions [] IncludeHyperlinkInReport off LaunchReport off PortableWordSizes off @@ -557,7 +841,7 @@ Model { CodeExecutionProfiling off CodeExecutionProfileVariable "executionProfile" CodeProfilingSaveOptions "SummaryOnly" - CodeProfilingInstrumentation off + CodeProfilingInstrumentation "off" SILDebugging off TargetLang "C" IncludeBusHierarchyInRTWFileBlockHierarchyMap off @@ -571,6 +855,7 @@ Model { GenerateCodeReplacementReport off GenerateMissedCodeReplacementReport off RTWCompilerOptimization "off" + ObjectivePriorities [] RTWCustomCompilerOptimizations "" CheckMdlBeforeBuild "Off" SharedConstantsCachingThreshold 1024 @@ -578,11 +863,11 @@ Model { Type "Handle" Dimension 2 Simulink.CodeAppCC { - $ObjectID 16 - Version "1.15.0" + $ObjectID 18 + Version "20.0.1" Array { Type "Cell" - Dimension 9 + Dimension 28 Cell "IgnoreCustomStorageClasses" Cell "InsertBlockDesc" Cell "SFDataObjDesc" @@ -592,54 +877,87 @@ Model { Cell "ParamNamingRule" Cell "InlinedPrmAccess" Cell "CustomSymbolStr" + Cell "IgnoreTestpoints" + Cell "BlockCommentType" + Cell "InsertPolySpaceComments" + Cell "MATLABFcnDesc" + Cell "InternalIdentifier" + Cell "CustomSymbolStrGlobalVar" + Cell "CustomSymbolStrType" + Cell "CustomSymbolStrField" + Cell "CustomSymbolStrFcn" + Cell "CustomSymbolStrModelFcn" + Cell "CustomSymbolStrFcnArg" + Cell "CustomSymbolStrBlkIO" + Cell "CustomSymbolStrTmpVar" + Cell "CustomSymbolStrMacro" + Cell "CustomSymbolStrUtil" + Cell "CustomSymbolStrEmxType" + Cell "CustomSymbolStrEmxFcn" + Cell "CustomUserTokenString" + Cell "ReqsInCode" PropName "DisabledProps" } + Description "" + Components [] + Comment "" ForceParamTrailComments off GenerateComments on CommentStyle "Auto" IgnoreCustomStorageClasses on IgnoreTestpoints off - IncHierarchyInIds off MaxIdLength 31 PreserveName off PreserveNameWithParent off ShowEliminatedStatement on OperatorAnnotations off - IncAutoGenComments off SimulinkDataObjDesc off SFDataObjDesc off MATLABFcnDesc off - IncDataTypeInIds off MangleLength 1 + SharedChecksumLength 8 CustomSymbolStrGlobalVar "$R$N$M" CustomSymbolStrType "$N$R$M_T" CustomSymbolStrField "$N$M" CustomSymbolStrFcn "$R$N$M$F" + CustomSymbolStrModelFcn "$R$N" CustomSymbolStrFcnArg "rt$I$N$M" CustomSymbolStrBlkIO "rtb_$N$M" CustomSymbolStrTmpVar "$N$M" CustomSymbolStrMacro "$R$N$M" CustomSymbolStrUtil "$N$C" + CustomSymbolStrEmxType "emxArray_$M$N" + CustomSymbolStrEmxFcn "emx$M$N" + CustomUserTokenString "" + CustomCommentsFcn "" DefineNamingRule "None" + DefineNamingFcn "" ParamNamingRule "None" + ParamNamingFcn "" SignalNamingRule "None" + SignalNamingFcn "" InsertBlockDesc off InsertPolySpaceComments off SimulinkBlockComments on + BlockCommentType "BlockPathComment" + StateflowObjectComments on MATLABSourceComments off EnableCustomComments off + InternalIdentifierFile "" InternalIdentifier "Shortened" InlinedPrmAccess "Literals" ReqsInCode off UseSimReservedNames off + ReservedNameArray [] + EnumMemberNameClash "error" } Simulink.GRTTargetCC { $BackupClass "Simulink.TargetCC" - $ObjectID 17 - Version "1.15.0" + $ObjectID 19 + Version "20.0.1" Array { Type "Cell" - Dimension 10 + Dimension 17 Cell "IncludeMdlTerminateFcn" Cell "GenerateAllocFcn" Cell "SuppressErrorStatus" @@ -650,8 +968,17 @@ Model { Cell "SupportNonInlinedSFcns" Cell "SupportComplex" Cell "SupportAbsoluteTime" + Cell "CombineOutputUpdateFcns" + Cell "ExistingSharedCode" + Cell "GenerateTestInterfaces" + Cell "ModelStepFunctionPrototypeControlCompliant" + Cell "RemoveDisableFunc" + Cell "RemoveResetFunc" + Cell "PreserveStateflowLocalDataDimensions" PropName "DisabledProps" } + Description "" + Components [] TargetFcnLib "ansi_tfl_tmw.mat" TargetLibSuffix "" TargetPreCompLibLocation "" @@ -659,11 +986,12 @@ Model { TargetLangStandard "C89/C90 (ANSI)" CodeReplacementLibrary "None" UtilityFuncGeneration "Auto" - ERTMultiwordTypeDef "System defined" - ERTMultiwordLength 256 + MultiwordTypeDef "System defined" MultiwordLength 2048 + DynamicStringBufferSize 256 GenerateFullHeader on InferredTypesCompatibility off + ExistingSharedCode "" GenerateSampleERTMain off GenerateTestInterfaces off ModelReferenceCompliant on @@ -671,11 +999,10 @@ Model { CompOptLevelCompliant on ConcurrentExecutionCompliant on IncludeMdlTerminateFcn on - GeneratePreprocessorConditionals "Disable all" CombineOutputUpdateFcns off CombineSignalStateStructs off + GroupInternalDataByFunction off SuppressErrorStatus off - ERTFirstTimeCompliant off IncludeFileDelimiter "Auto" ERTCustomFileBanners off SupportAbsoluteTime on @@ -683,11 +1010,13 @@ Model { MatFileLogging on MultiInstanceERTCode off CodeInterfacePackaging "Nonreusable function" + PurelyIntegerCode off SupportNonFinite on SupportComplex on - PurelyIntegerCode off SupportContinuousTime on SupportNonInlinedSFcns on + RemoveDisableFunc off + RemoveResetFunc off SupportVariableSizeSignals off ParenthesesLevel "Nominal" CastingMode "Nominal" @@ -695,9 +1024,21 @@ Model { ModelStepFunctionPrototypeControlCompliant off CPPClassGenCompliant on AutosarCompliant off + MDXCompliant off GRTInterface on GenerateAllocFcn off + UseToolchainInfoCompliant off GenerateSharedConstants on + CoderGroups [] + AccessMethods [] + LookupTableObjectStructAxisOrder "1,2,3,4,..." + LUTObjectStructOrderExplicitValues "Size,Breakpoints,Table" + LUTObjectStructOrderEvenSpacing "Size,Breakpoints,Table" + ArrayLayout "Column-major" + UnsupportedSFcnMsg "error" + ERTHeaderFileRootName "$R$E" + ERTSourceFileRootName "$R$E" + ERTDataFileRootName "$R_data" UseMalloc off ExtMode off ExtModeStaticAlloc off @@ -705,6 +1046,7 @@ Model { ExtModeStaticAllocSize 1000000 ExtModeTransport 0 ExtModeMexFile "ext_comm" + ExtModeMexArgs "" ExtModeIntrfLevel "Level1" RTWCAPISignals off RTWCAPIParams off @@ -716,28 +1058,74 @@ Model { PropName "Components" } } + SlCovCC.ConfigComp { + $ObjectID 20 + Version "20.0.1" + DisabledProps [] + Description "Simulink Coverage Configuration Component" + Components [] + Name "Simulink Coverage" + CovEnable off + CovScope "EntireSystem" + CovIncludeTopModel on + RecordCoverage off + CovPath "/" + CovSaveName "covdata" + CovCompData "" + CovMetricSettings "dwe" + CovFilter "" + CovHTMLOptions "" + CovNameIncrementing off + CovHtmlReporting off + CovForceBlockReductionOff on + CovEnableCumulative on + CovSaveCumulativeToWorkspaceVar off + CovSaveSingleToWorkspaceVar off + CovCumulativeVarName "covCumulativeData" + CovCumulativeReport off + CovSaveOutputData on + CovOutputDir "slcov_output/$ModelName$" + CovDataFileName "$ModelName$_cvdata" + CovShowResultsExplorer on + CovReportOnPause on + CovModelRefEnable "off" + CovModelRefExcluded "" + CovExternalEMLEnable on + CovSFcnEnable on + CovBoundaryAbsTol 1e-05 + CovBoundaryRelTol 0.01 + CovUseTimeInterval off + CovStartTime 0 + CovStopTime 0 + CovMcdcMode "Masking" + } PropName "Components" } Name "Configuration" CurrentDlgPage "Solver" - ConfigPrmDlgPosition [ 290, 49, 1370, 843 ] + ConfigPrmDlgPosition [ 290, 49, 1370, 843 ] + ExtraOptions "" } Simulink.ConfigSet { - $ObjectID 18 - Version "1.15.0" + $ObjectID 21 + Version "20.0.1" + DisabledProps [] Description "* Simulation Target Description\nDefault S-Function target.\n" Array { Type "Handle" - Dimension 8 + Dimension 9 Simulink.SolverCC { - $ObjectID 19 - Version "1.15.0" + $ObjectID 22 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] StartTime "0.0" StopTime "50" AbsTol "1e-6" + AutoScaleAbsTol off FixedStep ".01" InitialStep "auto" - MaxNumMinSteps "-1" MaxOrder 5 ZcThreshold "auto" ConsecutiveZCsStepRelTol "10*128*eps" @@ -748,8 +1136,7 @@ Model { MinStep "auto" MaxConsecutiveMinStep "1" RelTol "1e-3" - SolverMode "SingleTasking" - EnableConcurrentExecution off + EnableMultiTasking off ConcurrentTasks off Solver "ode5" SolverName "ode5" @@ -758,15 +1145,24 @@ Model { ZeroCrossControl "UseLocalSettings" ZeroCrossAlgorithm "Nonadaptive" AlgebraicLoopSolver "TrustRegion" + SolverInfoToggleStatus off + IsAutoAppliedInSIP off SolverResetMethod "Fast" PositivePriorityOrder off AutoInsertRateTranBlk off SampleTimeConstraint "Unconstrained" InsertRTBMode "Whenever possible" + SampleTimeProperty [] + DecoupledContinuousIntegration off + MinimalZcImpactIntegration off + ODENIntegrationMethod "ode3" } Simulink.DataIOCC { - $ObjectID 20 - Version "1.15.0" + $ObjectID 23 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] Decimation "1" ExternalInput "" FinalStateName "xFinal" @@ -776,7 +1172,7 @@ Model { LoadExternalInput off LoadInitialState off SaveFinalState off - SaveCompleteFinalSimState off + SaveOperatingPoint off SaveFormat "StructureWithTime" SignalLoggingSaveFormat "ModelDataLogs" SaveOutput on @@ -785,6 +1181,8 @@ Model { DSMLogging on InspectSignalLogs off VisualizeSimOutput on + StreamToWorkspace off + StreamVariableName "streamout" SaveTime on ReturnWorkspaceOutputs off StateSaveName "xout" @@ -796,24 +1194,36 @@ Model { OutputTimes "[]" ReturnWorkspaceOutputsName "out" Refine "1" + LoggingToFile off + DatasetSignalFormat "timeseries" + LoggingFileName "out.mat" + LoggingIntervals "[-inf, inf]" } Simulink.OptimizationCC { - $ObjectID 21 - Version "1.15.0" + $ObjectID 24 + Version "20.0.1" Array { Type "Cell" - Dimension 4 + Dimension 9 Cell "ZeroExternalMemoryAtStartup" Cell "ZeroInternalMemoryAtStartup" Cell "NoFixptDivByZeroProtection" Cell "OptimizeModelRefInitCode" + Cell "BooleansAsBitfields" + Cell "PassReuseOutputArgsAs" + Cell "PassReuseOutputArgsThreshold" + Cell "UseSpecifiedMinMax" + Cell "EfficientTunableParamExpr" PropName "DisabledProps" } + Description "" + Components [] BlockReduction off BooleanDataType off ConditionallyExecuteInputs on - InlineParams off + DefaultParameterBehavior "Tunable" UseDivisionForNetSlopeComputation "off" + GainParamInheritBuiltInType off UseFloatMulNetSlope off DefaultUnderspecifiedDataType "double" UseSpecifiedMinMax off @@ -824,9 +1234,11 @@ Model { CachingGlobalReferences off GlobalBufferReuse on StrengthReduction off + AdvancedOptControl "" ExpressionFolding on BooleansAsBitfields off BitfieldContainerType "uint_T" + BitwiseOrLogicalOp "Same as modeled" EnableMemcpy on MemcpyThreshold 64 PassReuseOutputArgsAs "Structure reference" @@ -843,20 +1255,40 @@ Model { NoFixptDivByZeroProtection off EfficientFloat2IntCast off EfficientMapNaN2IntZero on - OptimizeModelRefInitCode off LifeSpan "inf" MaxStackSize "Inherit from target" BufferReusableBoundary on SimCompilerOptimization "off" AccelVerboseBuild off + OptimizeBlockOrder "off" + OptimizeDataStoreBuffers on + BusAssignmentInplaceUpdate on + DifferentSizesBufferReuse off + UseRowMajorAlgorithm off + OptimizationLevel "level2" + OptimizationPriority "Balanced" + OptimizationCustomize on + LabelGuidedReuse off + MultiThreadedLoops off + DenormalBehavior "GradualUnderflow" + EfficientTunableParamExpr off } Simulink.DebuggingCC { - $ObjectID 22 - Version "1.15.0" + $ObjectID 25 + Version "20.0.1" + Array { + Type "Cell" + Dimension 1 + Cell "UseOnlyExistingSharedCode" + PropName "DisabledProps" + } + Description "" + Components [] RTPrefix "error" ConsistencyChecking "none" ArrayBoundsChecking "none" SignalInfNanChecking "none" + StringTruncationChecking "error" SignalRangeChecking "none" ReadBeforeWriteMsg "UseLocalSettings" WriteAfterWriteMsg "UseLocalSettings" @@ -879,12 +1311,12 @@ Model { IgnoredZcDiagnostic "warning" SolverPrmCheckMsg "none" InheritedTsInSrcMsg "warning" - DiscreteInheritContinuousMsg "warning" MultiTaskDSMMsg "warning" MultiTaskCondExecSysMsg "none" MultiTaskRateTransMsg "error" SingleTaskRateTransMsg "none" TasksWithSamePriorityMsg "warning" + ExportedTasksRateTransMsg "none" SigSpecEnsureSampleTimeMsg "none" CheckMatrixSingularityMsg "none" IntegerOverflowMsg "none" @@ -900,18 +1332,20 @@ Model { UnderSpecifiedDataTypeMsg "none" UnnecessaryDatatypeConvMsg "none" VectorMatrixConversionMsg "none" - InvalidFcnCallConnMsg "error" - FcnCallInpInsideContextMsg "UseLocalSettings" + FcnCallInpInsideContextMsg "warning" SignalLabelMismatchMsg "none" UnconnectedInputMsg "warning" UnconnectedOutputMsg "warning" UnconnectedLineMsg "warning" + UseOnlyExistingSharedCode "error" SFcnCompatibilityMsg "none" FrameProcessingCompatibilityMsg "error" UniqueDataStoreMsg "none" BusObjectLabelMismatch "warning" RootOutportRequireBusObject "warning" AssertControl "UseLocalSettings" + AllowSymbolicDim on + RowMajorDimensionSupport off ModelReferenceIOMsg "none" ModelReferenceMultiInstanceNormalModeStructChecksumCheck "error" ModelReferenceVersionMismatchMessage "none" @@ -921,27 +1355,51 @@ Model { ModelReferenceSymbolNameMessage "warning" ModelReferenceExtraNoncontSigs "error" StateNameClashWarn "warning" - SimStateInterfaceChecksumMismatchMsg "warning" - SimStateOlderReleaseMsg "error" + OperatingPointInterfaceChecksumMismatchMsg "warning" + NonCurrentReleaseOperatingPointMsg "error" + ChecksumConsistencyForSSReuse "none" + PregeneratedLibrarySubsystemCodeDiagnostic "warning" + MatchCodeGenerationContextForUpdateDiagram "none" InitInArrayFormatMsg "warning" StrictBusMsg "ErrorLevel1" BusNameAdapt "WarnAndRepair" NonBusSignalsTreatedAsBus "none" + SymbolicDimMinMaxWarning "warning" + LossOfSymbolicDimsSimulationWarning "warning" + LossOfSymbolicDimsCodeGenerationWarning "error" + SymbolicDimsDataTypeCodeGenerationDiagnostic "error" BlockIODiagnostic "none" SFUnusedDataAndEventsDiag "warning" SFUnexpectedBacktrackingDiag "warning" SFInvalidInputDataAccessInChartInitDiag "warning" SFNoUnconditionalDefaultTransitionDiag "warning" SFTransitionOutsideNaturalParentDiag "warning" - SFUnconditionalTransitionShadowingDiag "warning" + SFUnreachableExecutionPathDiag "warning" SFUndirectedBroadcastEventsDiag "warning" SFTransitionActionBeforeConditionDiag "warning" SFOutputUsedAsStateInMooreChartDiag "error" + SFTemporalDelaySmallerThanSampleTimeDiag "warning" + SFSelfTransitionDiag "warning" + SFExecutionAtInitializationDiag "none" + SFMachineParentedDataDiag "warning" IntegerSaturationMsg "none" + AllowedUnitSystems "all" + UnitsInconsistencyMsg "warning" + AllowAutomaticUnitConversions on + RCSCRenamedMsg "warning" + RCSCObservableMsg "warning" + ForceCombineOutputUpdateInSim off + UnitDatabase "" + UnderSpecifiedDimensionMsg "none" + DebugExecutionForFMUViaOutOfProcess off + ArithmeticOperatorsInVariantConditions "warning" } Simulink.HardwareCC { - $ObjectID 23 - Version "1.15.0" + $ObjectID 26 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] ProdBitPerChar 8 ProdBitPerShort 16 ProdBitPerInt 32 @@ -950,6 +1408,8 @@ Model { ProdBitPerFloat 32 ProdBitPerDouble 64 ProdBitPerPointer 32 + ProdBitPerSizeT 32 + ProdBitPerPtrDiffT 32 ProdLargestAtomicInteger "Char" ProdLargestAtomicFloat "None" ProdIntDivRoundTo "Undefined" @@ -966,6 +1426,8 @@ Model { TargetBitPerFloat 32 TargetBitPerDouble 64 TargetBitPerPointer 32 + TargetBitPerSizeT 32 + TargetBitPerPtrDiffT 32 TargetLargestAtomicInteger "Char" TargetLargestAtomicFloat "None" TargetShiftRightIntArith on @@ -978,45 +1440,94 @@ Model { TargetHWDeviceType "Specified" TargetUnknown off ProdEqTarget on + UseEmbeddedCoderFeatures on + UseSimulinkCoderFeatures on + HardwareBoardFeatureSet "EmbeddedCoderHSP" } Simulink.ModelReferenceCC { - $ObjectID 24 - Version "1.15.0" + $ObjectID 27 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] UpdateModelReferenceTargets "IfOutOfDateOrStructuralChange" + EnableRefExpFcnMdlSchedulingChecks on CheckModelReferenceTargetMessage "error" EnableParallelModelReferenceBuilds off ParallelModelReferenceErrorOnInvalidPool on ParallelModelReferenceMATLABWorkerInit "None" ModelReferenceNumInstancesAllowed "Multi" PropagateVarSize "Infer from blocks in model" + ModelDependencies "" ModelReferencePassRootInputsByReference on ModelReferenceMinAlgLoopOccurrences off PropagateSignalLabelsOutOfModel off SupportModelReferenceSimTargetCustomCode off } Simulink.SFSimCC { - $ObjectID 25 - Version "1.15.0" - SFSimOverflowDetection on + $ObjectID 28 + Version "20.0.1" + DisabledProps [] + Description "" + Components [] + SimCustomSourceCode "" + SimCustomHeaderCode "" + SimCustomInitializer "" + SimCustomTerminator "" + SimReservedNameArray [] + SimUserSources "" + SimUserIncludeDirs "" + SimUserLibraries "" + SimUserDefines "" + SimCustomCompilerFlags "" + SimCustomLinkerFlags "" SFSimEcho off SimCtrlC on SimIntegrity on SimUseLocalCustomCode off SimParseCustomCode on + SimAnalyzeCustomCode off SimBuildMode "sf_incremental_build" SimGenImportedTypeDefs off + ModelFunctionsGlobalVisibility "on" + CompileTimeRecursionLimit 50 + EnableRuntimeRecursion on + MATLABDynamicMemAlloc on + MATLABDynamicMemAllocThreshold 65536 + CustomCodeFunctionArrayLayout [] + DefaultCustomCodeFunctionArrayLayout "NotSpecified" + CustomCodeUndefinedFunction "UseInterfaceOnly" } Simulink.RTWCC { $BackupClass "Simulink.RTWCC" - $ObjectID 26 - Version "1.15.0" + $ObjectID 29 + Version "20.0.1" Array { Type "Cell" - Dimension 1 + Dimension 16 Cell "IncludeHyperlinkInReport" + Cell "GenerateTraceInfo" + Cell "GenerateTraceReport" + Cell "GenerateTraceReportSl" + Cell "GenerateTraceReportSf" + Cell "GenerateTraceReportEml" + Cell "PortableWordSizes" + Cell "GenerateWebview" + Cell "GenerateCodeMetricsReport" + Cell "GenerateCodeReplacementReport" + Cell "GenerateMissedCodeReplacementReport" + Cell "GenerateErtSFunction" + Cell "CreateSILPILBlock" + Cell "CodeExecutionProfiling" + Cell "CodeProfilingSaveOptions" + Cell "CodeProfilingInstrumentation" PropName "DisabledProps" } + Description "" SystemTargetFile "grt.tlc" + HardwareBoard "None" + ShowCustomHardwareApp off + ShowEmbeddedHardwareApp off TLCOptions "" GenCodeOnly off MakeCommand "make_rtw" @@ -1025,11 +1536,10 @@ Model { PackageName "" TemplateMakefile "grt_default_tmf" PostCodeGenCommand "" - Description "" GenerateReport off - SaveLog off RTWVerbose on RetainRTWFile off + RTWBuildHooks [] ProfileTLC off TLCDebug off TLCCoverage off @@ -1041,10 +1551,15 @@ Model { CustomInclude "" CustomSource "" CustomLibrary "" + CustomDefine "" + CustomBLASCallback "" + CustomLAPACKCallback "" + CustomFFTCallback "" CustomInitializer "" CustomTerminator "" Toolchain "Automatically locate an installed toolchain" BuildConfiguration "Faster Builds" + CustomToolchainOptions [] IncludeHyperlinkInReport off LaunchReport off PortableWordSizes off @@ -1052,7 +1567,7 @@ Model { CodeExecutionProfiling off CodeExecutionProfileVariable "executionProfile" CodeProfilingSaveOptions "SummaryOnly" - CodeProfilingInstrumentation off + CodeProfilingInstrumentation "off" SILDebugging off TargetLang "C" IncludeBusHierarchyInRTWFileBlockHierarchyMap off @@ -1066,6 +1581,7 @@ Model { GenerateCodeReplacementReport off GenerateMissedCodeReplacementReport off RTWCompilerOptimization "off" + ObjectivePriorities [] RTWCustomCompilerOptimizations "" CheckMdlBeforeBuild "Off" SharedConstantsCachingThreshold 1024 @@ -1073,11 +1589,11 @@ Model { Type "Handle" Dimension 2 Simulink.CodeAppCC { - $ObjectID 27 - Version "1.15.0" + $ObjectID 30 + Version "20.0.1" Array { Type "Cell" - Dimension 9 + Dimension 28 Cell "IgnoreCustomStorageClasses" Cell "InsertBlockDesc" Cell "SFDataObjDesc" @@ -1087,54 +1603,87 @@ Model { Cell "ParamNamingRule" Cell "InlinedPrmAccess" Cell "CustomSymbolStr" + Cell "IgnoreTestpoints" + Cell "BlockCommentType" + Cell "InsertPolySpaceComments" + Cell "MATLABFcnDesc" + Cell "InternalIdentifier" + Cell "CustomSymbolStrGlobalVar" + Cell "CustomSymbolStrType" + Cell "CustomSymbolStrField" + Cell "CustomSymbolStrFcn" + Cell "CustomSymbolStrModelFcn" + Cell "CustomSymbolStrFcnArg" + Cell "CustomSymbolStrBlkIO" + Cell "CustomSymbolStrTmpVar" + Cell "CustomSymbolStrMacro" + Cell "CustomSymbolStrUtil" + Cell "CustomSymbolStrEmxType" + Cell "CustomSymbolStrEmxFcn" + Cell "CustomUserTokenString" + Cell "ReqsInCode" PropName "DisabledProps" } + Description "" + Components [] + Comment "" ForceParamTrailComments off GenerateComments on CommentStyle "Auto" IgnoreCustomStorageClasses on IgnoreTestpoints off - IncHierarchyInIds off MaxIdLength 31 PreserveName off PreserveNameWithParent off ShowEliminatedStatement on OperatorAnnotations off - IncAutoGenComments off SimulinkDataObjDesc off SFDataObjDesc off MATLABFcnDesc off - IncDataTypeInIds off MangleLength 1 + SharedChecksumLength 8 CustomSymbolStrGlobalVar "$R$N$M" CustomSymbolStrType "$N$R$M_T" CustomSymbolStrField "$N$M" CustomSymbolStrFcn "$R$N$M$F" + CustomSymbolStrModelFcn "$R$N" CustomSymbolStrFcnArg "rt$I$N$M" CustomSymbolStrBlkIO "rtb_$N$M" CustomSymbolStrTmpVar "$N$M" CustomSymbolStrMacro "$R$N$M" CustomSymbolStrUtil "$N$C" + CustomSymbolStrEmxType "emxArray_$M$N" + CustomSymbolStrEmxFcn "emx$M$N" + CustomUserTokenString "" + CustomCommentsFcn "" DefineNamingRule "None" + DefineNamingFcn "" ParamNamingRule "None" + ParamNamingFcn "" SignalNamingRule "None" + SignalNamingFcn "" InsertBlockDesc off InsertPolySpaceComments off SimulinkBlockComments on + BlockCommentType "BlockPathComment" + StateflowObjectComments on MATLABSourceComments off EnableCustomComments off + InternalIdentifierFile "" InternalIdentifier "Shortened" InlinedPrmAccess "Literals" ReqsInCode off UseSimReservedNames off + ReservedNameArray [] + EnumMemberNameClash "error" } Simulink.GRTTargetCC { $BackupClass "Simulink.TargetCC" - $ObjectID 28 - Version "1.15.0" + $ObjectID 31 + Version "20.0.1" Array { Type "Cell" - Dimension 10 + Dimension 16 Cell "IncludeMdlTerminateFcn" Cell "GenerateAllocFcn" Cell "SuppressErrorStatus" @@ -1145,8 +1694,16 @@ Model { Cell "SupportNonInlinedSFcns" Cell "SupportComplex" Cell "SupportAbsoluteTime" + Cell "PreserveStateflowLocalDataDimensions" + Cell "ExistingSharedCode" + Cell "GenerateTestInterfaces" + Cell "ModelStepFunctionPrototypeControlCompliant" + Cell "RemoveDisableFunc" + Cell "RemoveResetFunc" PropName "DisabledProps" } + Description "" + Components [] TargetFcnLib "ansi_tfl_tmw.mat" TargetLibSuffix "" TargetPreCompLibLocation "" @@ -1154,11 +1711,12 @@ Model { TargetLangStandard "C89/C90 (ANSI)" CodeReplacementLibrary "None" UtilityFuncGeneration "Auto" - ERTMultiwordTypeDef "System defined" - ERTMultiwordLength 256 + MultiwordTypeDef "System defined" MultiwordLength 2048 + DynamicStringBufferSize 256 GenerateFullHeader on InferredTypesCompatibility off + ExistingSharedCode "" GenerateSampleERTMain off GenerateTestInterfaces off ModelReferenceCompliant on @@ -1166,11 +1724,10 @@ Model { CompOptLevelCompliant on ConcurrentExecutionCompliant on IncludeMdlTerminateFcn on - GeneratePreprocessorConditionals "Disable all" CombineOutputUpdateFcns off CombineSignalStateStructs off + GroupInternalDataByFunction off SuppressErrorStatus off - ERTFirstTimeCompliant off IncludeFileDelimiter "Auto" ERTCustomFileBanners off SupportAbsoluteTime on @@ -1178,11 +1735,13 @@ Model { MatFileLogging on MultiInstanceERTCode off CodeInterfacePackaging "Nonreusable function" + PurelyIntegerCode off SupportNonFinite on SupportComplex on - PurelyIntegerCode off SupportContinuousTime on SupportNonInlinedSFcns on + RemoveDisableFunc off + RemoveResetFunc off SupportVariableSizeSignals off ParenthesesLevel "Nominal" CastingMode "Nominal" @@ -1190,9 +1749,21 @@ Model { ModelStepFunctionPrototypeControlCompliant off CPPClassGenCompliant on AutosarCompliant off + MDXCompliant off GRTInterface on GenerateAllocFcn off + UseToolchainInfoCompliant on GenerateSharedConstants on + CoderGroups [] + AccessMethods [] + LookupTableObjectStructAxisOrder "1,2,3,4,..." + LUTObjectStructOrderExplicitValues "Size,Breakpoints,Table" + LUTObjectStructOrderEvenSpacing "Size,Breakpoints,Table" + ArrayLayout "Column-major" + UnsupportedSFcnMsg "error" + ERTHeaderFileRootName "$R$E" + ERTSourceFileRootName "$R$E" + ERTDataFileRootName "$R_data" UseMalloc off ExtMode off ExtModeStaticAlloc off @@ -1200,6 +1771,7 @@ Model { ExtModeStaticAllocSize 1000000 ExtModeTransport 0 ExtModeMexFile "ext_comm" + ExtModeMexArgs "" ExtModeIntrfLevel "Level1" RTWCAPISignals off RTWCAPIParams off @@ -1211,27 +1783,68 @@ Model { PropName "Components" } } + SlCovCC.ConfigComp { + $ObjectID 32 + Version "20.0.1" + DisabledProps [] + Description "Simulink Coverage Configuration Component" + Components [] + Name "Simulink Coverage" + CovEnable off + CovScope "EntireSystem" + CovIncludeTopModel on + RecordCoverage off + CovPath "/" + CovSaveName "covdata" + CovCompData "" + CovMetricSettings "dcmtr" + CovFilter "" + CovHTMLOptions "" + CovNameIncrementing off + CovHtmlReporting on + CovForceBlockReductionOff on + CovEnableCumulative on + CovSaveCumulativeToWorkspaceVar on + CovSaveSingleToWorkspaceVar on + CovCumulativeVarName "covCumulativeData" + CovCumulativeReport off + CovSaveOutputData on + CovOutputDir "slcov_output/$ModelName$" + CovDataFileName "$ModelName$_cvdata" + CovShowResultsExplorer on + CovReportOnPause on + CovModelRefEnable "off" + CovModelRefExcluded "" + CovExternalEMLEnable off + CovSFcnEnable off + CovBoundaryAbsTol 1e-05 + CovBoundaryRelTol 0.01 + CovUseTimeInterval off + CovStartTime 0 + CovStopTime 0 + CovMcdcMode "Masking" + } PropName "Components" } Name "Configuration1" CurrentDlgPage "Solver" - ConfigPrmDlgPosition [ 290, 49, 1370, 843 ] + ConfigPrmDlgPosition [ 290, 49, 1370, 843 ] + ExtraOptions "" } PropName "ConfigurationSets" } Simulink.ConfigSet { $PropName "ActiveConfigurationSet" - $ObjectID 18 + $ObjectID 21 } Object { $PropName "DataTransfer" - $ObjectID 29 + $ObjectID 33 $ClassName "Simulink.GlobalDataTransfer" DefaultTransitionBetweenSyncTasks "Ensure deterministic transfer (maximum delay)" DefaultTransitionBetweenAsyncTasks "Ensure data integrity only" DefaultTransitionBetweenContTasks "Ensure deterministic transfer (minimum delay)" DefaultExtrapolationMethodBetweenContTasks "None" - AutoInsertRateTranBlk [0] } ExplicitPartitioning off WSDataSource "MATLAB Code" @@ -1240,12 +1853,13 @@ Model { ForegroundColor "black" BackgroundColor "white" DropShadow off - NamePlacement "normal" + NameLocation "bottom" FontName "Helvetica" FontSize 10 FontWeight "normal" FontAngle "normal" ShowName on + HideAutomaticName on BlockRotation 0 BlockMirror off } @@ -1259,7 +1873,12 @@ Model { FontSize 10 FontWeight "normal" FontAngle "normal" + MarkupType "model" UseDisplayTextAsClickCallback off + AnnotationType "note_annotation" + FixedHeight off + FixedWidth off + Interpreter "off" } LineDefaults { FontName "Helvetica" @@ -1270,8 +1889,8 @@ Model { MaskDefaults { SelfModifiable "off" IconFrame "on" - IconOpaque "on" - RunInitForIconRedraw "off" + IconOpaque "opaque" + RunInitForIconRedraw "analyze" IconRotate "none" PortRotate "default" IconUnits "autoscale" @@ -1290,7 +1909,7 @@ Model { Block { BlockType Demux Outputs "4" - DisplayOption "none" + DisplayOption "bar" BusSelectionMode off } Block { @@ -1304,24 +1923,26 @@ Model { Multiplication "Element-wise(K.*u)" ParamMin "[]" ParamMax "[]" - ParamDataTypeStr "Inherit: Same as input" + ParamDataTypeStr "Inherit: Inherit via internal rule" OutMin "[]" OutMax "[]" - OutDataTypeStr "Inherit: Same as input" + OutDataTypeStr "Inherit: Inherit via internal rule" LockScale off RndMeth "Floor" - SaturateOnIntegerOverflow on + SaturateOnIntegerOverflow off SampleTime "-1" } Block { BlockType Inport Port "1" + IconDisplay "Port number" OutputFunctionCall off OutMin "[]" OutMax "[]" OutDataTypeStr "Inherit: auto" LockScale off BusOutputAsStruct off + Unit "inherit" PortDimensions "-1" VarSizeSig "Inherit" SampleTime "-1" @@ -1400,19 +2021,26 @@ Model { Block { BlockType Outport Port "1" + IconDisplay "Port number" OutMin "[]" OutMax "[]" OutDataTypeStr "Inherit: auto" LockScale off BusOutputAsStruct off + Unit "inherit" PortDimensions "-1" VarSizeSig "Inherit" SampleTime "-1" SignalType "auto" SamplingMode "auto" + EnsureOutportIsVirtual off SourceOfInitialOutputValue "Dialog" OutputWhenDisabled "held" InitialOutput "[]" + MustResolveToSignalObject off + OutputWhenUnConnected off + OutputWhenUnconnectedValue "0" + VectorParamsAs1DForOutWhenUnconnected on } Block { BlockType Product @@ -1420,13 +2048,13 @@ Model { Multiplication "Element-wise(.*)" CollapseMode "All dimensions" CollapseDim "1" - InputSameDT on + InputSameDT off OutMin "[]" OutMax "[]" - OutDataTypeStr "Inherit: Same as first input" + OutDataTypeStr "Inherit: Inherit via internal rule" LockScale off - RndMeth "Zero" - SaturateOnIntegerOverflow on + RndMeth "Floor" + SaturateOnIntegerOverflow off SampleTime "-1" } Block { @@ -1434,28 +2062,11 @@ Model { FunctionName "system" SFunctionModules "''" PortCounts "[]" - SFunctionDeploymentMode off - EnableBusSupport off + MultiThreadCoSim "auto" } Block { BlockType Scope - ModelBased off - TickLabels "OneTimeTick" - ZoomMode "on" - Grid "on" - ShowLegends off - TimeRange "auto" - YMin "-5" - YMax "5" - SaveToWorkspace off - SaveName "ScopeData" - DataFormat "Array" - LimitDataPoints on - MaxDataPoints "5000" - Decimation "1" - SampleInput off - SampleTime "-1" - ScrollMode off + DefaultConfigurationName "Simulink.scopes.TimeScopeBlockCfg" } Block { BlockType Signum @@ -1472,20 +2083,21 @@ Model { PermitHierarchicalResolution "All" TreatAsAtomicUnit off MinAlgLoopOccurrences off - PropExecContextOutsideSubsystem off - CheckFcnCallInpInsideContextMsg off + ScheduleAs "Sample time" SystemSampleTime "-1" RTWSystemCode "Auto" RTWFcnNameOpts "Auto" RTWFileNameOpts "Auto" FunctionInterfaceSpec "void_void" FunctionWithSeparateData off + MatchGraphicalInterface off RTWMemSecFuncInitTerm "Inherit from model" RTWMemSecFuncExecute "Inherit from model" RTWMemSecDataConstants "Inherit from model" RTWMemSecDataInternal "Inherit from model" RTWMemSecDataParameters "Inherit from model" SimViewingDevice off + ActiveForDiff off DataTypeOverride "UseLocalSettings" DataTypeOverrideAppliesTo "AllNumericTypes" MinMaxOverflowLogging "UseLocalSettings" @@ -1493,30 +2105,41 @@ Model { MaskHideContents off SFBlockType "NONE" Variant off + VariantControlMode "Expression" GeneratePreprocessorConditionals off + AllowZeroVariantControls off + PropagateVariantConditions off + TreatAsGroupedWhenPropagatingVariantConditions on ContentPreviewEnabled off IsWebBlock off + IsInjectorSS off + Latency "0" + AutoFrameSizeCalculation off + IsWebBlockPanel off } Block { BlockType Sum - IconShape "rectangular" + IconShape "round" Inputs "++" CollapseMode "All dimensions" CollapseDim "1" - InputSameDT on + InputSameDT off AccumDataTypeStr "Inherit: Inherit via internal rule" OutMin "[]" OutMax "[]" - OutDataTypeStr "Inherit: Same as first input" + OutDataTypeStr "Inherit: Inherit via internal rule" LockScale off RndMeth "Floor" - SaturateOnIntegerOverflow on + SaturateOnIntegerOverflow off SampleTime "-1" } Block { BlockType TriggerPort TriggerType "rising" IsSimulinkFunction off + FunctionVisibility "global" + Variant off + GeneratePreprocessorConditionals off StatesWhenEnabling "inherit" PropagateVarSize "During execution" ShowOutputPort off @@ -1524,6 +2147,8 @@ Model { SampleTimeType "triggered" SampleTime "1" ZeroCross on + DisallowConstTsAndPrmTs off + InitialTriggerSignalState "compatibility (no trigger on first evaluation)" PortDimensions "-1" TriggerSignalSampleTime "-1" OutMin "[]" @@ -1536,6 +2161,9 @@ Model { Name "Autotrans_online" Location [120, 105, 1491, 948] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -1548,14 +2176,14 @@ Model { ShowPageBoundaries off ZoomFactor "160" ReportName "simulink-default.rpt" - SIDHighWatermark "158" + SIDHighWatermark "159" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "Throttle" SID "152" Position [80, 167, 105, 183] ZOrder 59 - IconDisplay "Port number" } Block { BlockType Inport @@ -1564,7 +2192,6 @@ Model { Position [80, 432, 105, 448] ZOrder 60 Port "2" - IconDisplay "Port number" } Block { BlockType SubSystem @@ -1578,13 +2205,14 @@ Model { Port { PortNumber 1 Name "EngineRPM" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } System { Name "Engine" Location [339, 44, 919, 758] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -1596,13 +2224,13 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "100" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "Ti" SID "2" Position [35, 19, 60, 31] ZOrder -1 - IconDisplay "Port number" } Block { BlockType Inport @@ -1611,7 +2239,6 @@ Model { Position [35, 48, 60, 62] ZOrder -2 Port "2" - IconDisplay "Port number" } Block { BlockType Lookup2D @@ -1646,7 +2273,11 @@ Model { Position [195, 42, 225, 73] ZOrder -5 ShowName off + IconShape "rectangular" Inputs "-+" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Gain @@ -1655,6 +2286,9 @@ Model { Position [260, 39, 300, 81] ZOrder -6 Gain "1/Iei" + ParamDataTypeStr "Inherit: Same as input" + OutDataTypeStr "Inherit: Same as input" + SaturateOnIntegerOverflow on } Block { BlockType Outport @@ -1662,7 +2296,6 @@ Model { SID "8" Position [395, 54, 420, 66] ZOrder -7 - IconDisplay "Port number" InitialOutput "0" } Line { @@ -1721,10 +2354,8 @@ Model { Annotation { SID "116" Name "Engine" - Position [225, 152, 273, 170] + Position [201, 143, 249, 161] InternalMargins [0, 0, 0, 0] - FixedHeight off - FixedWidth off ZOrder -1 FontName "Arial" FontSize 14 @@ -1742,8 +2373,11 @@ Model { RequestExecContextInheritance off System { Name "Online STL Monitor" - Location [120, 105, 1491, 948] + Location [3000, 397, 4371, 1240] Open on + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -1755,13 +2389,13 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "143" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "gear" SID "149" Position [5, 152, 30, 168] ZOrder 57 - IconDisplay "Port number" } Block { BlockType Inport @@ -1770,7 +2404,6 @@ Model { Position [5, 182, 30, 198] ZOrder 58 Port "2" - IconDisplay "Port number" } Block { BlockType Inport @@ -1779,7 +2412,6 @@ Model { Position [5, 212, 30, 228] ZOrder 59 Port "3" - IconDisplay "Port number" } Block { BlockType Demux @@ -1790,20 +2422,13 @@ Model { ZOrder 49 ShowName off Outputs "2" - DisplayOption "bar" Port { PortNumber 1 Name "rob_up" - RTWStorageClass "Auto" - DataLogging on - DataLoggingNameMode "SignalName" } Port { PortNumber 2 Name "rob_low" - RTWStorageClass "Auto" - DataLogging on - DataLoggingNameMode "SignalName" } } Block { @@ -1819,27 +2444,30 @@ Model { } Block { BlockType S-Function - Name "STL Monitor\n" - SID "131" + Name "STL Monitor" + SID "159" Ports [1, 1] Position [195, 171, 375, 209] - ZOrder 41 + ZOrder 65 FunctionName "onlineMonitorWrapper" - Parameters "SignalNames, STLString, MaxRob" + Parameters "SignalNames, STLString, MaxRob,RefreshRate" + SFunctionDeploymentMode off + EnableBusSupport off + SFcnIsStateOwnerBlock off Object { $PropName "MaskObject" - $ObjectID 30 + $ObjectID 34 $ClassName "Simulink.Mask" Type "STL Monitor" Description "Monitor an STL Formula on input signal. Takes two parameters: a string with \ncomma separated i" - "dentifiers for the input signals, (ex: 'x1,x2,y'), and a \nstring for the formula (ex: 'alw_[0, 50] (x1[t]>0 => y" - "[t] >0)'). Outputs a \ntwo dimensional signal bounding the satisfaction of the formula. " + "dentifiers for the input signals, (ex: 'x1,x2,y'), and a \nstring for the formula (ex: 'alw_[0, 50] (x1[t]>0 => " + "y[t] >0)'). Outputs a \ntwo dimensional signal bounding the satisfaction of the formula. " Display "fprintf('%s', STLString)\n" Array { Type "Simulink.MaskParameter" - Dimension 3 + Dimension 4 Object { - $ObjectID 31 + $ObjectID 35 Type "edit" Name "SignalNames" Prompt "Signal names" @@ -1847,7 +2475,7 @@ Model { Tunable "off" } Object { - $ObjectID 32 + $ObjectID 36 Type "edit" Name "STLString" Prompt "String For STL formula" @@ -1855,24 +2483,31 @@ Model { Tunable "off" } Object { - $ObjectID 33 + $ObjectID 37 Type "edit" Name "MaxRob" Prompt "Maximum robustness" Value "max_rob" } + Object { + $ObjectID 38 + Type "edit" + Name "RefreshRate" + Prompt "Refresh Rate" + Value "0.1" + } PropName "Parameters" } Array { Type "Simulink.dialog.Control" - Dimension 4 + Dimension 5 Object { - $ObjectID 34 + $ObjectID 39 $ClassName "Simulink.dialog.Group" Prompt "%" Object { $PropName "DialogControls" - $ObjectID 35 + $ObjectID 40 $ClassName "Simulink.dialog.Text" Prompt "%" Name "DescTextVar" @@ -1880,20 +2515,25 @@ Model { Name "DescGroupVar" } Object { - $ObjectID 36 + $ObjectID 41 $ClassName "Simulink.dialog.parameter.Edit" Name "SignalNames" } Object { - $ObjectID 37 + $ObjectID 42 $ClassName "Simulink.dialog.parameter.Edit" Name "STLString" } Object { - $ObjectID 38 + $ObjectID 43 $ClassName "Simulink.dialog.parameter.Edit" Name "MaxRob" } + Object { + $ObjectID 44 + $ClassName "Simulink.dialog.parameter.Edit" + Name "RefreshRate" + } PropName "DialogControls" } } @@ -1929,9 +2569,15 @@ Model { Ports [1, 1] Position [485, 147, 600, 173] ZOrder 56 - LibraryVersion "1.356" + LibraryVersion "1.465" SourceBlock "simulink/Logic and Bit\nOperations/Compare\nTo Constant" SourceType "Compare To Constant" + SourceProductBaseCode "SL" + RTWMemSecFuncInitTerm "Inherit from model" + RTWMemSecFuncExecute "Inherit from model" + RTWMemSecDataConstants "Inherit from model" + RTWMemSecDataInternal "Inherit from model" + RTWMemSecDataParameters "Inherit from model" ContentPreviewEnabled off relop "<=" const "rob_up_lim" @@ -1945,9 +2591,15 @@ Model { Ports [1, 1] Position [485, 202, 600, 228] ZOrder 54 - LibraryVersion "1.356" + LibraryVersion "1.465" SourceBlock "simulink/Logic and Bit\nOperations/Compare\nTo Constant" SourceType "Compare To Constant" + SourceProductBaseCode "SL" + RTWMemSecFuncInitTerm "Inherit from model" + RTWMemSecFuncExecute "Inherit from model" + RTWMemSecDataConstants "Inherit from model" + RTWMemSecDataInternal "Inherit from model" + RTWMemSecDataParameters "Inherit from model" ContentPreviewEnabled off relop ">=" const "rob_low_lim" @@ -1961,9 +2613,15 @@ Model { Ports [1, 1] Position [590, 267, 705, 293] ZOrder 64 - LibraryVersion "1.356" + LibraryVersion "1.465" SourceBlock "simulink/Logic and Bit\nOperations/Compare\nTo Constant" SourceType "Compare To Constant" + SourceProductBaseCode "SL" + RTWMemSecFuncInitTerm "Inherit from model" + RTWMemSecFuncExecute "Inherit from model" + RTWMemSecDataConstants "Inherit from model" + RTWMemSecDataInternal "Inherit from model" + RTWMemSecDataParameters "Inherit from model" ContentPreviewEnabled off relop "<=" const "rob_diff_lim" @@ -1977,23 +2635,18 @@ Model { Ports [2, 1] Position [475, 262, 505, 293] ZOrder 63 + IconShape "rectangular" Inputs "+-" - InputSameDT off - OutDataTypeStr "Inherit: Inherit via internal rule" - SaturateOnIntegerOverflow off Port { PortNumber 1 Name "rob_diff" - RTWStorageClass "Auto" - DataLogging on - DataLoggingNameMode "SignalName" } } Line { - ZOrder 72 + ZOrder 159 SrcBlock "Mux" SrcPort 1 - DstBlock "STL Monitor\n" + DstBlock "STL Monitor" DstPort 1 } Line { @@ -2004,8 +2657,8 @@ Model { DstPort 1 } Line { - ZOrder 78 - SrcBlock "STL Monitor\n" + ZOrder 158 + SrcBlock "STL Monitor" SrcPort 1 DstBlock "Demux" DstPort 1 @@ -2112,6 +2765,9 @@ Model { Name "ShiftLogic" Location [146, 439, 1489, 1073] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -2123,14 +2779,14 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "100" - SIDHighWatermark "33" + SIDHighWatermark "35" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "speed" SID "16::1" Position [20, 101, 40, 119] ZOrder -1 - IconDisplay "Port number" } Block { BlockType Inport @@ -2139,7 +2795,6 @@ Model { Position [20, 136, 40, 154] ZOrder -2 Port "2" - IconDisplay "Port number" } Block { BlockType Inport @@ -2148,40 +2803,37 @@ Model { Position [20, 171, 40, 189] ZOrder -3 Port "3" - IconDisplay "Port number" } Block { BlockType Demux Name " Demux " - SID "16::33" + SID "16::35" Ports [1, 1] Position [270, 230, 320, 270] - ZOrder 6 + ZOrder 8 Outputs "1" Port { PortNumber 1 Name "CALC_TH" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } } Block { BlockType S-Function Name " SFunction " - SID "16::32" - Tag "Stateflow S-Function Autotrans_online 1" + SID "16::34" + Tag "Stateflow S-Function 1" Ports [3, 2] Position [180, 100, 230, 180] - ZOrder 5 + ZOrder 7 FunctionName "sf_sfun" Parameters "TWAIT" PortCounts "[3 2]" - EnableBusSupport on + SFunctionDeploymentMode off + EnableBusSupport off + SFcnIsStateOwnerBlock off Port { PortNumber 2 Name "gear" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } } Block { @@ -2190,7 +2842,6 @@ Model { SID "16::6" Position [460, 101, 480, 119] ZOrder -6 - IconDisplay "Port number" } Block { BlockType Outport @@ -2199,24 +2850,23 @@ Model { Position [460, 136, 480, 154] ZOrder -7 Port "2" - IconDisplay "Port number" } Line { - ZOrder 13 + ZOrder 19 SrcBlock "speed" SrcPort 1 DstBlock " SFunction " DstPort 1 } Line { - ZOrder 14 + ZOrder 20 SrcBlock "up_th" SrcPort 1 DstBlock " SFunction " DstPort 2 } Line { - ZOrder 15 + ZOrder 21 SrcBlock "down_th" SrcPort 1 DstBlock " SFunction " @@ -2224,7 +2874,7 @@ Model { } Line { Name "gear" - ZOrder 16 + ZOrder 22 Labels [0, 0] SrcBlock " SFunction " SrcPort 2 @@ -2233,7 +2883,7 @@ Model { } Line { Name "CALC_TH" - ZOrder 17 + ZOrder 23 Labels [0, 0] SrcBlock " Demux " SrcPort 1 @@ -2241,7 +2891,7 @@ Model { DstPort 1 } Line { - ZOrder 18 + ZOrder 24 SrcBlock " SFunction " SrcPort 1 Points [20, 0] @@ -2266,6 +2916,9 @@ Model { Name "ThresholdCalculation" Location [360, 44, 897, 793] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -2277,13 +2930,13 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "100" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "gear" SID "18" Position [20, 118, 50, 132] ZOrder -1 - IconDisplay "Port number" } Block { BlockType Inport @@ -2292,7 +2945,6 @@ Model { Position [20, 53, 50, 67] ZOrder -2 Port "2" - IconDisplay "Port number" } Block { BlockType TriggerPort @@ -2302,6 +2954,7 @@ Model { Position [160, 15, 180, 35] ZOrder -3 TriggerType "function-call" + VariantControl "(inherit)" ZeroCross off } Block { @@ -2338,7 +2991,6 @@ Model { SID "23" Position [340, 128, 370, 142] ZOrder -6 - IconDisplay "Port number" } Block { BlockType Outport @@ -2347,7 +2999,6 @@ Model { Position [335, 63, 365, 77] ZOrder -7 Port "2" - IconDisplay "Port number" } Line { ZOrder 1 @@ -2401,10 +3052,8 @@ Model { Annotation { SID "117" Name "Threshold Calculation" - Position [212, 196, 360, 214] + Position [138, 187, 286, 205] InternalMargins [0, 0, 0, 0] - FixedHeight off - FixedWidth off ZOrder -1 FontName "Arial" FontSize 14 @@ -2424,19 +3073,18 @@ Model { Port { PortNumber 1 Name "ImprellerTorque" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } Port { PortNumber 2 Name "OutputTorque" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } System { Name "Transmission" Location [223, 44, 1337, 1145] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -2448,13 +3096,13 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "234" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "Ne" SID "26" Position [25, 33, 55, 47] ZOrder -1 - IconDisplay "Port number" } Block { BlockType Inport @@ -2463,7 +3111,6 @@ Model { Position [25, 98, 55, 112] ZOrder -2 Port "2" - IconDisplay "Port number" } Block { BlockType Inport @@ -2472,7 +3119,6 @@ Model { Position [25, 138, 55, 152] ZOrder -3 Port "3" - IconDisplay "Port number" } Block { BlockType SubSystem @@ -2486,7 +3132,7 @@ Model { RequestExecContextInheritance off Object { $PropName "MaskObject" - $ObjectID 39 + $ObjectID 45 $ClassName "Simulink.Mask" Type "torque converter" Description "torque converter " @@ -2498,21 +3144,21 @@ Model { Type "Simulink.MaskParameter" Dimension 3 Object { - $ObjectID 40 + $ObjectID 46 Type "edit" Name "speedratio" Prompt " speed ratio " Value "converter_data(:,1)" } Object { - $ObjectID 41 + $ObjectID 47 Type "edit" Name "Kfactor" Prompt " K factor " Value "converter_data(:,2)" } Object { - $ObjectID 42 + $ObjectID 48 Type "edit" Name "Torkratio" Prompt " torque ratio" @@ -2524,13 +3170,14 @@ Model { Port { PortNumber 2 Name "turbine torque" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } System { Name "TorqueConverter" Location [8, 391, 712, 1182] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -2542,13 +3189,13 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "100" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "Ne" SID "30" Position [30, 98, 55, 112] ZOrder -1 - IconDisplay "Port number" } Block { BlockType Inport @@ -2556,9 +3203,8 @@ Model { SID "31" Position [30, 68, 55, 82] ZOrder -2 - NamePlacement "alternate" + NameLocation "top" Port "2" - IconDisplay "Port number" } Block { BlockType Lookup @@ -2585,7 +3231,9 @@ Model { Position [270, 39, 315, 106] ZOrder -5 Inputs "*/" - RndMeth "Floor" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Product @@ -2595,7 +3243,9 @@ Model { Position [100, 61, 150, 119] ZOrder -6 Inputs "*/" - RndMeth "Floor" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Lookup @@ -2613,7 +3263,9 @@ Model { Ports [2, 1] Position [445, 64, 490, 106] ZOrder -8 - RndMeth "Floor" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Outport @@ -2621,7 +3273,6 @@ Model { SID "38" Position [515, 29, 540, 41] ZOrder -9 - IconDisplay "Port number" InitialOutput "0" } Block { @@ -2631,7 +3282,6 @@ Model { Position [515, 79, 540, 91] ZOrder -10 Port "2" - IconDisplay "Port number" InitialOutput "0" } Line { @@ -2724,10 +3374,8 @@ Model { Annotation { SID "118" Name "Torque Converter" - Position [297, 217, 415, 235] + Position [238, 217, 357, 235] InternalMargins [0, 0, 0, 0] - FixedHeight off - FixedWidth off VerticalAlignment "top" ZOrder -1 FontName "Arial" @@ -2748,6 +3396,9 @@ Model { Name "TransmissionRatio" Location [606, 44, 1117, 812] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -2759,13 +3410,13 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "100" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "Tin" SID "41" Position [25, 28, 55, 42] ZOrder -1 - IconDisplay "Port number" } Block { BlockType Inport @@ -2774,7 +3425,6 @@ Model { Position [25, 73, 55, 87] ZOrder -2 Port "2" - IconDisplay "Port number" } Block { BlockType Inport @@ -2784,7 +3434,6 @@ Model { ZOrder -3 BlockMirror on Port "3" - IconDisplay "Port number" } Block { BlockType Lookup @@ -2804,7 +3453,9 @@ Model { Ports [2, 1] Position [235, 27, 265, 58] ZOrder -5 - RndMeth "Floor" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Product @@ -2814,7 +3465,9 @@ Model { Position [245, 147, 275, 178] ZOrder -6 BlockMirror on - RndMeth "Floor" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Outport @@ -2822,7 +3475,6 @@ Model { SID "47" Position [335, 38, 365, 52] ZOrder -7 - IconDisplay "Port number" InitialOutput "0" } Block { @@ -2833,7 +3485,6 @@ Model { ZOrder -8 BlockMirror on Port "2" - IconDisplay "Port number" InitialOutput "0" } Line { @@ -2892,10 +3543,8 @@ Model { Annotation { SID "119" Name "Transmission Gear Ratio" - Position [205, 213, 371, 231] + Position [122, 204, 288, 222] InternalMargins [0, 0, 0, 0] - FixedHeight off - FixedWidth off ZOrder -1 FontName "Arial" FontSize 14 @@ -2909,7 +3558,6 @@ Model { SID "49" Position [410, 33, 440, 47] ZOrder -6 - IconDisplay "Port number" InitialOutput "0" } Block { @@ -2919,7 +3567,6 @@ Model { Position [410, 68, 440, 82] ZOrder -7 Port "2" - IconDisplay "Port number" InitialOutput "0" } Line { @@ -2978,10 +3625,8 @@ Model { Annotation { SID "120" Name "Transmission" - Position [237, 209, 329, 227] + Position [191, 200, 283, 218] InternalMargins [0, 0, 0, 0] - FixedHeight off - FixedWidth off ZOrder -1 FontName "Arial" FontSize 14 @@ -2996,13 +3641,13 @@ Model { Ports [2, 2] Position [545, 313, 685, 382] ZOrder -9 - NamePlacement "alternate" + NameLocation "top" FontSize 14 ShowPortLabels "none" RequestExecContextInheritance off Object { $PropName "MaskObject" - $ObjectID 43 + $ObjectID 49 $ClassName "Simulink.Mask" Type "vehicle model" Description "vehicle dynamics: torque input from trans., outputs are input speed (transmission output) and vehicle s" @@ -3013,42 +3658,42 @@ Model { Type "Simulink.MaskParameter" Dimension 6 Object { - $ObjectID 44 + $ObjectID 50 Type "edit" Name "Rfd" Prompt " final drive ratio " Value "vehicledata(1)" } Object { - $ObjectID 45 + $ObjectID 51 Type "edit" Name "rload0" Prompt " drag friction at wheels " Value "vehicledata(2)" } Object { - $ObjectID 46 + $ObjectID 52 Type "edit" Name "rload2" Prompt " aerodynamic drag " Value "vehicledata(3)" } Object { - $ObjectID 47 + $ObjectID 53 Type "edit" Name "Rw" Prompt " wheel radius " Value "vehicledata(4)" } Object { - $ObjectID 48 + $ObjectID 54 Type "edit" Name "Iv" Prompt " vehicle inertia " Value "vehicledata(5)" } Object { - $ObjectID 49 + $ObjectID 55 Type "edit" Name "N20" Prompt " initial transmission output speed" @@ -3060,19 +3705,18 @@ Model { Port { PortNumber 1 Name "speed" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } Port { PortNumber 2 Name "TransmissionRPM" - RTWStorageClass "Auto" - DataLoggingNameMode "SignalName" } System { Name "Vehicle" Location [21, 133, 1056, 1052] Open off + PortBlocksUseCompactNotation off + SetExecutionDomain off + ExecutionDomainType "Deduce" ModelBrowserVisibility off ModelBrowserWidth 200 ScreenColor "white" @@ -3084,6 +3728,7 @@ Model { TiledPageScale 1 ShowPageBoundaries off ZoomFactor "100" + SimulinkSubDomain "Simulink" Block { BlockType Inport Name "OutputTorque" @@ -3091,7 +3736,6 @@ Model { Position [40, 70, 60, 90] ZOrder -1 FontSize 12 - IconDisplay "Port number" } Block { BlockType Inport @@ -3101,7 +3745,6 @@ Model { ZOrder -2 FontSize 12 Port "2" - IconDisplay "Port number" } Block { BlockType Gain @@ -3111,6 +3754,9 @@ Model { ZOrder -3 FontSize 12 Gain "Rfd" + ParamDataTypeStr "Inherit: Same as input" + OutDataTypeStr "Inherit: Same as input" + SaturateOnIntegerOverflow on } Block { BlockType Gain @@ -3120,6 +3766,9 @@ Model { ZOrder -4 FontSize 12 Gain "Rfd" + ParamDataTypeStr "Inherit: Same as input" + OutDataTypeStr "Inherit: Same as input" + SaturateOnIntegerOverflow on } Block { BlockType Gain @@ -3127,9 +3776,12 @@ Model { SID "56" Position [365, 187, 440, 243] ZOrder -5 - NamePlacement "alternate" + NameLocation "top" FontSize 12 Gain "2*pi*Rw" + ParamDataTypeStr "Inherit: Same as input" + OutDataTypeStr "Inherit: Same as input" + SaturateOnIntegerOverflow on } Block { BlockType Fcn @@ -3156,7 +3808,9 @@ Model { Position [725, 127, 750, 278] ZOrder -8 FontSize 12 - RndMeth "Floor" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Sum @@ -3167,7 +3821,11 @@ Model { ZOrder -9 ShowName off FontSize 12 + IconShape "rectangular" Inputs "+-" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Sum @@ -3178,6 +3836,10 @@ Model { ZOrder -10 ShowName off FontSize 12 + IconShape "rectangular" + InputSameDT on + OutDataTypeStr "Inherit: Same as first input" + SaturateOnIntegerOverflow on } Block { BlockType Gain @@ -3187,6 +3849,9 @@ Model { ZOrder -11 FontSize 12 Gain "1/Iv" + ParamDataTypeStr "Inherit: Same as input" + OutDataTypeStr "Inherit: Same as input" + SaturateOnIntegerOverflow on } Block { BlockType Integrator @@ -3205,9 +3870,12 @@ Model { SID "64" Position [455, 188, 525, 242] ZOrder -13 - NamePlacement "alternate" + NameLocation "top" FontSize 12 Gain "60/5280" + ParamDataTypeStr "Inherit: Same as input" + OutDataTypeStr "Inherit: Same as input" + SaturateOnIntegerOverflow on } Block { BlockType Outport @@ -3216,7 +3884,6 @@ Model { Position [765, 20, 785, 40] ZOrder -14 FontSize 12 - IconDisplay "Port number" InitialOutput "0" } Block { @@ -3227,7 +3894,6 @@ Model { ZOrder -15 FontSize 12 Port "2" - IconDisplay "Port number" InitialOutput "0" } Line { @@ -3354,10 +4020,8 @@ Model { Annotation { SID "121" Name "Vehicle" - Position [447, 352, 504, 370] + Position [419, 352, 476, 373] InternalMargins [0, 0, 0, 0] - FixedHeight off - FixedWidth off VerticalAlignment "top" ZOrder -1 FontSize 16 @@ -3372,7 +4036,6 @@ Model { Position [755, 453, 785, 467] ZOrder -10 FontSize 14 - IconDisplay "Port number" } Block { BlockType Outport @@ -3382,7 +4045,6 @@ Model { ZOrder -11 FontSize 14 Port "2" - IconDisplay "Port number" } Block { BlockType Outport @@ -3391,7 +4053,6 @@ Model { Position [740, 143, 770, 157] ZOrder -12 Port "3" - IconDisplay "Port number" } Block { BlockType Scope @@ -3401,19 +4062,12 @@ Model { Position [20, 15, 60, 55] ZOrder -13 IOType "viewer" - Floating off - Location [74, 539, 357, 735] - Open off + ScopeSpecificationString "C++SS(StrPVP('Location','[74, 539, 357, 735]'),StrPVP('Open','off'),MxPVP('AxesTitles'" + ",54,'struct(''axes1'',''%'')'),StrPVP('TimeRange','30'),StrPVP('YMin','1000'),StrPVP('YMax','5000')" + ",StrPVP('MaxDataPoints','7500'),StrPVP('LimitDataPoints','on'),StrPVP('DataFormat','Array'),StrPVP('Decimation'," + "'1'),StrPVP('BlockParamSampleInput','off'))" NumInputPorts "1" - List { - ListType AxesTitles - axes1 "%" - } - TimeRange "30" - YMin "1000" - YMax "5000" - MaxDataPoints "7500" - SampleTime "0" + Floating off } Line { Name "ImprellerTorque" @@ -3590,33 +4244,31 @@ Model { } Annotation { SID "123" - Position [708, 121, 710, 133] + Position [707, 115, 709, 130] InternalMargins [0, 0, 0, 0] - FixedHeight off - FixedWidth off ZOrder -2 } } } #Finite State Machines # -# Stateflow 80000005 +# Stateflow 80000032 # # Stateflow { machine { id 1 name "Autotrans_online" - isLibrary 0 - firstTarget 35 debug { runTimeCheck [0 0 0] } - sfVersion 80000005 + sfVersion 80000032 sfDemoChecksum [508233801 3487789180 2503317914 316703550] + firstTarget 35 } chart { id 2 + machine 1 name "ShiftLogic" windowPosition [146 439 1343 634] viewLimits [0 559.776 0 750.533] @@ -3624,19 +4276,18 @@ Stateflow { screen [1 1 1920 1200 1.000788022064618] treeNode [0 4 0 0] viewObj 2 - machine 1 subviewS { zoomFactor 0.833 } ssIdHighWaterMark 38 decomposition SET_CHART - firstEvent 33 - firstData 28 updateMethod DISCRETE sampleTime "0.04" chartFileNumber 1 disableImplicitCasting 1 supportVariableSizing 0 + firstData 28 + firstEvent 33 } state { id 3 @@ -3659,13 +4310,13 @@ Stateflow { arrowSize 12.207 chart 2 treeNode [2 5 0 9] - firstTransition 14 subviewer 2 ssIdNumber 2 type AND_STATE decomposition CLUSTER_STATE executionOrder 1 firstEvent 12 + firstTransition 14 } state { id 5 @@ -3727,7 +4378,6 @@ Stateflow { arrowSize 12.207 chart 2 treeNode [2 11 4 0] - firstTransition 21 subgrouped 1 subviewer 2 subviewS { @@ -3741,6 +4391,7 @@ Stateflow { type AND_STATE decomposition CLUSTER_STATE executionOrder 2 + firstTransition 21 } state { id 10 @@ -3772,19 +4423,19 @@ Stateflow { id 12 ssIdNumber 30 name "DOWN" - linkNode [4 0 13] scope LOCAL_EVENT trigger EITHER_EDGE_EVENT machine 1 + linkNode [4 0 13] } event { id 13 ssIdNumber 31 name "UP" - linkNode [4 12 0] scope LOCAL_EVENT trigger EITHER_EDGE_EVENT machine 1 + linkNode [4 12 0] } transition { id 14 @@ -3800,7 +4451,6 @@ Stateflow { } midPoint [100.7282 50.3156] chart 2 - linkNode [4 0 15] dataLimits [94.493 115.859 47.497 53.032] subviewer 2 slide { @@ -3808,6 +4458,7 @@ Stateflow { } executionOrder 1 ssIdNumber 13 + linkNode [4 0 15] } transition { id 15 @@ -3825,7 +4476,6 @@ Stateflow { } midPoint [290.4005 52.2879] chart 2 - linkNode [4 14 16] dataLimits [269.814 316.606 48.746 54.281] subviewer 2 slide { @@ -3833,6 +4483,7 @@ Stateflow { } executionOrder 1 ssIdNumber 11 + linkNode [4 14 16] } transition { id 16 @@ -3850,7 +4501,6 @@ Stateflow { } midPoint [190.7037 54.1586] chart 2 - linkNode [4 15 17] dataLimits [172.137 215.558 52.205 57.739] subviewer 2 slide { @@ -3858,6 +4508,7 @@ Stateflow { } executionOrder 1 ssIdNumber 12 + linkNode [4 15 17] } transition { id 17 @@ -3875,7 +4526,6 @@ Stateflow { } midPoint [386.8073 55.0584] chart 2 - linkNode [4 16 18] dataLimits [369.101 410.261 52.712 58.246] subviewer 2 slide { @@ -3883,6 +4533,7 @@ Stateflow { } executionOrder 1 ssIdNumber 10 + linkNode [4 16 18] } transition { id 18 @@ -3900,7 +4551,6 @@ Stateflow { } midPoint [197.8159 62.9528] chart 2 - linkNode [4 17 19] dataLimits [172.137 215.558 60.186 65.72] subviewer 2 drawStyle SMART @@ -3909,6 +4559,7 @@ Stateflow { } executionOrder 2 ssIdNumber 16 + linkNode [4 17 19] } transition { id 19 @@ -3926,7 +4577,6 @@ Stateflow { } midPoint [392.9398 66.5217] chart 2 - linkNode [4 18 20] dataLimits [369.101 410.261 64.02 69.554] subviewer 2 slide { @@ -3934,6 +4584,7 @@ Stateflow { } executionOrder 1 ssIdNumber 14 + linkNode [4 18 20] } transition { id 20 @@ -3951,7 +4602,6 @@ Stateflow { } midPoint [295.9072 67.523] chart 2 - linkNode [4 19 0] dataLimits [269.814 316.606 65.748 71.282] subviewer 2 slide { @@ -3959,6 +4609,7 @@ Stateflow { } executionOrder 2 ssIdNumber 15 + linkNode [4 19 0] } transition { id 21 @@ -3974,7 +4625,6 @@ Stateflow { } midPoint [297.1246 129.84] chart 2 - linkNode [9 0 22] dataLimits [294.003 300.003 123.809 145.577] subviewer 2 slide { @@ -3982,6 +4632,7 @@ Stateflow { } executionOrder 1 ssIdNumber 17 + linkNode [9 0 22] } transition { id 22 @@ -3999,14 +4650,15 @@ Stateflow { } midPoint [409.7143 177.1572] chart 2 - linkNode [9 21 23] dataLimits [347.325 441 162.495 220.707] subviewer 2 slide { + mode MIRROR_SLIDE sticky BOTH_STICK } executionOrder 1 ssIdNumber 18 + linkNode [9 21 23] } transition { id 23 @@ -4024,14 +4676,15 @@ Stateflow { } midPoint [164.327 171.1967] chart 2 - linkNode [9 22 24] dataLimits [114.641 253.299 163.768 222.138] subviewer 2 slide { + mode MIRROR_SLIDE sticky BOTH_STICK } executionOrder 2 ssIdNumber 19 + linkNode [9 22 24] } transition { id 24 @@ -4049,14 +4702,15 @@ Stateflow { } midPoint [235.8157 224.6063] chart 2 - linkNode [9 23 25] dataLimits [174.702 274.547 184.34 230.694] subviewer 2 slide { + mode MIRROR_SLIDE sticky BOTH_STICK } executionOrder 2 ssIdNumber 21 + linkNode [9 23 25] } transition { id 25 @@ -4074,14 +4728,15 @@ Stateflow { } midPoint [244.9922 233.2938] chart 2 - linkNode [9 24 26] dataLimits [174.702 286.803 184.34 244.658] subviewer 2 slide { + mode MIRROR_SLIDE sticky BOTH_STICK } executionOrder 1 ssIdNumber 22 + linkNode [9 24 26] } transition { id 26 @@ -4099,14 +4754,15 @@ Stateflow { } midPoint [337.7298 228.7341] chart 2 - linkNode [9 25 27] dataLimits [303.003 406.474 184.34 244.585] subviewer 2 slide { + mode MIRROR_SLIDE sticky BOTH_STICK } executionOrder 1 ssIdNumber 23 + linkNode [9 25 27] } transition { id 27 @@ -4124,20 +4780,20 @@ Stateflow { } midPoint [348.1617 220.8024] chart 2 - linkNode [9 26 0] dataLimits [317.63 406.474 184.34 232.501] subviewer 2 slide { + mode MIRROR_SLIDE sticky BOTH_STICK } executionOrder 2 ssIdNumber 20 + linkNode [9 26 0] } data { id 28 ssIdNumber 24 name "speed" - linkNode [2 0 29] scope INPUT_DATA machine 1 props { @@ -4145,14 +4801,17 @@ Stateflow { primitive SF_DOUBLE_TYPE units "double" } + unit { + name "inherit" + } } dataType "double" + linkNode [2 0 29] } data { id 29 ssIdNumber 25 name "gear" - linkNode [2 28 30] scope OUTPUT_DATA machine 1 props { @@ -4173,14 +4832,17 @@ Stateflow { units "int" } frame SF_FRAME_NO + unit { + name "inherit" + } } dataType "fixdt(0,8,5)" + linkNode [2 28 30] } data { id 30 ssIdNumber 26 name "TWAIT" - linkNode [2 29 31] scope PARAMETER_DATA initFromWorkspace 1 machine 1 @@ -4196,67 +4858,77 @@ Stateflow { bias "0" } } + unit { + name "inherit" + } } dataType "fixdt(0,8,6)" + linkNode [2 29 31] } data { id 31 ssIdNumber 27 name "up_th" - linkNode [2 30 32] scope INPUT_DATA machine 1 props { type { primitive SF_DOUBLE_TYPE } + unit { + name "inherit" + } } dataType "double" + linkNode [2 30 32] } data { id 32 ssIdNumber 28 name "down_th" - linkNode [2 31 0] scope INPUT_DATA machine 1 props { type { primitive SF_DOUBLE_TYPE } + unit { + name "inherit" + } } dataType "double" + linkNode [2 31 0] } event { id 33 ssIdNumber 29 name "CALC_TH" - linkNode [2 0 0] scope OUTPUT_EVENT trigger FUNCTION_CALL_EVENT machine 1 + linkNode [2 0 0] } instance { id 34 - name "ShiftLogic" machine 1 + name "ShiftLogic" chart 2 } target { id 35 + machine 1 name "sfun" codeFlags "" - machine 1 - linkNode [1 0 36] checksumOld [669254712 3226503146 2893573782 4148113788] + linkNode [1 0 36] } target { id 36 + machine 1 name "rtw" description "Default S-Function target." codeFlags " comments=0 preservenames=0 preservenameswithparent=0 exportcharts=0 statebitsets=1 databitsets=1 " "debug=0 telemetry=0 project=0 multiinstanced=0 echo=0 initializer=1 ioformat=1" - machine 1 linkNode [1 35 0] } } diff --git a/Params/m_src/N2Nn.m b/Params/m_src/N2Nn.m index cdd3130d..980f55a8 100644 --- a/Params/m_src/N2Nn.m +++ b/Params/m_src/N2Nn.m @@ -43,7 +43,7 @@ Nn = N2NnIter(n,p,nb); else % this is where we need some smarts, let's do simple first rng(1, 'twister'); % seed random generator to get deterministic results - if max_num_new < 1e6 % if max_num_new is still reasonable, just truncate full grid + if max_num_new < 1e5 % if max_num_new is still reasonable, just truncate full grid Nn = N2NnIter(n,p,nb); %FullNn = N2NnIter(n,p,nb); %idx= randperm(max_num_new); @@ -51,7 +51,7 @@ % always include/starts with min and max corners %Nn = unique([ones(n,1) nb' Nn(:,2:end)]', 'rows','stable')'; else % otherwise random stuff until we get enough unique vectors - Nn = unique(RandNn(n,nb,1e7)', 'rows', 'stable')'; + Nn = unique(RandNn(n,nb,1e6)', 'rows', 'stable')'; while size(Nn, 2) < num_new Nn_more = RandNn(n,nb,num_new); Nn = unique([Nn Nn_more]', 'rows','stable')'; diff --git a/Plots/BreachSamplesPlot.m b/Plots/BreachSamplesPlot.m index 4e69f22b..7ac2e609 100644 --- a/Plots/BreachSamplesPlot.m +++ b/Plots/BreachSamplesPlot.m @@ -279,11 +279,18 @@ function update_brset_plot(this) y_label = 'idx sample'; case 'auto' if isempty(this.data.variables) - y_label = B.P.ParamList(B.P.DimX+1); + if B.P.DimP>B.P.DimX + y_label = B.P.ParamList(B.P.DimX+1); + else + y_label = ''; + end else y_label = this.data.variables{1}; end ydata = B.GetParam(y_label,idx); + if isempty(ydata) + ydata = xdata*0; + end otherwise % assumes y_axis is a parameter name ydata = B.GetParam(this.y_axis, idx); y_label = this.y_axis; @@ -375,7 +382,6 @@ function ctxtfn_signals_plot(o,e) end sig = this.signature.signals{1}; F = BreachSignalsPlot(this.BrSet,sig, it); - set(F.Fig,'Name', ['Trace idx= ' num2str(it)]); else warning('BreachSamplesPlot:no_signal','No signal(s) to plot.'); end @@ -401,8 +407,7 @@ function ctxtfn_signals_plot(o,e) end - - + function update_req_plot(this) B = this.BrSet.BrSet; @@ -1011,8 +1016,7 @@ function ctxtfn_signals_plot(o,e) it = this.idx_tipped(1); end sig = this.signature.signals{1}; - F = BreachSignalsPlot(this.BrSet,sig, it); - set(F.Fig,'Name', ['Trace idx= ' num2str(it)]); + F = BreachSignalsPlot(this.BrSet,sig, it); end end diff --git a/Plots/BreachSignalsPlot.m b/Plots/BreachSignalsPlot.m index cb36bafd..c5a28fb4 100644 --- a/Plots/BreachSignalsPlot.m +++ b/Plots/BreachSignalsPlot.m @@ -3,8 +3,13 @@ properties BrSet Fig - Axes - ipts + Axes + Summary + end + + properties(SetAccess=protected, GetAccess=public) + ipts + zero_rob_line_name = 'zero robustness line' end methods @@ -23,33 +28,63 @@ end this.BrSet = BrSet; - this.Fig = figure; + this.Summary = BrSet.GetSummary(); + if isa(this.BrSet, 'BreachRequirement') + this.Summary.num_traces =this.Summary.num_traces_evaluated; + end + + this.Fig = figure; + + set(this.Fig, 'KeyPressFcn', @(o,e)this.key_pressed_callback(o,e)); + this.ipts = ipts; if ischar(signals) signals = {signals}; end - for is = 1:numel(signals) + for is = 1:numel(signals) % plot signals on separate axes this.AddSignals(signals{is}, is); - end + end + this.update_title(); end - function ax = AddAxes(this, pos) + function key_pressed_callback(this, o,e) + switch e.Key + case 'rightarrow' + if ismember(e.Modifier,'shift') + this.next_ipts(ceil(this.Summary.num_traces/10)); + elseif ismember(e.Modifier,'control') + this.next_ipts(10); + else + this.next_ipts(); + end + case 'leftarrow' + if ismember(e.Modifier,'shift') + this.prev_ipts(ceil(this.Summary.num_traces/10)); + elseif ismember(e.Modifier,'control') + this.prev_ipts(10); + else + this.prev_ipts(); + end + end + end + + function ax = AddAxes(this,pos) % AddAxes add new axe at specified position if nargin==1 pos = numel(this.Axes)+1; end num_ax_old = numel(this.Axes); if numel(this.Axes)>0 - Xlim = get(this.Axes(1),'XLim'); + Xlim = get(this.Axes(1).ax,'XLim'); end for ia = 1:num_ax_old if ia < pos - subplot(num_ax_old+1, 1, ia, this.Axes(ia)) + subplot(num_ax_old+1, 1, ia, this.Axes(ia).ax) else - subplot(num_ax_old+1, 1, ia+1, this.Axes(ia)) + subplot(num_ax_old+1, 1, ia+1, this.Axes(ia).ax) end end @@ -60,7 +95,11 @@ if exist('Xlim', 'var') set(ax, 'XLim', Xlim); end - this.Axes = [this.Axes(1:pos-1) ax this.Axes(pos:end)]; + + new_ax_struct.ax = ax; + new_ax_struct.signals= {}; + new_ax_struct.robs = {}; + this.Axes = [this.Axes(1:pos-1) new_ax_struct this.Axes(pos:end)]; if isempty(this.Fig) this.Fig = figure; else @@ -68,7 +107,7 @@ end if numel(this.Axes)>1 - linkaxes(this.Axes, 'x'); + linkaxes(arrayfun(@(c)(c.ax),this.Axes),'x'); end ax = this.AddAxesContextMenu(ax); % default to horizontal zoom mode @@ -77,23 +116,23 @@ end function DeleteAxes(this, pos) - % DeleteAxe Remove axe at specified position + % DeleteAxe Remove axe at specified position num_ax_old = numel(this.Axes); - this.Axes(pos).delete; + this.Axes(pos).ax.delete; this.Axes = [this.Axes(1:pos-1) this.Axes(pos+1:end)]; - for ia = 1:num_ax_old-1; - subplot(num_ax_old-1, 1, ia, this.Axes(ia)) + for ia = 1:num_ax_old-1 + subplot(num_ax_old-1, 1, ia, this.Axes(ia).ax) end figure(this.Fig); if ~isempty(this.Axes) - linkaxes(this.Axes, 'x'); + linkaxes(arrayfun(@(c)(c.ax),this.Axes), 'x'); end end - function AddSignals(this,sigs, ax, itraces) + function AddSignals(this,sigs,ax,itraces) if ischar(sigs) sigs = {sigs}; end @@ -110,13 +149,13 @@ function AddSignals(this,sigs, ax, itraces) if isnumeric(ax) if ax==0 - this.AddAxes(1); - ax = this.Axes(1); + this.AddAxes(1); + ax = this.Axes(1); elseif ax > numel(this.Axes) - this.AddAxes(); - ax =this.Axes(end); - else - ax = this.Axes(ax); + this.AddAxes(); + ax =this.Axes(end).ax; + else + ax = this.Axes(ax).ax; end end if ~isa(ax, 'matlab.graphics.axis.Axes') @@ -129,17 +168,60 @@ function AddSignals(this,sigs, ax, itraces) end this.update_legend(ax); end - + + function AddRobSignals(this,sigs,ax,itraces,ireq) + if ischar(sigs) + sigs = {sigs}; + end + + if ~exist('ax', 'var')||isempty(ax) + ax = numel(this.Axes)+1; + end + + if ~exist('itraces', 'var') + itraces = this.ipts; + elseif strcmp(itraces, 'all') + itraces = 1:size(this.BrSet.P.pts,2); + end + + if ~exist('ireq', 'var') + ireq = 1; + elseif ischar(ireq) + [~ , ireq] = this.BrSet.get_req_from_name(ireq); + end + + if isnumeric(ax) + if ax==0 + this.AddAxes(1); + ax = this.Axes(1); + elseif ax > numel(this.Axes) + this.AddAxes(); + ax =this.Axes(end).ax; + else + ax = this.Axes(ax).ax; + end + end + if ~isa(ax, 'matlab.graphics.axis.Axes') + error('Argument should be an Axes object or an index.') + end + + for is = 1:numel(sigs) + sig = sigs{is}; + this.plot_rob(sig, ax, itraces,ireq); + end + this.update_legend(ax); + end + function PlotDiagnostics(this, req) req.plot_full_diagnostics(this); for ia = 1:numel(this.Axes) - this.update_legend(this.Axes(ia)); + this.update_legend(this.Axes(ia).ax); end end function int_false= HighlightFalse(this, sig, ax,inv) if ~exist('ax', 'var')||isempty(ax) - ax = this.Axes(end); + ax = this.Axes(end).ax; end if ~exist('inv', 'var')||isempty(inv) inv = false; @@ -160,7 +242,7 @@ function PlotDiagnostics(this, req) end - function update_legend(this, ax) + function update_legend(this, ax) l = legend('-DynamicLegend'); c = flipud(get(ax, 'Children')); num_patch = 0; @@ -208,10 +290,98 @@ function update_legend(this, ax) set(l, 'Interpreter', 'None'); end + function pos = get_pos_from_ax(this,ax) + for pos = 1:numel(this.Axes) + if isequal(this.Axes(pos).ax,ax) + return; + end + end + if pos == numel(this.Axes) + error('Axes not found!'); + end + end + + function update_axes(this, ax) + if nargin==1 + Axes_to_update = this.Axes; + elseif isa(ax, 'matlab.graphics.axis.Axes') + Axes_to_update = ax; + elseif isnumeric(ax) + Axes_to_update = this.Axes(ax).ax; + end + + for A = Axes_to_update + ax = A.ax; + this.plot_signal(A.signals,ax,this.ipts); + if isa(this.BrSet, 'BreachRequirement') + if ~isempty(A.robs) + for ireq=1:numel(this.BrSet.req_monitors) % TODO: precond_monitors... + if ~isempty(A.robs{ireq}) + this.plot_rob(A.robs{ireq},ax,this.ipts,ireq); + end + end + end + end + end + end + + function set_ipts(this,ipts) + this.ipts= ipts; + this.update_axes(); + this.update_title(); + end + + + function next_ipts(this, num) + if nargin<2 + num = 1; + end + this.ipts = min(this.ipts+num, this.Summary.num_traces); + this.update_axes(); + this.update_title(); + end + + function prev_ipts(this,num) + if nargin<2 + num = 1; + end + this.ipts = max(1,this.ipts-num); + this.update_axes(); + this.update_title(); + end + + function update_title(this) + ttle = [this.BrSet.whoamI ': ']; + if isa(this.BrSet, 'BreachRequirement') + num_traces= this.Summary.num_traces_evaluated; + ttle = [ttle 'Trace ' num2str(this.ipts) '/' num2str(num_traces) '. ']; + % checks violations + + if this.Summary.num_violations_per_trace(this.ipts)>0 + status_vio = ' Status: False'; + else + status_vio = ' Status: True'; + end + + vio= find(this.Summary.num_violations_per_trace(this.ipts+1:end),1); + + if ~isempty(vio) + status_vio = [status_vio ' (Next False idx:' num2str(vio+this.ipts) ').']; + end + ttle = [ttle status_vio]; + + else + num_traces= this.Summary.num_traces; + ttle = [ttle 'Trace ' num2str(this.ipts) '/' num2str(num_traces)]; + end + set(this.Fig,'Name',ttle, 'NumberTitle', 'off'); + end + + end methods (Access=protected) - + function ax = AddAxesContextMenu(this, ax) cm = uicontextmenu(this.Fig); set(ax, 'UIContextMenu', cm); @@ -274,16 +444,29 @@ function update_legend(this, ax) for ir = 1:numel(this.BrSet.req_monitors) uimenu(trm, 'Label', this.BrSet.req_monitors{ir}.name,'Callback', @(o,e)ctxtfn_plot_full_diag(this.BrSet.req_monitors{ir},o,e)); end - end + rob_mnu = uimenu(cm, 'Label', 'Plot Robustness Signal'); + rob_mnu_map = containers.Map(); + + for ir = 1:numel(this.BrSet.req_monitors) + req = this.BrSet.req_monitors{ir}; + if isa(req, 'stl_monitor') + phi_name = req.name; + phi = req.formula; + cmu = uimenu(rob_mnu, 'Label',phi_name); + this.get_mnu(ax,cmu,phi,ir); + + end + end + end uimenu(cm, 'Label', 'Add axes above','Separator', 'on', 'Callback', @(o,e)ctxtfn_add_axes_above(ax,o,e)); uimenu(cm, 'Label', 'Add axes below', 'Callback', @(o,e)ctxtfn_add_axes_below(ax, o,e)); uimenu(cm, 'Label', 'Reset axes','Separator', 'on', 'Callback', @(o,e)ctxtfn_reset_axes(ax, o,e)); uimenu(cm, 'Label', 'Delete axes', 'Callback', @(o,e)ctxtfn_delete_axes(ax, o,e)); - + function ctxtfn_add_axes_above(ax, ~,~) for ia = 1:numel(this.Axes) - if isequal(ax,this.Axes(ia)) + if isequal(ax,this.Axes(ia).ax) break; end end @@ -292,7 +475,7 @@ function ctxtfn_add_axes_above(ax, ~,~) function ctxtfn_add_axes_below(ax, ~,~) for ia = 1:numel(this.Axes) - if isequal(ax,this.Axes(ia)) + if isequal(ax,this.Axes(ia).ax) break; end end @@ -301,7 +484,7 @@ function ctxtfn_add_axes_below(ax, ~,~) function ctxtfn_delete_axes(ax, ~,~) for ia = 1:numel(this.Axes) - if isequal(ax,this.Axes(ia)) + if isequal(ax,this.Axes(ia).ax) break; end end @@ -310,11 +493,14 @@ function ctxtfn_delete_axes(ax, ~,~) function ctxtfn_reset_axes(ax, ~,~) cla(ax); + pos = this.get_pos_from_ax(ax); + this.Axes(pos).signals = {}; title(''); legend off; end function ctxtfn_add_signal(ax, sig, ~,~) + this.plot_signal(sig, ax); this.update_legend(ax); end @@ -323,32 +509,159 @@ function ctxtfn_highlight_false(ax, sig, ~,~) this.HighlightFalse(sig, ax); end - function ctxtfn_plot_full_diag(req, ~,~) - + function ctxtfn_plot_full_diag(req, ~,~) this.PlotDiagnostics(req); + end + + end + + function get_mnu(this,ax,mnu_parent, phi,ir,o,e) + + if exist('o','var') + mnu_parent = o; + set(mnu_parent, 'Callback', @(o,e)do_nothing()); + i0 = 2; + else + i0 = 1; end - + [st_phis, phi_ids, not_expanded] =tree_disp(phi,0,2); + for i = i0:numel(st_phis) + + phi_str = strtrim(st_phis{i}); + phi_str = strrep(phi_str,'|-',''); + if isempty(not_expanded{i}) + mm= uimenu(mnu_parent, 'Label',st_phis{i},... + 'Callback', @(o,e)ctxtfn_plot_rob(phi_str,o,e)); + else + mm = uimenu(mnu_parent,'Label',st_phis{i}, ... + 'Callback', @(o,e)(this.get_mnu(ax,mnu_parent, not_expanded{i},ir,o,e))); + uimenu(mm, 'Label',disp(not_expanded{i},2),... + 'Callback', @(o,e)ctxtfn_plot_rob(disp(not_expanded{i}),o,e)); + end + end + + function ctxtfn_plot_rob(phi_str,~,~) + this.plot_rob(phi_str, ax,this.ipts, ir); + this.update_legend(ax); + end + function do_nothing() + end + end + + function h = get_line_from_signal_name(this, ax, signame) + h = []; + ch = get(ax,'Children'); + for idx_l =1:numel(ch) + c = ch(idx_l); + if strcmp(get(c,'DisplayName'), signame) + h = c; + end + end end + function l = plot_rob(this, formulas, ax, ipts, ireq) + % + if isempty(formulas) + l = []; + return + end + if ~iscell(formulas) + formulas= {formulas}; + end + + pos = this.get_pos_from_ax(ax); + if isempty(this.Axes(pos).robs) + this.Axes(pos).robs=cell(1, numel(this.BrSet.req_monitors)); + end + + this.Axes(pos).robs{ireq} = union(this.Axes(pos).robs{ireq}, formulas); + + if ~exist('ipts', 'var') + ipts= this.ipts; + end + + axes(ax); + hold on; + itraj = unique(this.BrSet.P.traj_ref(ipts), 'stable'); + + time = this.BrSet.P.traj{itraj}.time; + ch = get(ax,'Children'); + if isempty(ch) + set(ax, 'XLimMode', 'auto', 'YLimMode', 'auto'); + end + + for f = formulas + l = this.get_line_from_signal_name(ax, f{1}); % FIXME: here we + [t,r]= this.BrSet.GetRobustSat(ireq, itraj, f{1}); + if isempty(l) + l = plot(t, r, 'DisplayName', f{1}); + else + set(l,'XData',t,'YData',r); + end + if isempty(this.get_line_from_signal_name(ax,this.zero_rob_line_name)) + plot(time, 0*time, 'DisplayName', this.zero_rob_line_name, 'LineStyle', '--', 'Color','r'); + end + end + + + end - function plot_signal(this, sig, ax, ipts) + function l = plot_signal(this, sig, ax, ipts) + if isempty(sig) + l = []; + return + end + + pos = this.get_pos_from_ax(ax); + + this.Axes(pos).signals = union(this.Axes(pos).signals, sig); if ~exist('ipts', 'var') - ipts= this.ipts; + ipts= this.ipts; end + axes(ax); hold on; itraj = unique(this.BrSet.P.traj_ref(ipts), 'stable'); - for k = 1:numel(itraj) - time = this.BrSet.P.traj{itraj(k)}.time; - sig_values = this.BrSet.GetSignalValues(sig, itraj(k)); - if ~isempty(sig_values) - if k==1 - l = plot(time , sig_values, 'DisplayName', sig); + if ~iscell(sig) + sig= {sig}; + end + time = this.BrSet.P.traj{itraj}.time; + ch = get(ax,'Children'); + if isempty(ch) + set(ax, 'XLimMode', 'auto', 'YLimMode', 'auto'); + end + + for s = sig + % find out if it's a robustness signal or not + if isa(this.BrSet,'BreachRequirement') + [~, b, ~, bb]= this.BrSet.FindSignalsIdx(s{1}); + else + b=true; + end + if b||bb + sig_values = this.BrSet.GetSignalValues(s{1}, itraj); + l = this.get_line_from_signal_name(ax, s{1}); + if isempty(l) + l = plot(time , sig_values, 'DisplayName', s{1}); else - l = plot(time , sig_values); + set(l, 'XData',time,'YData',sig_values); end + + else % try robustnes... should be obsolete + warning('Not sure what I am doing here, plot_signal but trying robustness signal ?'); + l = this.get_line_from_signal_name(ax, s{1}); + [t,r]= this.BrSet.GetRobustSat(1, itraj, s{1}); + if isempty(l) + l = plot(t, r, 'DisplayName', s{1}); + else + set(l,'XData',t,'YData',r); + end + if isempty(this.get_line_from_signal_name(ax,this.zero_rob_line_name)) + plot(time, 0*time, 'DisplayName', this.zero_rob_line_name, 'LineStyle', '--', 'Color','r'); + end + end end diff --git a/README.md b/README.md index f280ae80..62a1613f 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,339 @@ -# README # +# Breach Toolbox +- [Introduction](#introduction) +- [Getting started](#getting-started) + - [Setup](#setup) + - [Builtin demos](#builtin-demos) + - [Contact/Support](#contactsupport) +- [Importing time series data](#importing-time-series-data) +- [Monitoring Signal Temporal Logic (STL) Formulas](#monitoring-signal-temporal-logic-stl-formulas) + - [Writing STL requirements in a file](#writing-stl-requirements-in-a-file) + - [Evaluating an STL formula on data](#evaluating-an-stl-formula-on-data) + - [Going further](#going-further) +- [Interfacing a Simulink model](#interfacing-a-simulink-model) + - [Varying parameters](#varying-parameters) + - [Signals](#signals) + - [Top level input and output signals](#top-level-input-and-output-signals) + - [Internal signals](#internal-signals) + - [Input signals generation](#input-signals-generation) + - [Going further](#going-further-1) + - [Running and testing multiple simulations](#running-and-testing-multiple-simulations) + - [Going further](#going-further-2) +- [Falsification](#falsification) + - [Going further](#going-further-3) +- [Interfacing a generic simulator](#interfacing-a-generic-simulator) -Breach is a Matlab toolbox for simulation-based design of dynamical/CPS/Hybrid systems. +[link](#section) -## Install -- Setup a C/C++ compiler using mex -setup -- add path to Breach folder -- Run InstallBreach -- (Optional) save path +# Introduction + +Breach is a Matlab toolbox for time series analysis and simulation-based analysis of dynamical/CPS/Hybrid systems. It can be useful to the prospective user (you) in the following situations: +- You have **time series data** and wants to check whether it satisfies some property +- You need **signal temporal logic (STL) monitoring capability**, e.g., to check formal requirements on your data +- You have a **Simulink models** and wants to perform **extensive testing** by running multiple simulations (e.g., parameter sweep) and quickly browse through the results, and/or assert whether some (STL) property is satisfied by simulations (random/Monte-Carlo testing) +- You need to **falsify** an STL requirement using various optimization algorithm, i.e., find **test cases of interest** +- You want to do some or all of the above to for a model implemented with **a simulator other than Simulink**. -## For subsequent use -- add path to Breach folder (if not previously saved) -- run InitBreach +The following describes the initial steps to get started with the above tasks. -## Getting Started +# Getting started -Type 'BrDemo.' and Tab to get a list of available demo scripts. +## Setup +To setup and use Breach, start Matlab and run `InitBreach` from the main Breach folder. This needs only to be done once per Matlab session. -Running GenDoc() will run all demos and publish results into Doc folder, -accessible via Doc/index.html. A version of html documentation is also -available -[online](https://bitbucket.decyphir.io/breach-docs/index.html). +## Builtin demos +Type `BrDemo.` and `Tab` key to get a list of available scripts to run for testing and demoing the toolbox. E.g., +``` +>> BrDemo.AFC_1_Interface +``` +Running `GenDoc()` will run all demos and publish results into the `Doc/index.html` folder. Note that this operation can take some time to complete. The index files is generated early in the process and the first sections are quickly available. ## Contact/Support - Contact info at decyphir dot com to report bugs, for help, complaints, support, etc. + +# Importing time series data + +Breach handles times series as *traces*, which are objects consisting of data indexed with a time array, *i.e.*, a strictly increasing array starting at 0. For example: +```matlab +not_time = [3 4 1 7]; % not valid because it is not increasing +not_time_either = [ 3 4 5 7]; % not valid because the first element is not 0 +ok_time = [0 3 4 5 7]; % valid +``` +A trace can be imported in Breach as 2d arrays where the first column is the time array. The relevant object is a `BreachTraceSystem`. We create one by declaring the names of the *signal* traces it will contain, where a signal a function of time mapping a time value to a scalar. Below we create one such object for, say, temperature and humidity data: +```matlab +Bdata = BreachTraceSystem({'temperature', 'humidity'}); +``` +It contains no data at this point. Next we create some artificial data corresponding to one hypothetical day of measurment, and add it to `B`. +```matlab +time = 0:.1:24; % in hours +temperature = 10 + 15*cos(pi*(time-3)/12+pi)+sin(pi/2*time); % in Celsius deg +humidity = 50 + 10*cos(pi*(time+2)/12)+sin(pi/3*time); % in percents +trace = [time' temperature' humidity']; % combine into a trace, column oriented +Bdata.AddTrace(trace); +``` + +A BreachTraceSystem object can contain multiple traces. Repeating the `AddTrace` call with a different trace will result in B containing two traces, etc. Traces can be plotted using the `PlotSignals` method: +```matlab +>> Bdata.PlotSignals(); +``` + +# Monitoring Signal Temporal Logic (STL) Formulas + +Signal Temporal Logic (STL) is a formalism to express predicates on the values of signals. STL formulas consist of atomic predicates connected by Boolean and temporal operators. For example, the formula `alw (temperature[t]<25) and ev_[0, 12] (humidity[t]>50)` for the synthetic data above means that the temperature stays below 25 all day and that at some point in the morning (0 being midnight and 12 being noon), the humidity gets above 50 percents. A formula is constructed using `STL_Formula` objects, which takes a name and a string as constructor arguments: +```matlab +>> phi = STL_Formula('phi', 'alw (temperature[t]<25) and ev_[0, 12] (humidity[t]>50)') +``` +## Writing STL requirements in a file +STL formulas can be specified in a separate file, which makes it easier to create complex formulas using subformulas. Breach supports parameters also. The following illustrates rewriting the above formulas using Breach file format. +```python +# File: Example_of_STL_spec_file.stl +# This is a comment. We define first parameters +param temp_threshold=25, humidity_threshold=50 + +# Atomic predicates are defined next +temp_is_ok := temperature[t] < temp_threshold +humidity_is_high := humidity[t] > humidity_threshold + +# Individual sub-formulas are defined next +temp_is_ok_all_day := alw (temp_is_ok) +humidity_is_high_before_noon := ev_[0, 12] (humidity_is_high) + +# Final formula +phi := temp_is_ok_all_day and humidity_is_high_before_noon +``` +To read an STL file, use the `STL_ReadFile`: +```matlab +>> STL_ReadFile('Example_of_STL_spec_file.stl') +``` +Using this command defines all formulas in the file and make them available as STL_Formula objects in the Matlab workspace. + +## Evaluating an STL formula on data + +To evaluate an STL formula one needs to define a `BreachRequirement` object that can be constructed directly from an `STL_Formula`: +```matlab +>> Rphi = BreachRequirement(phi); +``` +A `BreachRequirement` object can store and combine more than one STL requirement or specification but this is its most common use. After creation, one can use the `Eval` method on data to check the satisfaction of its requirement. +```matlab +>> Rphi.Eval(Bdata) + +ans = + + 0.4064 +``` +Note that the output is not a Boolean, but a real number. Breach computes so-called *quantitative* semantics, or *robustness*, of STL formulas. It can be interpreted as follows: if it is striclty positive, the formula is satisfied. If it is strictly negative, the formula is not satisfied by the data. When it is 0, it can be either way. The magnitude gives a hint of how "robustly" the formula is satisfied or violated. In this case, the number has a simple interpretation: the max temperature is about 24.6 Celsius degrees, i.e., about 0.4 degree below our threshold, which is the number we got. + +## Going further +For more information on specifications and how to use them, type this command into the Matlab prompt. +```matlab +>> edit BrDemo.AFC_4_Specifications.m +``` +and run the corresponding script. + +# Interfacing a Simulink model + +Breach can act as a test harness for any Simulink model using the `BreachSimulinkSystem` class. To do so, one needs to decide which *parameters* Breach will be able to change before running a simulations and which *signals* will be monitored by Breach (these signals will be available for use in STL formulas). + +## Varying parameters +Varying parameters are most commonly those initialized in Matlab workspace before running Simulink. In the model itself, they reference the corresponding variable names. As a single example, consider the PI controller for the 'AbstractFuelControl' model (AFC in short, available in the Ext/Models folder) pictured below. The proportional gain and integral gain are using variables `kp` and `ki`. + +![AFC PI controller](Doc/img/AFC_PI.svg) + +These parameters are initialised in the `InitAFCparams` script, along with others used elsewhere. +```matlab +fuel_inj_tol = 1.0; +(...) +kp = 0.04; +ki = 0.14; +``` +Note that if the model has some callback script run before each simulation, these scripts should not redefine the parameters interfaced with Breach. + +## Signals +### Top level input and output signals +For a given Simulink model, input and output blocks are automatically monitored. In the AFC example from the diagram below, this means Breach will monitor input signals `Pedal_Angle` and `Engine_Speed` and output signals `AF`, `AFref` and `controller_mode`. + +![AFC model top level](Doc/img/AFC_top_level.svg) + +### Internal signals +In addition to input and output signals, internal lines marked for logging in a Simulink models as shown below are detected and monitored by Breach. + +![AFC model internal signals](Doc/img/AFC_Internal_signals.svg) + +## Input signals generation + +Once parameters and signals are defined, a `BreachSimulinkSystem` object can be created: + +```matlab +BrDemo.InitAFCparams % this ensures that parameters needed by Simulink are initialized in the workspace +Bsim = BreachSimulinkSystem('AbstractFuelControl'); +``` + +By default input signals are assigned constant value determined by parameters names `input_name_u0`. E.g., in the AFC case, they are `Engine_Speed_u0` and `Pedal_Angle_u0`. In Breach, there are many ways to assign input generator similar to what the signal builder in Simulink can do. The relevant method is `SetInputGen`. Two basic usages are: +1. Constant time step input signals, using +```matlab +Bsim.SetInputGen('UniStep3'); % creates 3 parameters for each input signals +``` +2. Variable time step input signals, using +```matlab +Bsim.SetInputGen('VarStep3'); % creates 3 parameters for each input signals value and 10 time parameters +``` +In this case, parameters are named `input_name_u0,input_name_dt0, input_name_u1, input_name_dt1,...`, where the timing parameter `dt0` set the time difference between value `u0` and `u1`. +Many other options are available for signal generation. A GUI is available to explore some of them: +``` +Bsim.SetInputGenGUI; +``` + +![Input generator GUI](Doc/img/InputGenGUI.png) + + +## Going further +For more information type these command into the Matlab prompt +```matlab +>> edit BrDemo.AFC_1_Interface.m +>> edit BrDemo.AFC_2_Simulation.m +``` +and run the corresponding scripts. + +## Running and testing multiple simulations +To generate multiple simulations, one need to assign a range or domain of variation for some parameter(s) +```matlab +BrDemo.InitAFC; % Initialize the AFC model with a pulse generator for Pedal_Angle +var = {'Pedal_Angle_pulse_amp', 'Pedal_Angle_pulse_period'}; +ranges = [ 10 60 ; 10 15] % ranges for pulse amplitude and pulse period +BrAFC.SetParamRanges(var, ranges); % declare ranges +``` +We can then sample this domain. The two most common methods for sampling are grid and quasi-random. + +```matlab +Bgrid = BrAFC.copy(); +Bgrid.GridSample(5); % creates a grid of 5x5=25 samples + +Brand = BrAFC.copy(); +Brand.QuasiRandomSample(10); % Creates 10 samples quasi-randomly in the specified range. +``` +`Brand` and `Bgrid` are now objects with multiple configurations for the `AFC` model. Using the `Sim` will run all of them and store the corresponding traces. E.g., + +```matlab +Brand.Sim(40); % simulate AFC model until time 40 +Brand.PlotSignals({'Pedal_Angle', 'AF'}); +``` +To test an STL requirement on 10 random simulations, we can simply eval it on `Brand`. + +```matlab +STL_ReadFile(AFC_simple_spec.stl) +R = BreachRequirement(AF_alw_ok); +R.Eval(Brand) +``` +The `Eval` method evaluate the requirement for all 10 but returns a single value, by default the minimum over the 10 evaluations. The function `BreachSamplesPlot` can be used to examine the results in detail. +```matlab +BreachSamplesPlot(R) +``` +## Going further +For more information on sampling sets, type the following command at the Matlab prompt +```matlab +>> edit BrDemo.AFC_3_Sets.m +``` +and run the corresponding script. + +# Falsification + +Falsification is the process of letting an optimization algorithm run simulations searching for one that will violates a requirement. To setup a falsification run in Breach, one needs to + +1. create the interface and search space (e.g., a `BreachSimulinkSystem` object), +2. create or choose the requirement (`BreachRequirement` object) and +3. Create and setup a falsification problem (`FalsificationProblem`) + +Steps 1. and 2. are the same as above when preparing for testing multiple traces. +```matlab +% Step 1. create a BreachSimulinkSystem with variable parameters +BrDemo.InitAFC; % Initialize the AFC model with a pulse generator for Pedal_Angle +var = {'Pedal_Angle_pulse_amp', 'Pedal_Angle_pulse_period'}; +ranges = [ 10 60 ; 10 15] % ranges for pulse amplitude and pulse period +BrAFC.SetParamRanges(var, ranges); + +% Step 2. Create a BreachRequirement object from an STL formula +STL_ReadFile(AFC_simple_spec.stl); +R = BreachRequirement(AF_alw_ok); +``` +Step 3. is done directly by invoking the `FalsificationProblem` constructor: +```matlab +pb = FalsificationProblem(BrAFC,R); +``` +The problem is configured with default solver and options. Feeling adventurous, one can simply invoke the `solve` method to run falsification. Once it terminates, either after some time, or after finding a falsifying trace, results can be examined with the `GetLog` and `BreachSamplesPlot` functions. +```matlab +pb.solve(); +Rlog = pb.GetLog(); % returns a BreachRequirement object with evaluations of all traces computed during the falsification run +BreachSamplesPlot(Rlog); % interactive exploration of the run +``` + +## Going further +For more information on falsification problems, solvers, etc, type the following command at the Matlab prompt +```matlab +>> edit BrDemo.AFC_5_Falsification.m +``` +and run the corresponding script. + +# Interfacing a generic simulator + +For simulators other than Simulink, Breach offers a generic mechanism +to create an interface. As an example, consider the code used to create artificial weather data above, slightly modified to include two parameters: +```matlab +base_temp = 10; +base_humidity = 50; +time = 0:.1:24; % in hours +temperature = base_temp + 15*cos(pi*(time-3)/12+pi)+sin(pi/2*time); % in Celsius deg +humidity = base_humidity + 10*cos(pi*(time+2)/12)+sin(pi/3*time); % in percents +``` +This is equivalent to having a (admitedly extremely simplified) weather simulator taking base temperature and humidity as parameters and returning temperature and humidity signals for one day. This code can be encapsulated in a function `sim_weather` and a Breach interface can be created with a `BreachSystem` object: +```matlab +Bweather = BreachSystem('weather', ... % system name + {'temperature','humidity'},... % signals + {'base_temp','base_hum'},... % parameters + [30 50], ... % default values for parameters + @sim_weather); +``` + +Then `Bweather` can be used to compute multiple traces varying parameters, monitor STL specifications, perform falsification, etc. Below is the complete, commented code for the `sim_weather` function: + +```matlab +function [t_out, X,p] = sim_weather(Sys, t_in, p) +% sim_weather computes one trace of the weather system, given a set of parameter vectors p +% and a time specification t_in. +% +% [t_out,X,p] = sim_weather(Sys,p,t_in) +% +% Inputs: Sys, p and t_in are provided by Breach. +% - Sys is a structure with information about signals and parameters. In +% particular, Sys.ParamList is a cell of signals and parameter names such +% that: +% - Sys.ParamList(1:Sys.DimX) returns names of all signals +% - Sys.ParamList(Sys.DimX+1:Sys.DimP) returns the names of constant parameters +% - p is an array of length Sys.DimX+Sys.DimP. +% - t_in is of the form [0 t_in(end)] or [0 t_in(2) ... t_in(end)], strictly increasing +% +% Outputs: simfn has to return the following: +% - t_out must be such that t_out(1) =0 and t_out(end) = t_in(end). +% In addition, if t_in has more than two elements, then t_out must be +% equal to t_in. Otherwise, t_out can have as many elements as +% returned by the simulation. +% - X must be of dimensions (Sys.DimX, t_out). The rows of X must +% contain simulation results for signals named in Sys.ParamList(1:DimX) +% - p is the same as p unless the simulator changes it (outputs scalars +% in addition to signals) + +% recover parameters from p - for legacy reason, the first elements in p +% are for signals, and parameters start at index Sys.DimX+1 = 3 +base_temp =p(3); +base_hum = p(4); + +% compute signals - a simple function of time in this case but for a more complex +% simulator, this is where the actual call to the simulator will take place +temperature = base_temp + 15*cos(pi*(t_in-3)/12+pi)+sin(pi/2*t_in); % in Celsius deg +humidity = base_hum + 10*cos(pi*(t_in+2)/12)+sin(pi/3*t_in); % in percents + +% format outputs as expected by Breach +X = [temperature; + humidity]; +t_out = t_in; + +end +``` diff --git a/VERSION b/VERSION index 27f9cd32..9ab8337f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.0 +1.9.1