From 2e79143d9addb02f6fc6e4e39292ceb41a3ffc4f Mon Sep 17 00:00:00 2001 From: Tin Rabuzin Date: Tue, 23 Feb 2016 10:14:22 +0100 Subject: [PATCH 1/5] Adding script to run the second order example and change of the scope in the Simulink model. --- Examples/SecondOrder/run_example.m | 79 ++++++++++++++++++++++++ Examples/SecondOrder/variable_rafael.mdl | 40 ++++++------ 2 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 Examples/SecondOrder/run_example.m diff --git a/Examples/SecondOrder/run_example.m b/Examples/SecondOrder/run_example.m new file mode 100644 index 0000000..fc0d55a --- /dev/null +++ b/Examples/SecondOrder/run_example.m @@ -0,0 +1,79 @@ +%% ==========Moving to the example folder========== + +str = 'X:/dev/iTesla_RaPId/iTesla_RaPId/Examples/SecondOrder'; +cd(str); + +%% ==========Reference data settings========== + +%Output data +RaPIdObject.experimentData.pathToReferenceData = 'measuredDataO.mat'; %Data file name +RaPIdObject.experimentData.expressionReferenceTime = 'time'; %Time variable name +RaPIdObject.experimentData.expressionReferenceData = 'signal'; %Data variable name + +%Input data +RaPIdObject.experimentData.pathToInData = ''; + +%% ==========Experiment settings========== + +%General settings +RaPIdObject.experimentSettings.tf = 50; %Simulation length +RaPIdObject.experimentSettings.ts = 0.01; %Sampling time +RaPIdObject.experimentSettings.t_fitness_start = 4; %Start calculating fintess function after t_fintess_start +RaPIdObject.experimentSettings.timeOut = 2; %Seconds before simulation timeout +RaPIdObject.experimentSettings.integrationMethod = 'ode45'; %Solver selection +RaPIdObject.experimentSettings.solverMode = 'Simulink'; +RaPIdObject.experimentSettings.optimizationAlgorithm = 'pso'; %Selection of optimization algorithm +RaPIdObject.experimentSettings.maxIterations = 100; %Maximum number of estimation iterations +RaPIdObject.experimentSettings.verbose = 1; %Can trigger more data for debugging +RaPIdObject.experimentSettings.saveHist = 0; %Don't save history + +%Model related settings +RaPIdObject.experimentSettings.pathToSimulinkModel = 'variable_rafael.mdl'; %Simulink model file name +RaPIdObject.experimentSettings.pathToFMUModel = 'Rafael_0original_0estimated.fmu'; %FMU file name +RaPIdObject.experimentSettings.modelName = 'variable_rafael'; %Simulink model name +RaPIdObject.experimentSettings.blockName = 'variable_rafael/Rafael_original_estimated'; %FMU name +RaPIdObject.experimentSettings.scopeName = 'simout'; %Result sink name +RaPIdObject.experimentSettings.displayMode = 'Show'; + +%Estimation parameter settings +RaPIdObject.experimentSettings.p_0 = [0.3, 4.1, 1.7, 1.1]; %Initial parameter guess +RaPIdObject.experimentSettings.p_min = [0.1, 3.9, 1.5, 1.1]; %Minimum values of parameters +RaPIdObject.experimentSettings.p_max = [1, 4.2, 1.7, 1.5]; %Maximum values of parameters + +%Fitness function settings +RaPIdObject.experimentSettings.cost_type = 1; %Fitness function selection +RaPIdObject.experimentSettings.objective_weights = 1; %Weights of the output signals for fitness function + +%% ==========Optimization Algorithm settings========== + +switch RaPIdObject.experimentSettings.optimizationAlgorithm + case 'pso' + RaPIdObject.psoSettings.w = 0.25; %Particle inertia weight + RaPIdObject.psoSettings.self_coeff = 0.25; %Self recognition coefficient + RaPIdObject.psoSettings.social_coeff = 0.25; %Social coefficient + RaPIdObject.psoSettings.limit = 0.25; %Iteration limit + RaPIdObject.psoSettings.nRandMin = 8; %Minimum number of random particles + RaPIdObject.psoSettings.nb_particles = 8; %Number of particles + RaPIdObject.psoSettings.fitnessStopRatio = 1e-5; %Fitness stop ratio + RaPIdObject.psoSettings.kick_multiplier = 0.002; %Kick multiplier + RaPIdObject.psoSettings.method = 'PSO'; +end + +%% ==========FMU parameters, inputs and outputs========== + +RaPIdObject.parameterNames = {'transferFunction.b[1]','transferFunction.a[1]','transferFunction.a[2]','transferFunction.a[3]'}; +RaPIdObject.fmuInputNames = {}; +RaPIdObject.fmuOutputNames = {'y1'}; %Output variable names + +%% ==========Running the computation========== + +%Opening simulink model +open_system(RaPIdObject.experimentSettings.pathToSimulinkModel); %Opening the simulink model +open_system(strcat(RaPIdObject.experimentSettings.modelName,'/Scope')); %Opening the scope in the model to observe estimation process +pause(1); %Waiting one second for scope to initialize +%% + +%Starting the estimation process +[sol, hist] = rapid(RaPIdObject); +sprintf('Vector of estimated parameters is: %s',mat2str(sol,3)) + diff --git a/Examples/SecondOrder/variable_rafael.mdl b/Examples/SecondOrder/variable_rafael.mdl index a6371ae..4ee5961 100644 --- a/Examples/SecondOrder/variable_rafael.mdl +++ b/Examples/SecondOrder/variable_rafael.mdl @@ -6,7 +6,7 @@ Model { NumRootInports 0 NumRootOutports 0 ParameterArgumentNames "" - ComputedModelVersion "1.22" + ComputedModelVersion "1.24" NumModelReferences 0 NumTestPointedSignals 0 } @@ -39,7 +39,7 @@ Model { DockPosition "Left" Width [50] Height [50] - Filter [8] + Filter [9] } Object { $PropName "ExplorerBarInfo" @@ -56,7 +56,7 @@ Model { LoadSaveID "0" Extents [1512.0, 869.0] ZoomFactor [3.5635593220338988] - Offset [-2.1474435196194435, 50.071343638525562] + Offset [-2.1474435196194577, 50.071343638525548] } } } @@ -66,9 +66,9 @@ Model { ModifiedByFormat "%" LastModifiedBy "Tin Rabuzin" ModifiedDateFormat "%" - LastModifiedDate "Fri Feb 19 15:13:42 2016" - RTWModifiedTimeStamp 377795587 - ModelVersionFormat "1.%" + LastModifiedDate "Tue Feb 23 09:54:14 2016" + RTWModifiedTimeStamp 378122050 + ModelVersionFormat "1.%" ConfigurationManager "None" SampleTimeColors off SampleTimeAnnotations off @@ -850,8 +850,8 @@ Model { Position [310, 207, 350, 263] ZOrder -3 Floating off - Location [207, 743, 907, 1016] - Open on + Location [389, 469, 1296, 987] + Open off NumInputPorts "1" List { ListType AxesTitles @@ -859,12 +859,12 @@ Model { } List { ListType ScopeGraphics - FigureColor "[0.501960784313725 0.501960784313725 0.501960784313725]" - AxesColor "[0 0 0]" - AxesTickColor "[1 1 1]" - LineColors "[1 1 0;1 0 1;0 1 1;1 0 0;0 1 0;0 0 1]" + FigureColor "[1 1 1]" + AxesColor "[1 1 1]" + AxesTickColor "[0 0 0]" + LineColors "[0 0 1;1 0 0;0 1 1;1 0 0;0 1 0;0 0 1]" LineStyles "-|-|-|-|-|-" - LineWidths "[0.5 0.5 0.5 0.5 0.5 0.5]" + LineWidths "[2 2 0.5 0.5 0.5 0.5]" MarkerStyles "none|none|none|none|none|none" } ShowLegends off @@ -942,7 +942,7 @@ MatData { "6UE '-T;W!4:6UE !T;VQE0 . , 8 ( !@ % \" 0 ) X P !" "@ @ ) @ 4 ( 0 $ ! ( 0 ! #@ #@ & \" 8 !0 @ ! 0" - " $ \"0 @ 400 X P !@ @ ) @ 4 ( 0 $ ! ( 0 ! #@ " + " $ \"0 @ @ D(0 X P !@ @ ) @ 4 ( 0 $ ! ( 0 ! #@ " " % & \" 0 !0 @ ! &0 $ $ !D !2869A96Q?;W)I9VEN86Q?97-T:6UA=&5D " " X P !@ @ ) @ 4 ( 0 $ ! ( 0 ! #@ (@ & \" ( !0 " " @ ! 0 $ !0 $ T ! #0 &9M:6QL;V=L979E; . . 8 ( ! % \" " @@ -1122,17 +1122,17 @@ MatData { "871H &9O;&1EFEP961P871H ')E;&%T:7" "9E9FUU9F]L9&5R &1L;'!A=&@ 'AM;'!A=&@ %)E;&]A9 %)E;&]A9$-P" "='( $YE=F5R3&]A9&5D $YO1&QL4&QA=&9O Date: Tue, 23 Feb 2016 10:57:24 +0100 Subject: [PATCH 2/5] Adding the code to run SecondOrder example during setup --- Sources/install/run_example.m | 88 +++++++++++++++++++++++++++++++++++ Sources/setup_rapid.m | 3 +- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 Sources/install/run_example.m diff --git a/Sources/install/run_example.m b/Sources/install/run_example.m new file mode 100644 index 0000000..05e9934 --- /dev/null +++ b/Sources/install/run_example.m @@ -0,0 +1,88 @@ +%Script to run SecondOrder example during initialization + + +%% ==========Moving to the example folder========== + +str = '../../Examples/SecondOrder'; +cd(str); + +%% ==========Reference data settings========== + +%Output data +RaPIdObject.experimentData.pathToReferenceData = 'measuredDataO.mat'; %Data file name +RaPIdObject.experimentData.expressionReferenceTime = 'time'; %Time variable name +RaPIdObject.experimentData.expressionReferenceData = 'signal'; %Data variable name + +%Input data +RaPIdObject.experimentData.pathToInData = ''; + +%% ==========Experiment settings========== + +%General settings +RaPIdObject.experimentSettings.tf = 50; %Simulation length +RaPIdObject.experimentSettings.ts = 0.01; %Sampling time +RaPIdObject.experimentSettings.t_fitness_start = 4; %Start calculating fintess function after t_fintess_start +RaPIdObject.experimentSettings.timeOut = 2; %Seconds before simulation timeout +RaPIdObject.experimentSettings.integrationMethod = 'ode45'; %Solver selection +RaPIdObject.experimentSettings.solverMode = 'Simulink'; +RaPIdObject.experimentSettings.optimizationAlgorithm = 'pso'; %Selection of optimization algorithm +RaPIdObject.experimentSettings.maxIterations = 1; %Maximum number of estimation iterations +RaPIdObject.experimentSettings.verbose = 1; %Can trigger more data for debugging +RaPIdObject.experimentSettings.saveHist = 0; %Don't save history + +%Model related settings +RaPIdObject.experimentSettings.pathToSimulinkModel = 'variable_rafael.mdl'; %Simulink model file name +RaPIdObject.experimentSettings.pathToFMUModel = 'Rafael_0original_0estimated.fmu'; %FMU file name +RaPIdObject.experimentSettings.modelName = 'variable_rafael'; %Simulink model name +RaPIdObject.experimentSettings.blockName = 'variable_rafael/Rafael_original_estimated'; %FMU name +RaPIdObject.experimentSettings.scopeName = 'simout'; %Result sink name +RaPIdObject.experimentSettings.displayMode = 'Show'; + +%Estimation parameter settings +RaPIdObject.experimentSettings.p_0 = [0.3, 4.1, 1.7, 1.1]; %Initial parameter guess +RaPIdObject.experimentSettings.p_min = [0.1, 3.9, 1.5, 1.1]; %Minimum values of parameters +RaPIdObject.experimentSettings.p_max = [1, 4.2, 1.7, 1.5]; %Maximum values of parameters + +%Fitness function settings +RaPIdObject.experimentSettings.cost_type = 1; %Fitness function selection +RaPIdObject.experimentSettings.objective_weights = 1; %Weights of the output signals for fitness function + +%% ==========Optimization Algorithm settings========== + +switch RaPIdObject.experimentSettings.optimizationAlgorithm + case 'pso' + RaPIdObject.psoSettings.w = 0.25; %Particle inertia weight + RaPIdObject.psoSettings.self_coeff = 0.25; %Self recognition coefficient + RaPIdObject.psoSettings.social_coeff = 0.25; %Social coefficient + RaPIdObject.psoSettings.limit = 0.25; %Iteration limit + RaPIdObject.psoSettings.nRandMin = 8; %Minimum number of random particles + RaPIdObject.psoSettings.nb_particles = 8; %Number of particles + RaPIdObject.psoSettings.fitnessStopRatio = 1e-5; %Fitness stop ratio + RaPIdObject.psoSettings.kick_multiplier = 0.002; %Kick multiplier + RaPIdObject.psoSettings.method = 'PSO'; +end + +%% ==========FMU parameters, inputs and outputs========== + +RaPIdObject.parameterNames = {'transferFunction.b[1]','transferFunction.a[1]','transferFunction.a[2]','transferFunction.a[3]'}; +RaPIdObject.fmuInputNames = {}; +RaPIdObject.fmuOutputNames = {'y1'}; %Output variable names + +%% ==========Running the computation========== + +%Opening simulink model +open_system(RaPIdObject.experimentSettings.pathToSimulinkModel); %Opening the simulink model +open_system(strcat(RaPIdObject.experimentSettings.modelName,'/Scope')); %Opening the scope in the model to observe estimation process +pause(1); %Waiting one second for scope to initialize +%% + +%Starting the estimation process +[sol, hist] = rapid(RaPIdObject); +cd('../../Sources'); +if isempty(sol) + warning('Test example failed!'); +else + disp(strcat('Vector of estimated parameters is: ', mat2str(sol,3))); + disp('======= Test example succeeded! ======='); +end +clear RaPIdObject sol hist str dataMeasuredS diff --git a/Sources/setup_rapid.m b/Sources/setup_rapid.m index cd23b10..0c5ab03 100644 --- a/Sources/setup_rapid.m +++ b/Sources/setup_rapid.m @@ -31,6 +31,7 @@ % Check of RaPId dependencies run('.\install\check_installed') - +disp('======= Running the test example ======='); +run('.\install\run_example') % En of setup, run the GUI run_rapid_gui \ No newline at end of file From a660622282435a5da7559a9e9a400a7b007e62cd Mon Sep 17 00:00:00 2001 From: Maxime Baudette Date: Tue, 23 Feb 2016 14:33:43 +0100 Subject: [PATCH 3/5] Example run at installation Added some try/catch goodies #12 Second Order example switched to relative path Closes #20 #29 --- Examples/SecondOrder/run_example.m | 3 ++- Sources/setup_rapid.m | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Examples/SecondOrder/run_example.m b/Examples/SecondOrder/run_example.m index fc0d55a..b8b2e67 100644 --- a/Examples/SecondOrder/run_example.m +++ b/Examples/SecondOrder/run_example.m @@ -1,6 +1,7 @@ %% ==========Moving to the example folder========== -str = 'X:/dev/iTesla_RaPId/iTesla_RaPId/Examples/SecondOrder'; + +str = '../../Examples/SecondOrder'; cd(str); %% ==========Reference data settings========== diff --git a/Sources/setup_rapid.m b/Sources/setup_rapid.m index 0c5ab03..9b50cdc 100644 --- a/Sources/setup_rapid.m +++ b/Sources/setup_rapid.m @@ -32,6 +32,12 @@ % Check of RaPId dependencies run('.\install\check_installed') disp('======= Running the test example ======='); -run('.\install\run_example') +try + run('.\install\run_example') +catch msg_error + cd('../../Sources'); + disp(' /!\ Something went wrong in the example /!\'); + throwAsCaller(msg_error); +end % En of setup, run the GUI run_rapid_gui \ No newline at end of file From 7802aae03824641128524f6f0b27ee0602e00564 Mon Sep 17 00:00:00 2001 From: Jan Lavenius Date: Tue, 23 Feb 2016 22:21:02 +0100 Subject: [PATCH 4/5] * Updated container.mat in SecondOrder example * Updated run_example for SecondOrder example to use RaPIdObjects * Removed case sensitivity in Show simulation setting in rapid.m * Updated RaPIdClass.m to give default objects when using constructor with no arguments. * Moved code for default settings and auto-updating from RaPIdClass.m to initRapidObj.m & updateRapidObj.m. * RaPIdClass now have a special class folder, @RaPIdClass --- Examples/SecondOrder/container.mat | Bin 11896 -> 5249 bytes Examples/SecondOrder/run_example.m | 7 +- Sources/core/@RaPIdClass/RaPIdClass.m | 88 ++++++++++++ Sources/core/@RaPIdClass/initRapidObj.m | 37 +++++ Sources/core/@RaPIdClass/updateRapidObj.m | 80 +++++++++++ Sources/core/RaPIdClass.m | 162 ---------------------- Sources/core/functions/rapid.m | 4 +- 7 files changed, 213 insertions(+), 165 deletions(-) create mode 100644 Sources/core/@RaPIdClass/RaPIdClass.m create mode 100644 Sources/core/@RaPIdClass/initRapidObj.m create mode 100644 Sources/core/@RaPIdClass/updateRapidObj.m delete mode 100644 Sources/core/RaPIdClass.m diff --git a/Examples/SecondOrder/container.mat b/Examples/SecondOrder/container.mat index 32ab565d4f7f41b77215f878dc716d282e46b604..6ae1591245ce8d1f06379b1d6901e06922aabe3f 100644 GIT binary patch literal 5249 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 +% +% Copyright 2015 Luigi Vanfretti, Achour Amazouz, Maxime Baudette, +% Tetiana Bogodorova, Jan Lavenius, Tin Rabuzin, Giuseppe Laera, +% Francisco Gomez-Lopez +% +% The authors can be contacted by email: luigiv at kth dot se +% +% This file is part of Rapid Parameter Identification ("RaPId") . +% +% RaPId is free software: you can redistribute it and/or modify +% it under the terms of the GNU Lesser General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% RaPId is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU Lesser General Public License for more details. +% +% You should have received a copy of the GNU Lesser General Public License +% along with RaPId. If not, see . + +classdef RaPIdClass assign version=1 + s.version=double(~isempty(isprop(s, 'version'))); % 0 if really old, else 1 - old + obj = RaPIdClass(s); % update object + elseif s.version <1.41 % check if latest ver + obj = RaPIdClass(s); % update object + else + obj=s; % everything is up to date + end + catch err + disp(err) + disp(struct2table(err.stack)) + end + end + + end + + methods + function obj = RaPIdClass(varargin) %Constructor + if nargin == 0 %Create a new object of the latest version + try + obj=initRapidObj(obj); + catch + %NOP, will still give a an object + end + elseif isa(varargin{1},'RaPIdClass') && varargin{1}.version==1.41 + %NOP, up to date + else % Old version, try to update + obj=RaPIdClass(); % New object + obj=obj.updateRapidObj(varargin{1}); % update old object + end + end + function obj = saveobj(obj) + + end + end +end \ No newline at end of file diff --git a/Sources/core/@RaPIdClass/initRapidObj.m b/Sources/core/@RaPIdClass/initRapidObj.m new file mode 100644 index 0000000..ab60d26 --- /dev/null +++ b/Sources/core/@RaPIdClass/initRapidObj.m @@ -0,0 +1,37 @@ +function obj = initRapidObj(obj) +% INITRAPIDOBJ this function is meant to create a default rapidobject +% Detailed explanation goes here +obj.experimentSettings=struct('tf',1,'ts',0.1,'p_min',[],'p_max',[],'p_0',[],... + 'cost_type',1,'objective_weights',1,'t_fitness_start',0,... + 'integrationMethod','ode45','maxIterations',100,'solverMode','Simulink',... + 'pathToSimulinkModel','','modelName','','blockName','','scopeName','simout',... + 'verbose',1,'displayMode','hide','saveHist',0,'timeOut',2,... + 'pathToFmuModel','','outputPostProcessing','','optimizationAlgorithm','pso',... + 'pathToFMUModel',''); +obj.experimentData = struct('pathToInData','','expressionInData','',... + 'expressionInDataTime','','referenceOutdata',[],'referenceTime',[],... + 'pathToReferenceData','','expressionReferenceTime','','expressionReferenceData',''); +obj.psoSettings=struct('w',0.25,'self_coeff',0.25,'social_coeff',0.25,... + 'limit',0.2500,'nRandMin',8,'nb_particles',8,'fitnessStopRatio',1e-5,... + 'kick_multiplier',0.002,'w_min', 0.01, 'w_max',1,'method','PSO'); +obj.gaSettings=struct('nbCromosomes',40,'nbCroossOver1',10,'nbCroossOver2',10,... + 'nbMutations',10,'nbReproduction',10,'limit',10,'fitnessStopRatio',1e-5,... + 'headSize1',5,'headSize2',5,'headSize3',3,'nbReinjection',5,'nRandMin',10, ... + 'p0s', [],'storeData',0); +obj.combiSettings=struct('firstMethod','pso','psoExtOptions','nm','secondMetod','nm'); +obj.naiveSettings=struct('tolerance1',1e-4,'tolerance2',1e-7,'iterations',1,'iterations2',1,'iterations3',1); +obj.knitroSettings=struct('path2Knitro','','knOptionsFile','', ... + 'knOptions','optimset(''Algorithm'',''active-set'',''TolFun'',1e-6,''TolX'',1e-6);'); +obj.nmSettings='optimset(''fminsearch'')'; +obj.cgSettings='optimset(optimset(''fminunc''),''FinDiffType'',''central'',''TolX'',1e-6,''LargeScale'',''off'')'; +obj.psoExtSettings='psoptimset'; +obj.gaExtSettings='gaoptimset'; +obj.fminconSettings='optimset(''FinDiffRelStep'',0.1)'; +obj.pfSettings=struct('nb_particles', 100,'prune_threshold', 0.1,'kernel_sigma',1); +obj.resultData=[]; +obj.fmuOutputNames={''}; +obj.parameterNames={''}; +obj.fmuInputNames={''}; +obj.version=1.41; +end + diff --git a/Sources/core/@RaPIdClass/updateRapidObj.m b/Sources/core/@RaPIdClass/updateRapidObj.m new file mode 100644 index 0000000..e2aaac2 --- /dev/null +++ b/Sources/core/@RaPIdClass/updateRapidObj.m @@ -0,0 +1,80 @@ +function obj = updateRapidObj(obj,oldThing) +% UPDATERAPIDOBJ this function will update old rapid-objects +% Detailed explanation goes here +objversion=oldThing.version; %old version number +%% This part takes care of updating old structs to rapidobjects +if isstruct(oldThing) && objversion==0 %to convert some very old mySettings-structs + obj.psoSettings = oldThing.pso_options; + obj.naiveSettings = oldThing.naive_options; + obj.gaSettings = oldThing.ga_options; + obj.combiSettings = oldThing.combiOptions; + obj.knitroSettings = oldThing.kn_options; + obj.nmSettings = oldThing.nmOptions; + obj.cgSettings = oldThing.cgOptions; + obj.psoExtSettings = oldThing.psoExtOptions; + obj.gaExtSettings = oldThing.gaExtOptions; + obj.fminconSettings = oldThing.fminconOptions; + obj.fmuOutputNames = oldThing.fmuOutData; + obj.parameterNames = oldThing.parameterNames; + obj.experimentSettings = struct('tf',oldThing.tf,'ts',oldThing.Ts,... + 'p_min',oldThing.p_min,'p_max',oldThing.p_max,'p_0',oldThing.p0,'cost_type',oldThing.cost,'objective_weights',oldThing.objective.vect,... + 't_fitness_start',oldThing.t0_fitness,'integrationMethod',oldThing.intMethod, ... + 'pathToSimulinkModel',oldThing.path2simulinkModel,'modelName',oldThing.modelName,'blockName',oldThing.blockName,... + 'scopeName',oldThing.scopeName,'verbose',oldThing.verbose,'saveHist', false,'optimizationAlgorithm',oldThing.methodName); + obj.experimentData = struct('referenceOutdata',oldThing.realData,'referenceTime',oldThing.realTime,'pathToReferenceData',oldThing.path2data,... + 'expressionReferenceTime',oldThing.dataT,'expressionReferenceData',oldThing.dataY); + obj.experimentSettings.outputPostProcessing=@(x)x; %function handle, do nothing as standard + if isfield(oldThing,'displayMode') + obj.experimentSettings.displayMode = oldThing.displayMode; + end + if isfield(oldThing,'nbMaxIterations') + obj.experimentSettings.maxIterations = oldThing.nbMaxIterations; + end + if isfield(oldThing, 'mode') + obj.experimentSettings.solverMode = oldThing.mode; + end + if isfield(oldThing,'fmuInputNames') + obj.fmuInputNames = oldThing.fmuInputNames; + end + if isfield(oldThing,'path2fmuModel') + obj.experimentSettings.pathToFmuModel = oldThing.path2fmuModel; + end + if isfield(oldThing,'pf_options') && ~isempty(oldThing.pf_options) + obj.pfSettings = oldThing.pf_options; + end + if isfield(oldThing,'inDat') + oldThing.inDat = struct('path',[],'signal',[],'time',[]); + end + obj.experimentData.pathToInData = oldThing.inDat.path; + obj.experimentData.expressionInData = oldThing.inDat.signal; + obj.experimentData.expressionInDataTime = oldThing.inDat.time; + objversion=1; % ver should now be according to 1 +end +%% Copy settings to new object +names=properties(obj); +ii=find(~strcmp(names,'version')); +for k=1:length(ii) + obj.(names{ii(k)})=oldThing.(names{ii(k)}); +end +%% We can now be sure that the object has the right properties copied, time to update the last changes to make objects up to date to 1.41 +if objversion<1.4 %Make sure everythings is up to date to 1.4 + obj.experimentSettings.timeOut=2; + objversion=1.4; % increment version number +end + + if objversion <1.41 % Make sure everythings is up to date to 1.41 + oldnames={'alpha1','alpha2','alpha3'}; + newnames={'w','self_coeff','social_coeff'}; + for k=1:3 %renaming fields in psoSettings + obj.psoSettings.(newnames{k})=obj.psoSettings.(oldnames{k}); + + end + obj.psoSettings=rmfield(obj.psoSettings,oldnames); + obj.psoSettings.method='PSO'; + obj.psoSettings.w_min=0.01; + obj.psoSettings.w_max=1; + objversion=1.41; % will be used when incrementing + end + % this will contain more things as changed to attributes + % are introduced. i.e if ==1.4 and so on. +end \ No newline at end of file diff --git a/Sources/core/RaPIdClass.m b/Sources/core/RaPIdClass.m deleted file mode 100644 index 217f48b..0000000 --- a/Sources/core/RaPIdClass.m +++ /dev/null @@ -1,162 +0,0 @@ -%% -% -% Copyright 2015 Luigi Vanfretti, Achour Amazouz, Maxime Baudette, -% Tetiana Bogodorova, Jan Lavenius, Tin Rabuzin, Giuseppe Laera, -% Francisco Gomez-Lopez -% -% The authors can be contacted by email: luigiv at kth dot se -% -% This file is part of Rapid Parameter Identification ("RaPId") . -% -% RaPId is free software: you can redistribute it and/or modify -% it under the terms of the GNU Lesser General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% RaPId is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU Lesser General Public License for more details. -% -% You should have received a copy of the GNU Lesser General Public License -% along with RaPId. If not, see . - -classdef RaPIdClass assign version=1 - s.version=double(~isempty(isprop(s, 'version'))); % 0 if really old, else 1 - old - obj = RaPIdClass(s); % update object - elseif s.version <1.41 % check if latest ver - obj = RaPIdClass(s); % update object - else - obj=s; % everything is up to date - end - catch err - disp(err) - end - end - end - methods - function obj = RaPIdClass(varargin) - if nargin > 0 && isstruct(varargin{1}) && varargin{1}.version==0 %to convert some old mySettings-structs, will be removed in future. - tmp=varargin{1}; - obj.psoSettings = tmp.pso_options; - obj.naiveSettings = tmp.naive_options; - obj.gaSettings = tmp.ga_options; - obj.combiSettings = tmp.combiOptions; - obj.knitroSettings = tmp.kn_options; - obj.nmSettings = tmp.nmOptions; - obj.cgSettings = tmp.cgOptions; - obj.psoExtSettings = tmp.psoExtOptions; - obj.gaExtSettings = tmp.gaExtOptions; - obj.fminconSettings = tmp.fminconOptions; - obj.fmuOutputNames = tmp.fmuOutData; - obj.parameterNames = tmp.parameterNames; - obj.experimentSettings = struct('tf',tmp.tf,'ts',tmp.Ts,... - 'p_min',tmp.p_min,'p_max',tmp.p_max,'p_0',tmp.p0,'cost_type',tmp.cost,'objective_weights',tmp.objective.vect,... - 't_fitness_start',tmp.t0_fitness,'integrationMethod',tmp.intMethod, ... - 'pathToSimulinkModel',tmp.path2simulinkModel,'modelName',tmp.modelName,'blockName',tmp.blockName,... - 'scopeName',tmp.scopeName,'verbose',tmp.verbose,'saveHist', false,'optimizationAlgorithm',tmp.methodName); - obj.experimentData = struct('referenceOutdata',tmp.realData,'referenceTime',tmp.realTime,'pathToReferenceData',tmp.path2data,... - 'expressionReferenceTime',tmp.dataT,'expressionReferenceData',tmp.dataY); - obj.experimentSettings.outputPostProcessing=@(x)x; %function handle, do nothing as standard - if isfield(tmp,'displayMode') - obj.experimentSettings.displayMode = tmp.displayMode; - else - obj.experimentSettings.displayMode = 'hide'; - end - if isfield(tmp,'nbMaxIterations') - obj.experimentSettings.maxIterations = tmp.nbMaxIterations; - else - obj.experimentSettings.maxIterations = 100; - end - if isfield(tmp, 'mode') - obj.experimentSettings.solverMode = tmp.mode; - else - obj.experimentSettings.solverMode = 'Simulink'; - end - if isfield(tmp,'fmuInputNames') - obj.fmuInputNames = tmp.fmuInputNames; - end - if isfield(tmp,'path2fmuModel') - obj.experimentSettings.pathToFmuModel = tmp.path2fmuModel; - end - if isfield(tmp,'pf_options') && ~isempty(tmp.pf_options) - obj.pfSettings = tmp.pf_options; - else - obj.pfSettings = struct('nb_particles', 100,'prune_threshold', 0.1,'kernel_sigma',1); - end - if ~isfield(tmp,'inDat') - tmp.inDat = struct('path',[],'signal',[],'time',[]); - end - obj.experimentData.pathToInData = tmp.inDat.path; - obj.experimentData.expressionInData = tmp.inDat.signal; - obj.experimentData.expressionInDataTime = tmp.inDat.time; - obj.version=1; % ver should be according to 1 - obj=RaPIdClass(obj); % update to latest version - end - if nargin > 0 && isstruct(varargin{1}) && varargin{1}.version==1 - tmp=varargin{1}; - names=properties(obj); - for k=1:length(names) - obj.(names{k})=tmp.(names{k}); - end - obj=RaPIdClass(obj); % update rapidobject to latest version - elseif nargin>0 && isa(varargin{1},'RaPIdClass') - obj=varargin{1}; - if obj.version<1.4 - obj.experimentSettings.timeOut=2; %default - obj.version=1.4; - end - if obj.version <1.41 - oldnames={'alpha1','alpha2','alpha3'}; - newnames={'w','self_coeff','social_coeff'}; - for k=1:3 %renaming fields in psoSettings - obj.psoSettings.(newnames{k})=obj.psoSettings.(oldnames{k}); - end - obj.psoSettings=rmfield(obj.psoSettings,oldnames); % remove old names - obj.psoSettings.method='PSO'; - obj.psoSettings.w_min=0.01; - obj.psoSettings.w_max=1; - obj.version=1.41; - end - % this should contain more things as changed to attributes - % are introduced. i.e if ==1.4 and so on. - end - - end - function obj = saveobj(obj) - - end - end -end - diff --git a/Sources/core/functions/rapid.m b/Sources/core/functions/rapid.m index 194d4d2..9b7c883 100644 --- a/Sources/core/functions/rapid.m +++ b/Sources/core/functions/rapid.m @@ -247,8 +247,8 @@ %% Cleaning up after the optimization switch RaPIdObject.experimentSettings.solverMode case 'Simulink' - switch RaPIdObject.experimentSettings.displayMode - case 'show' + switch lower(RaPIdObject.experimentSettings.displayMode) + case {'show'} % NOP otherwise close_system(RaPIdObject.experimentSettings.modelName,0) From 805309a7abd93a5f4d6e665ab921dbfa2518ece6 Mon Sep 17 00:00:00 2001 From: Maxime Baudette Date: Wed, 24 Feb 2016 10:59:19 +0100 Subject: [PATCH 5/5] Changing the command to get the path of the model to something more general --- Examples/SecondOrder/run_example.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/SecondOrder/run_example.m b/Examples/SecondOrder/run_example.m index c8983d4..4730692 100644 --- a/Examples/SecondOrder/run_example.m +++ b/Examples/SecondOrder/run_example.m @@ -1,7 +1,7 @@ %% ==========Moving to the example folder========== -str = '../../Examples/SecondOrder'; +[str,~,~] = fileparts(mfilename('fullpath')); oldFolder=cd(str); %% ==========Reference data settings==========