function varargout = IMPACT_Control(varargin)
% IMPACT_Control(varargin)
%   IMPACT_Control main GUI for IMPACT controller design

%   Project: IMPACT
%   Title of Code: IMPACT_Control
%   Relevant additional documentation:
%   Developer: Carlos Gonzalez
%   External Dependencies: NA
%
%   Disclaimer
%   CAUTION: It is strongly recommended that changes to this code
%   should be avoided without first consulting with authors.
%-----------


gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @IMPACT_Control_OpeningFcn, ...
    'gui_OutputFcn',  @IMPACT_Control_OutputFcn, ...
    'gui_LayoutFcn',  [] , ...
    'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
    warning on all;
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT GDTR_EDIT


function IMPACT_Control_OpeningFcn(hObject, eventdata, handles, varargin)
handles.iRelease = 1.0;

% start up picture
splash();


set(hObject,'Keypressfcn',@key_press);

handles.output = hObject;

% controller groups
handles.Design.Cs = struct('name', 'controller 1', 'ptoCont', 'tf(1)', 'floaterImpedance', 'tf(1)',...
    'sparImpedance', 'tf(1)', 'floaterFexc', 'tf(1)','sparFexc', 'tf(1)',...
    'floaterImpedanceX', 'tf(1)','sparImpedanceX', 'tf(1)', 'floaterFexcX', 'tf(1)','sparFexcX', 'tf(1)','ptoContX', 'tf(1)');


handles.projectFile = []; % project file
handles.projParamPath = []; % parameter path in the project file
handles.projParamFile = []; % parameter file in the project file
handles.wtConfig = 0; % initialise the selected model
handles.wtPath = 0; % initialise the selected model path
handles.allFilepath = []; % initialise the previous selected file folder path
handles.conData = tf(1); % initialise the controller data from the sisotool
handles.upgradePlotsFcn = @upgrade_pushbutton9_Callback;
handles.model = 1;
handles.iWecType = 0;
handles.iControlType = 1;
handles.iAdaptiveDamping = 0;
handles.iPtoPositionConstraint = 0;
handles.additionalParam = '';
handles.gainPLD = 0;

% EKF paramters
EKF.sampleTime = 0.01;
EKF.procCovariance1 = 1e6;
EKF.procCovariance2 = 1e6;
EKF.procCovariance3 = 1e-11;
EKF.measCovariance = 1e10;
EKF.upperFreq = 2;
EKF.procCovariance1_0 = 1e5;
EKF.procCovariance2_0 = 1e5;
EKF.procCovariance3_0 = 0.1;
EKF.freq_0 = 0.5;
EKF.Fexc_0 = 1e5;
handles.Design.EKFFloater = EKF;
handles.Design.EKFSpar = EKF;

movegui( gcf, 'center' );% move the gui to the center

drawLoop;

addIMPACTIcon(hObject);
% change the font name
set(gcf, 'DefaultTextFontName', 'Verdana');

function varargout = IMPACT_Control_OutputFcn(hObject, ~, handles)
varargout{1} = handles;


% --- Executes during object creation, after setting all properties.
function axes1_CreateFcn(hObject, eventdata, handles)



function mode = get_mode_type( handles, hObject )
% function to determine which mode (Type of Analysis)-------

% hObject is the handle of the selected radio button
if ( get( handles.radiobutton_CL, 'Value' ) == 1 )
    mode = 'cl'; % mode = close loop
elseif ( get( handles.radiobutton_OL, 'Value' ) == 1 )
    mode = 'ol'; % mode = open loop
else set( hObject, 'Value', 1); % in case of no radio button is selected
    mode = get_mode_type( handles, hObject);
end


function x = xmodel(mode, handles, type)
% function to calculate model  ----------

if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

[var1,var2] = get_var_names(handles);

switch (var1)
    case 'u1'
        strInput = 'ol';
    case 'u2'
        strInput = 'olx';
    case 'PTO Force Demand'
        strInput = 'plant';
end

switch (var2)
    case 'Relative velocity'
        stOutput = 'zModelPto';
        hFunc = @getVelocityModel;
        switch var1
            case {'u1','PTO Force Demand'}
                iDirection = 3;
            case 'u2'
                iDirection = 1;
        end
    case 'Floater velocity'
        stOutput = 'zModelFloater';
        hFunc = @getVelocityModel;
        iDirection = 3;
    case 'Spar velocity'
        stOutput = 'zModelSpar';
        hFunc = @getVelocityModel;
        iDirection = 3;
    case 'Relative velocity X'
        stOutput = 'zModelPto';
        hFunc = @getVelocityModel;
        iDirection = 1;
    case 'Floater velocity X'
        stOutput = 'zModelFloater';
        hFunc = @getVelocityModel;
        iDirection = 1;
    case 'Spar velocity X'
        stOutput = 'zModelSpar';
        hFunc = @getVelocityModel;
        iDirection = 1;
end


iModel = handles.model;
switch (iDirection)
    case 1
        zModel = handles.Design.Models(iModel).zModelX;
    case 3
        zModel = handles.Design.Models(iModel).zModel;
end
if isempty(zModel)
    x = [];
    errordlgMLS('There was an error reading the model file','Error');
    return
end


try
    x = feval(hFunc,(zModel.(stOutput)));
catch
    errordlgMLS('Incorrect output for current input');
    x = [];
    return;
end


s = tf('s');

try
    switch(strInput)
        case 'ol'
            C1 = eval(get(handles.edit_ptoCont,'string'));
        case 'olx'
            C1 = eval(get(handles.edit_ptoContX,'string'));
        otherwise
            C1 = tf(1);
    end
catch
    errordlgMLS( 'Incorrect form of PTO controller' );
    x=[];
    return;
end


%-------------------------------
%%
if strcmp( mode, 'ol' )
    cl = 0;
else
    cl = 1;
end
%------------------------

zTf = C1;

% Determine the range of frequency
arFreq = getFreqRange(handles, x);


% try
if strcmp( type, 'sisotool_analysis' )
    switch(strInput)
        case 'ol'
            C1 = eval(get(handles.edit_ptoCont,'string'));
        case 'olx'
            C1 = eval(get(handles.edit_ptoContX,'string'));
        otherwise
            C1 = tf(1);
    end
    % tf for sisotool analysis
    %     C1 = get (handles.edit_ptoCont,'string');%tf( 1 );
    return;
end
% end

arZ = magPhaseToComplex(x,arFreq);
if strcmpi(strInput,'plant')
    return;
else
    arTfComplex = complexTF(zTf,arFreq);
    arOL = transposeComplex(arTfComplex).*arZ;
    arCL = arOL./(1+cl*arOL);
    x = complexToMagPhase(arCL,arFreq);
end





function [y,err] = common_tf( handles, mode )
% common transfer function for bode, nyquist etc
err = 0;
if nargin < 2
    mode = get_mode_type( handles );
end

[var1,var2] = get_var_names(handles);

iModel = handles.model;
zModel = handles.Design.Models(iModel).zModel;

if isempty(zModel)
    y = [];
    err = 1;
    errordlgMLS('There was an error reading the model file','Error');
    return
end

switch (var1)
    case 'u1'
        strInput = 'u1';
    case 'PTO Force Demand'
        strInput = 'ptoDemand';
end

switch (var2)
    case 'Relative velocity'
        stOutput = 'zModelPto';
    case 'Floater velocity'
        stOutput = 'zModelFloater';
    case 'Spar velocity'
        stOutput = 'zModelSpar';
end

try
    y = zModel.(stOutput);
catch
    errordlgMLS('Incorrect output for current input');
    y = [];
    return
end


function freqPlots( name, tfFcn, handles, spe_name )
% simplifies the freq plot code

if isempty(tfFcn)
    return
end

fcn = textscan( name, '%s' );
fcn2 = fcn{1}{1};

h = findobj( 'Name', name );
if isempty( h )
    figureMLS( 'Name', name,'NumberTitle','off' );
else figure( h );
end
[ var1,var2 ] = get_var_names( handles );

len2 = sprintf('%s-%s', var1, var2);

h2 = findobj( 'tag', ['checkbox_' fcn2 '_hold']);
hAxes = get(h,'Children');
hPlots = [];
for iCont = 1:numel(hAxes)
    if strcmpi(get(hAxes(iCont), 'type'),'axes') && ~strcmpi(get(hAxes(iCont), 'tag'),'legend');
        hPlots = [hPlots,hAxes(iCont)];
    end
end
if (get(h2,'Value') == 1)
    hold on
    set(hPlots,'NextPlot','add');
    if ~isempty(h)
        hL = findobj( h, 'tag', 'legend' );
        % Error if legend doesnot exist
        if ~isempty(hL)
            len1 = get( hL(1), 'String' );
            len2 = horzcat( len1, len2 );
        end
    end
else
    hold off
    for iCont = 1:numel(hPlots)
        delete(get(hPlots(iCont),'Children'));
    end
    set(hPlots,'NextPlot','replace');
end

if nargin == 4
    fcn1 = spe_name;
else
    fcn1 = fcn2;
end

% get the lower and upper frequency
arFreq = getFreqRange(handles, tfFcn);
lowerFreq = arFreq(1);
upperFreq = arFreq(end);

% switch fcn1
% feval( fcn1, tfFcn, {lowerFreq, upperFreq}); % sensitivity, bode, nyquist, nichols
wecBode(tfFcn,'mp');

if ~isempty(h)
    hL = findobj( h, 'type', 'axes', 'tag', '' );
else
    hL = findobj( gcf, 'type', 'axes' );
end

% critical line for phase plot
hPhaseLine = findobj('type', 'line', 'tag', 'phaseLine');
delete(hPhaseLine)
%legend
legend( hL(1), len2 );
% plot line
if strcmp(fcn1, 'bode')
    yLim = get(hL(1), 'YLim');
    val = rem(yLim(1)-180, 360);
    yLim = yLim - val;
    ind = 0;
    while 1
        val = yLim(1) + 360*ind;
        if val > yLim(2)
            break;
        end
        set(gcf, 'CurrentAxes', hL(1));
        line([lowerFreq, upperFreq], [val, val], 'Color', 'k', 'tag', 'phaseLine');
        ind = ind + 1;
    end
end


function plotBode_Callback(hObject, eventdata, handles)

if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end
mode = get_mode_type( handles );
y = xmodel(mode,handles,[]);
freqPlots( 'bode plot', y, handles  );


function file_menu_Callback(hObject, eventdata, handles)
function load_menu_Callback(hObject, eventdata, handles)

function exit_menu_Callback(hObject, eventdata, handles)
close(ancestor(hObject, 'figure'));
button = questdlgMLS('Quit ?','Close All','Yes','No','default');
if strcmp(button,'Yes')
    close;
end


function axes1_ButtonDownFcn(hObject, eventdata, handles)


function edit_ptoCont_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Pto controller');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'ptoCont', handles);

strCell = get(handles.popupmenu_designView, 'String');
str = strCell{get(handles.popupmenu_designView, 'Value')};
if strcmp(str, 'C1')
    updateDesignView(C, handles);
end


function handles = updateCs(str, C, handles)
% str: string for controller fcn, e.g. tf(1)
% C: controller name, e.g. C1

strCell = get(handles.popupmenu_controller, 'String');
if ~iscell(strCell)
    strCell = {strCell};
end

% seleted controller group string
strG = strCell{get(handles.popupmenu_controller, 'Value')};

Cs = handles.Design.Cs;
if numel(Cs) < numel(strCell)
    errordlgMLS(sprintf('Controller group has been changed. You need to restart Dynamic design view.'));
    return;
end
for m = 1:numel(strCell)
    if strcmp(Cs(m).name, strG)
        break;
    end
end
Cs(m).(C) = str;

handles.Design.Cs = Cs;
guidata(handles.axes1, handles);


function updateDesignView(C, handles)
hFig = findobj('type', 'figure', 'tag', 'mlsDesignView');
if isempty(hFig)
    return;
end
handlesDV = guidata(hFig);
handlesDV.C = C;
guidata(handlesDV.hFig, handlesDV);
handles.DesignView.updatePlotFcn(handlesDV);

function edit_ptoCont_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function edit_ptoContX_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'C2');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'ptoContX', handles);

strCell = get(handles.popupmenu_designView, 'String');
str = strCell{get(handles.popupmenu_designView, 'Value')};
if strcmp(str, 'C2')
    updateDesignView(C, handles);
end


function edit_ptoContX_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function listbox1_Callback(hObject, eventdata, handles)
if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

iValue1 = get(hObject,'Value');
zValues1 = get(hObject,'String');
stOption1 = zValues1{iValue1};

iValue2 = get(handles.listbox2,'Value');
zValues2 = get(handles.listbox2,'String');
stOption2 = zValues2{iValue2};


if (strcmpi(stOption1,'u1') && strcmpi(stOption2,'Relative velocity')) || ...
        (strcmpi(stOption1,'u2') && strcmpi(stOption2,'Relative velocity'))
    set(handles.radiobutton_CL,'Enable','on');
else
    set(handles.radiobutton_CL,'Enable','off');
    set(handles.radiobutton_OL,'Value',1);
    set(handles.radiobutton_CL,'Value',0);
end

iValue = get(handles.listbox2,'Value');
if ~strcmpi(stOption1,'u1') && handles.iWecType==3
    stOutput = {'Relative velocity';'Floater velocity'; 'Spar velocity'};
elseif ~strcmpi(stOption1,'u1') && ~strcmpi(stOption1,'u2') && handles.iWecType==4
    stOutput = {'Relative velocity';'Floater velocity'; 'Spar velocity';'Relative velocity X';'Floater velocity X'; 'Spar velocity X'};
else
    stOutput = {'Relative velocity'};
end
set(handles.listbox2,'String',stOutput);
set(handles.listbox2,'Value',min(iValue,numel(stOutput)));
graph_com( handles );





%---------
function listbox1_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function listbox2_Callback( hObject, eventdata, handles )
if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

iValue1 = get(handles.listbox1,'Value');
zValues1 = get(handles.listbox1,'String');
stOption1 = zValues1{iValue1};

iValue2 = get(hObject,'Value');
zValues2 = get(hObject,'String');
stOption2 = zValues2{iValue2};


if strcmpi(stOption1,'u1') && strcmpi(stOption2,'Relative velocity')
    set(handles.radiobutton_CL,'Enable','on');
else
    set(handles.radiobutton_CL,'Enable','off');
    set(handles.radiobutton_OL,'Value',1);
    set(handles.radiobutton_CL,'Value',0);
end
graph_com( handles );



function listbox2_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function [ var1,var2 ] = get_var_names( handles )
% get the input and output

% the input and output are both strings
list_entries1 = get( handles.listbox1, 'String' );
list_entries2 = get( handles.listbox2, 'String' );
index_selected1 = get( handles.listbox1, 'Value' );
index_selected2 = get( handles.listbox2, 'Value' );
var1 = list_entries1{ index_selected1 };
var2 = list_entries2{ index_selected2 };



function mutual_exclude(off)
set(off,'Value',0);
%----------------
function radiobutton_CL_Callback( hObject, eventdata, handles )
mutual_exclude(handles.radiobutton_OL);
get_mode_type( handles, hObject );
graph_com( handles );



%------------------
function radiobutton_OL_Callback( hObject, eventdata, handles )
mutual_exclude(handles.radiobutton_CL);
get_mode_type( handles, hObject );
graph_com( handles );



% --------------------------------------------------------------------
function menu_model_Callback(hObject, eventdata, handles)


function menu_newParam_Callback(hObject, eventdata, handles)


function menu_viewModifyParam_Callback(hObject, eventdata, handles)

cd1 = cd;
% change the current path into previous one
if ~isempty( handles.allFilepath )
    cd( handles.allFilepath );
end

[ filename, filepath ] = uigetfile({ '*.m' },...
    'Select a IMPACT  model');
cd(cd1);

if filepath == 0
    return;
else
    iWecType = getWecType(fullfile(filepath,filename));
    if (iWecType~=-1)
        setParams(iWecType, filename, filepath, hObject,handles);
    else
        errordlgMLS(sprintf('WEC type cannot be find in file or it has a value different from 1, 2, 3 or 4.\nPlease check the line "iWecType = XX;" in the model file'));
    end
end



function menu_loadParamFile_Callback(hObject, eventdata, handles)
loadParamFileSetting(handles, [], [], []);


function success = loadParamFileSetting(handles, file, path, saveFullFile)
% load the *.m parameter file
% work for loadParamFile and Open project file

success = 0;

[handles, sucess] = loadMFile(handles, file, path, saveFullFile);

if ~sucess
    return
end


hFigure = findobj('tag', 'controller_design');

guidata(hFigure, handles);
listbox1_Callback(handles.listbox1, [], handles);
success = 1;


function edit_lowerFreq_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for frequency is not correct');
end

function edit_lowerFreq_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function edit_upperFreq_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for frequency is not correct');
end



function edit_upperFreq_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function menu_about_Callback(hObject, eventdata, handles)
About();

function menu_manual_Callback(hObject, eventdata, handles)
try
    open(fullfile(matlabroot,'toolbox','IMPACT','help','IMPACT Control Design Manual.pdf'));
catch
    errordlgMLS(sprintf('The manual cannot be opened.\nPlease make sure you have not changed the path %s',fullfile(matlabroot,'toolbox','IMPACT','help')));
end



function menu_openProj_Callback(hObject, eventdata, handles)
cd1 = cd;
% change the current path into previous one
if ~isempty( handles.allFilepath )
    cd( handles.allFilepath );
end

% get the file name and path for the project file
[ filename, filepath ] = uigetfile({ '*.m' },...
    'Select the project file');

cd( cd1 );

if isequal(filename, 0)
    return;
end
fullFile = fullfile(filepath, filename);
handles.allFilepath = filepath;


success = checkPrjFile(fullFile, 'caller');
if success==-1
    return
end

hAll = [handles.popupmenu_model, handles.popupmenu_controller];
set(hAll, 'String', {''}, 'Value', 1);
handles.Design = [];
handles.Design.Cs = struct('name', '', 'ptoCont', '', 'floaterImpedance', '',...
    'sparImpedance', '', 'floaterFexc', '','sparFexc','','floaterImpedanceX', '',...
    'sparImpedanceX', '', 'floaterFexcX', '','sparFexcX','', 'ptoContX', '');

% loading parameter files
for m=1:numel(file)
    str = file{m};
    success = loadParamFileSetting(guidata(handles.edit_ptoCont), file{m}, path{m}, fullfile(path{m}, file{m}));
    if ~success
        return
    end
end

handles = guidata(handles.edit_ptoCont);
str = get(handles.popupmenu_controller, 'String');
if ~iscell(str)
    str = {str};
end
str(cellfun('isempty', str)) = [];
ind = numel(str);
for m=1:numel(Data)
    data = fieldnames(Data(m));
    for n=1:numel(data)
        switch data{n}
            case 'name'
                handles.Design.Cs(m+ind).name = Data(m).name;
            case 'ptoCont'
                handles.Design.Cs(m+ind).ptoCont = Data(m).ptoCont;
            case 'floaterImpedance'
                handles.Design.Cs(m+ind).floaterImpedance = Data(m).floaterImpedance;
            case 'sparImpedance'
                handles.Design.Cs(m+ind).sparImpedance = Data(m).sparImpedance;
            case 'floaterFexc'
                handles.Design.Cs(m+ind).floaterFexc = Data(m).floaterFexc;
            case 'sparFexc'
                handles.Design.Cs(m+ind).sparFexc = Data(m).sparFexc;
            case 'floaterImpedanceX'
                handles.Design.Cs(m+ind).floaterImpedanceX = Data(m).floaterImpedanceX;
            case 'sparImpedanceX'
                handles.Design.Cs(m+ind).sparImpedanceX = Data(m).sparImpedanceX;
            case 'floaterFexcX'
                handles.Design.Cs(m+ind).floaterFexcX = Data(m).floaterFexcX;
            case 'sparFexcX'
                handles.Design.Cs(m+ind).sparFexcX = Data(m).sparFexcX;
            case 'ptoContX'
                handles.Design.Cs(m+ind).ptoContX = Data(m).ptoContX;
        end
    end
    str = [str; Data(m).name];
end

for m=1:numel(Data(m))
    data = fieldnames(handles.Design.Cs(m));
    for n =1:numel(data)
        switch data{n}
            case 'ptoCont'
                if isempty(handles.Design.Cs(m+ind).ptoCont)
                    handles.Design.Cs(m+ind).ptoCont = 'tf(1)';
                end
            case 'floaterImpedance'
                if isempty(handles.Design.Cs(m+ind).floaterImpedance)
                    handles.Design.Cs(m+ind).floaterImpedance = 'tf(1)';
                end
            case 'sparImpedance'
                if isempty(handles.Design.Cs(m+ind).sparImpedance)
                    handles.Design.Cs(m+ind).sparImpedance = 'tf(1)';
                end
            case 'floaterFexc'
                if isempty(handles.Design.Cs(m+ind).floaterFexc)
                    handles.Design.Cs(m+ind).floaterFexc = 'tf(1)';
                end
            case 'sparFexc'
                if isempty(handles.Design.Cs(m+ind).sparFexc)
                    handles.Design.Cs(m+ind).sparFexc = 'tf(1)';
                end
            case 'floaterImpedanceX'
                if isempty(handles.Design.Cs(m+ind).floaterImpedanceX)
                    handles.Design.Cs(m+ind).floaterImpedanceX = 'tf(1)';
                end
            case 'sparImpedanceX'
                if isempty(handles.Design.Cs(m+ind).sparImpedanceX)
                    handles.Design.Cs(m+ind).sparImpedanceX = 'tf(1)';
                end
            case 'floaterFexcX'
                if isempty(handles.Design.Cs(m+ind).floaterFexcX)
                    handles.Design.Cs(m+ind).floaterFexcX = 'tf(1)';
                end
            case 'sparFexcX'
                if isempty(handles.Design.Cs(m+ind).sparFexcX)
                    handles.Design.Cs(m+ind).sparFexcX = 'tf(1)';
                end
            case 'ptoContX'
                if isempty(handles.Design.Cs(m+ind).ptoContX)
                    handles.Design.Cs(m+ind).ptoContX = 'tf(1)';
                end
        end
    end
end

EKFFields = {'freq_0','Fexc_0','sampleTime','procCovariance1','procCovariance2','procCovariance3','procCovariance1_0','procCovariance2_0','procCovariance3_0','measCovariance','upperFreq'};
projEKFFields = {'rInitialFrequencyEkf','rInitialPhi0','rTimeStep','arProcessNoiseCovariance_1','arProcessNoiseCovariance_2','arProcessNoiseCovariance_3',...
    'arProcessNoiseCovariance_1_0','arProcessNoiseCovariance_2_0','arProcessNoiseCovariance_3_0','arMeasurementNoiseCovariance','rUpperFreq'};

EKF.sampleTime = 0.01;
EKF.procCovariance1 = 1e6;
EKF.procCovariance2 = 1e6;
EKF.procCovariance3 = 1e-11;
EKF.measCovariance = 1e10;
EKF.upperFreq = 2;
EKF.procCovariance1_0 = 1e5;
EKF.procCovariance2_0 = 1e5;
EKF.procCovariance3_0 = 0.1;
EKF.freq_0 = 0.5;
EKF.Fexc_0 = 1e5;

% Assign floater values
bMissing = 0;
if exist('EKFFloater','var')
    for iCont = 1:numel(EKFFields)
        iError = 0;
        if isfield(EKFFloater,projEKFFields{iCont})
            val = EKFFloater.(projEKFFields{iCont});
            if isFiniteNum(val, [0, inf; 0, 0]);
                EKFFloaterGUI.(EKFFields{iCont})= val;
            else
                iError = 1;
                bMissing = 1;
            end
        else
            iError = 1;
            bMissing = 1;
        end
        if iError
            EKFFloaterGUI.(EKFFields{iCont})= EKF.(EKFFields{iCont});
        end
    end
else
    EKFFloaterGUI = EKF;
end

% Assign spar values
if exist('EKFFloater','var')
    for iCont = 1:numel(EKFFields)
        iError = 0;
        if isfield(EKFSpar,projEKFFields{iCont})
            val = EKFSpar.(projEKFFields{iCont});
            if isFiniteNum(val, [0, inf; 0, 0]);
                EKFSparGUI.(EKFFields{iCont})= val;
            else
                iError = 1;
                bMissing = 1;
            end
        else
            iError = 1;
            bMissing = 1;
        end
        if iError
            EKFSparGUI.(EKFFields{iCont})= EKF.(EKFFields{iCont});
        end
    end
else
    EKFSparGUI = EKF;
end

if bMissing
    warndlgMLS('Some values of the Extended Kalman Filter were missing or not correct. Default values have been applied');
end
handles.Design.EKFFloater = EKFFloaterGUI;
handles.Design.EKFSpar = EKFSparGUI;

if ~exist('stAddParamsFile','var')
    stAddParamsFile = '';
end
handles.additionalParam = stAddParamsFile;
set(handles.edit_AdditionalParams,'String',stAddParamsFile,'TooltipString',stAddParamsFile);

controllerEdits = {'displacementLimit','maxForcePto','minForcePto','outputSampleTime','startRampTime','rampTimeLength','gainPLD','gainPLDX','displacementLimitX'};
controllerNames = {'rDisplacementLimit','rMaxForcePto','rMinForcePto','rOutputSampleTime','rStartRampTime','rRampTimeLength','rPassiveDampingGain','rPassiveDampingGainX','rDisplacementLimit'};
for iCont=1:numel(controllerEdits)
    if exist(controllerNames{iCont},'var')
        eval(sprintf('set(handles.edit_%s,''String'',%g);',controllerEdits{iCont},eval(controllerNames{iCont})));
    else
        warndlgMLS('Some values of thecontroller were missing or not correct');
    end
end

iError = 0;
if isint(iControlType) && iControlType>0 && iControlType<4
    set(handles.popupmenu_controlType,'Value',iControlType);
    handles.iControlType = iControlType;
else
    iError = 1;
end

if isint(iAdaptiveDamping) && iAdaptiveDamping==0 || iAdaptiveDamping==1
    handles.adaptiveDamping = iAdaptiveDamping;
else
    iError = 1;
end

if isint(iPtoPositionConstraint) && iPtoPositionConstraint==0 || iPtoPositionConstraint==1
    set(handles.radiobutton_ptoPositionConstraint,'Value',iPtoPositionConstraint);
    handles.iPtoPositionConstraint = iPtoPositionConstraint;
else
    iError = 1;
end

if iError
    warndlgMLS('One or more controller parameters have not been read correctly');
end
%%
if ~isempty(str)
    set(handles.popupmenu_controller, 'String', str, 'Value', 1);
    popupmenu_controller_Callback(handles.popupmenu_controller, [], handles);
end

handles.projectFile = fullFile;
%%
% handles = guidata(handles.axes1);
guidata(hObject, handles);

function success = checkPrjFile(fullFile, mode)
try
    success = checkPrjFile2(fullFile, mode);
    if success==-1
        return
    end
    if nargin>1
        switch mode
            case 'caller'
                varCell = {'iRelease', 'file', 'path', 'Data','EKFFloater','EKFSpar','iControlType','iAdaptiveDamping','iPtoPositionConstraint','rDisplacementLimit','rDisplacementLimitX',...
                    'rMaxForcePto','rMinForcePto','rOutputSampleTime','rStartRampTime','rRampTimeLength','rPassiveDampingGain','rPassiveDampingGainX','stAddParamsFile'};
                varCellVar = {'iRelease', 'file', 'path', 'Data','EKFFloater','EKFSpar','iControlType','iAdaptiveDamping','iPtoPositionConstraint','rDisplacementLimit','rDisplacementLimitX',...
                    'rMaxForcePto','rMinForcePto','rOutputSampleTime','rStartRampTime','rRampTimeLength','rPassiveDampingGain','rPassiveDampingGainX','stAddParamsFile'};
                
                for m=1:numel(varCell)
                    str = varCell{m};
                    strVar = varCellVar{m};
                    if exist(str,'var')
                        assignin('caller', strVar, eval(str));
                    end
                end
        end
    end
catch
    errordlgMLS(sprintf('Error occured when reading file %s', fullFile));
    success = -1;
    return
end

function success = checkPrjFile2(fullFile, mode)
success = -1;
if ~exist(fullFile,'file')
    errordlgMLS(sprintf('%s does not exist', fullFile));
    return;
end

try
    readFile(fullFile);
catch
    errordlgMLS(sprintf('%s cannot be run', fullFile));
    return
end


success = 1;

% project release
if ~exist('iRelease', 'var')
    iRelease = 1.0;
end

% check if all variables exist
switch iRelease
    case 1
        varCell = {'iRelease', 'file', 'path', 'Data','EKFFloater','EKFSpar',...
            'iControlType','iAdaptiveDamping','iPtoPositionConstraint','rDisplacementLimit','rDisplacementLimitX',...
            'rMaxForcePto','rMinForcePto','rOutputSampleTime','rStartRampTime','rRampTimeLength','rPassiveDampingGain','rPassiveDampingGainX','stAddParamsFile'};
end
stErrorMsg = '';
for m=1:numel(varCell)
    if ~exist(varCell{m}, 'var')
        stErrorMsg = sprintf('%sVariable %s does not exist\n', stErrorMsg,varCell{m});
        success = 0;
    end
end
if ~isempty(stErrorMsg)
    errordlgMLS(stErrorMsg);
end

% check if parameter files exist
nFiles = numel(file);
for m=1:nFiles
    fullFile = fullfile(path{m}, file{m});
    if ~exist(fullFile, 'file')
        waitfor(errordlgMLS(sprintf('%s does not exist. Please choose a model to load', fullFile)));
        if strcmp( fullFile(end), 'm')
            [ filename, filepath ] = uigetfile({ '*.m' },...
                'Select the project file');
        end
        path{m} = filepath;
        file{m} = filename;
        
        if isequal(filename, 0)
            success = -1;
            return;
        end
        fullFile = fullfile(path{m}, file{m});
        
    end
end

% check controllers
nCs = numel(Data);

for m=1:nCs
    data = fieldnames(Data(m));
    for n=1:numel(data)
        switch data{n}
            case 'ptoCont'
                if ~checkTf(Data(m).ptoCont, sprintf('Controller %d PTO controller', m))
                    success = 0;
                end
            case 'floaterImpedance'
                if ~checkTf(Data(m).floaterImpedance, sprintf('Controller %d Floater Impedance', m))
                    success = 0;
                end
            case 'sparImpedance'
                if ~checkTf(Data(m).sparImpedance, sprintf('Controller %d Spar Impedance', m))
                    success = 0;
                end
            case 'floaterFexc'
                if ~checkTf(Data(m).floaterFexc, sprintf('Controller %d Floater Fexc', m))
                    success = 0;
                end
            case 'sparFexc'
                if ~checkTf(Data(m).sparFexc, sprintf('Controller %d Spar Fexc', m))
                    success = 0;
                end
            case 'floaterImpedanceX'
                if ~checkTf(Data(m).floaterImpedanceX, sprintf('Controller %d Floater Impedance X', m))
                    success = 0;
                end
            case 'sparImpedanceX'
                if ~checkTf(Data(m).sparImpedanceX, sprintf('Controller %d Spar Impedance X', m))
                    success = 0;
                end
            case 'floaterFexcX'
                if ~checkTf(Data(m).floaterFexcX, sprintf('Controller %d Floater Fexc X', m))
                    success = 0;
                end
            case 'sparFexcX'
                if ~checkTf(Data(m).sparFexcX, sprintf('Controller %d Spar Fexc X', m))
                    success = 0;
                end
            case 'ptoContX'
                if ~checkTf(Data(m).ptoContX, sprintf('Controller %d PTO controller X', m))
                    success = 0;
                end
        end
    end
    
end
%%
if nargin>1
    switch mode
        case 'caller'
            for m=1:numel(varCell)
                str = varCell{m};
                if exist(str,'var')
                    assignin('caller', str, eval(str));
                end
            end
    end
end




function projectFile_cancel(hObject, eventdata)
close;

function menu_saveProj_Callback(hObject, eventdata, handles)

if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

if isempty(handles.projectFile)
    menu_saveAsProj_Callback(handles.menu_saveAsProj, [], handles);
else
    fullFile = handles.projectFile;
    handle_tempFig = figureMLS('visible', 'off', 'handleVisibility', 'off');
    guidata(handle_tempFig, 'Cancel');
    hWarn = wrndlgMLS(handle_tempFig, sprintf('Project file %s will be overwritten. Continue?', fullFile), 'invisible');
    uiwait(hWarn);
    button = guidata(handle_tempFig);
    close(handle_tempFig);
    if strcmp(button, 'OK')
        saveOrSaveAs(fullFile, handles);
    end
end

function menu_saveAsProj_Callback(hObject, eventdata, handles)

if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

%get the filename and pathname for 'save as'
[filename, pathname] = uiputfile( ...
    {'*.m'; '*.*'}, ...
    'Save as');
% save the parameter file
% If 'Cancel' was selected then return
if isequal([filename,pathname],[0,0])
    return
else
    fullFile = [pathname, filename];
    saveOrSaveAs(fullFile, handles);
end




function saveOrSaveAs(fullFile, handles, varargin)
% used to save the project file

% controllers
[fullFileFolder,fullFileName,fullFileExt] = fileparts(fullFile);
fullFileTmp = fullfile(fullFileFolder,[fullFileName,'.tmp']);
fid = fopen(fullFileTmp, 'w+');
if fid==-1
    errordlgMLS(sprintf('Cannot create %s', fullFile));
    return
end

% the first line of the project file
fprintf(fid, '%%%% Project file for IMPACT \n\n');

% toolbox release
fprintf(fid, '%% Release\n');
fprintf(fid, 'iRelease = %1.3f;\n\n',handles.iRelease);

%% all parameters
% parameter file
Models = handles.Design.Models;
nModels = numel(Models);
fprintf(fid, '%% Models files\n');

modelNoSaved = [];
for m=1:nModels
    if strcmp(Models(m).wtPath,fullfile(matlabroot,'toolbox','IMPACT','temp'))
        handle_tempFig = figureMLS('visible', 'off', 'handleVisibility', 'off');
        guidata(handle_tempFig, 'Cancel');
        hWarn = wrndlgMLS(handle_tempFig, sprintf('The model %s has not been saved. Do you want to save it?',Models(m).wtConfig), 'invisible');
        uiwait(hWarn);
        button = guidata(handle_tempFig);
        close(handle_tempFig);
        if strcmp(button, 'OK')
            [filename, pathname] = uiputfile( ...
                {'*.m'; '*.*'}, ...
                'Save as');
            if isequal([filename,pathname],[0,0])
                modelNoSaved = [modelNoSaved,m];
            else
                fullFile = [pathname, filename];
                copyfile(fullfile(Models(m).wtPath,Models(m).wtConfig),fullFile,'f');
                Models(m).wtPath = pathname;
                Models(m).wtConfig = filename;
                fprintf(fid, 'path{%d} = ''%s'';\n', m, Models(m).wtPath);
                fprintf(fid, 'file{%d} = ''%s'';\n\n', m, Models(m).wtConfig);
            end
        else
            modelNoSaved = [modelNoSaved,m];
        end
    else
        fprintf(fid, 'path{%d} = ''%s'';\n', m, Models(m).wtPath);
        fprintf(fid, 'file{%d} = ''%s'';\n\n', m, Models(m).wtConfig);
    end
    fprintf(fid, '\n');
end

% controller values
strCs = get(handles.popupmenu_controller, 'String');
if ~iscell(strCs)
    strCs = {strCs};
end
strCs(cellfun('isempty', strCs)) = [];
nCs = numel(strCs);
Cs = handles.Design.Cs;
%factor = handles.StoredData.factor;
fprintf(fid, '%% Controller parameters\n');
% no controller groups
if isempty(strCs)
    fprintf(fid, 'Data = [];');
    fclose(fid);
    return;
end
for m=1:nCs
    fprintf(fid, 'Data(%d).name = ''%s'';\n', m, Cs(m).name);
    fprintf(fid, 'Data(%d).ptoCont = ''%s'';\n', m, Cs(m).ptoCont);
    fprintf(fid, 'Data(%d).floaterImpedance = ''%s'';\n', m, Cs(m).floaterImpedance);
    fprintf(fid, 'Data(%d).sparImpedance = ''%s'';\n', m, Cs(m).sparImpedance);
    fprintf(fid, 'Data(%d).floaterFexc = ''%s'';\n', m, Cs(m).floaterFexc);
    fprintf(fid, 'Data(%d).sparFexc = ''%s'';\n\n', m, Cs(m).sparFexc);
    
    fprintf(fid, 'Data(%d).floaterImpedanceX = ''%s'';\n', m, Cs(m).floaterImpedanceX);
    fprintf(fid, 'Data(%d).sparImpedanceX = ''%s'';\n', m, Cs(m).sparImpedanceX);
    fprintf(fid, 'Data(%d).floaterFexcX = ''%s'';\n', m, Cs(m).floaterFexcX);
    fprintf(fid, 'Data(%d).sparFexcX = ''%s'';\n\n', m, Cs(m).sparFexcX);
    fprintf(fid, 'Data(%d).ptoContX = ''%s'';\n\n', m, Cs(m).ptoContX);
end
fprintf(fid, '\n');

% Extended Kalman Filter Params
EKFFloater = handles.Design.EKFFloater;
fprintf(fid, 'EKFFloater.rInitialFrequencyEkf = %g;\n',EKFFloater.freq_0);
fprintf(fid, 'EKFFloater.rInitialPhi0 = %g;\n',EKFFloater.Fexc_0 );
fprintf(fid, 'EKFFloater.rTimeStep = %g;\n',EKFFloater.sampleTime);
fprintf(fid, 'EKFFloater.arProcessNoiseCovariance_1 = %g;\n',EKFFloater.procCovariance1 );
fprintf(fid, 'EKFFloater.arProcessNoiseCovariance_2 = %g;\n',EKFFloater.procCovariance2 );
fprintf(fid, 'EKFFloater.arProcessNoiseCovariance_3 = %g;\n',EKFFloater.procCovariance3 );
fprintf(fid, 'EKFFloater.arProcessNoiseCovariance_1_0 = %g;\n',EKFFloater.procCovariance1_0 );
fprintf(fid, 'EKFFloater.arProcessNoiseCovariance_2_0 = %g;\n',EKFFloater.procCovariance2_0 );
fprintf(fid, 'EKFFloater.arProcessNoiseCovariance_3_0 = %g;\n',EKFFloater.procCovariance3_0 );
fprintf(fid, 'EKFFloater.arMeasurementNoiseCovariance = %g;\n',EKFFloater.measCovariance );
fprintf(fid, 'EKFFloater.rUpperFreq = %g;\n',EKFFloater.upperFreq);

fprintf(fid, '\n');
EKFSpar = handles.Design.EKFSpar;
fprintf(fid, 'EKFSpar.rInitialFrequencyEkf = %g;\n',EKFSpar.freq_0);
fprintf(fid, 'EKFSpar.rInitialPhi0 = %g;\n',EKFSpar.Fexc_0 );
fprintf(fid, 'EKFSpar.rTimeStep = %g;\n',EKFSpar.sampleTime);
fprintf(fid, 'EKFSpar.arProcessNoiseCovariance_1 = %g;\n',EKFSpar.procCovariance1 );
fprintf(fid, 'EKFSpar.arProcessNoiseCovariance_2 = %g;\n',EKFSpar.procCovariance2 );
fprintf(fid, 'EKFSpar.arProcessNoiseCovariance_3 = %g;\n',EKFSpar.procCovariance3 );
fprintf(fid, 'EKFSpar.arProcessNoiseCovariance_1_0 = %g;\n',EKFSpar.procCovariance1_0 );
fprintf(fid, 'EKFSpar.arProcessNoiseCovariance_2_0 = %g;\n',EKFSpar.procCovariance2_0 );
fprintf(fid, 'EKFSpar.arProcessNoiseCovariance_3_0 = %g;\n',EKFSpar.procCovariance3_0 );
fprintf(fid, 'EKFSpar.arMeasurementNoiseCovariance = %g;\n',EKFSpar.measCovariance );
fprintf(fid, 'EKFSpar.rUpperFreq = %g;\n',EKFSpar.upperFreq);

fprintf(fid, '\n');
fprintf(fid, 'iControlType = %d;\n',handles.iControlType);
fprintf(fid, 'iAdaptiveDamping = %d;\n',handles.iAdaptiveDamping);
fprintf(fid, 'iPtoPositionConstraint  = %d;\n',handles.iPtoPositionConstraint);
value = getValue(handles.edit_displacementLimit);
if ~isFiniteNum(value,[0, inf;0 0])
    errordlgMLS('Incorrect value for PTO displacement. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rDisplacementLimit = %f;\n',value);
end

value = getValue(handles.edit_maxForcePto);
if ~isFiniteNum(value,[0, inf;0 0])
    errordlgMLS('Incorrect value for maximum PTO force. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rMaxForcePto = %f;\n',value);
end

value = getValue(handles.edit_minForcePto);
if ~isFiniteNum(value,[-inf, inf;0 0])
    errordlgMLS('Incorrect value for minimum PTO force. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rMinForcePto = %f;\n',value);
end

value = getValue(handles.edit_outputSampleTime);
if ~isFiniteNum(value,[0, inf;0 0])
    errordlgMLS('Incorrect value for output sample time. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rOutputSampleTime = %f;\n',value);
end

value = getValue(handles.edit_startRampTime);
if ~isFiniteNum(value,[0, inf;1 0])
    errordlgMLS('Incorrect value for start of ramp time. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rStartRampTime = %f;\n',value);
end

value = getValue(handles.edit_rampTimeLength);
if ~isFiniteNum(value,[0, inf;1 0])
    errordlgMLS('Incorrect value for duration of ramp time. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rRampTimeLength = %f;\n',value);
    
end

value = getValue(handles.edit_gainPLD);
if ~isFiniteNum(value,[-inf, 0;0 1])
    errordlgMLS('Incorrect value for the gain of the PLD. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rPassiveDampingGain = %f;\n',value);
end

value = getValue(handles.edit_gainPLDX);
if ~isFiniteNum(value,[-inf, 0;0 1])
    errordlgMLS('Incorrect value for the gain of the PLD X. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rPassiveDampingGainX = %f;\n',value);
end

value = getValue(handles.edit_displacementLimitX);
if ~isFiniteNum(value,[0, inf;1 0])
    errordlgMLS('Incorrect value for PTO displacement X. The project cannot be saved');
    fclose(fid);
    delete(fullFileTmp);
    return
else
    fprintf(fid, 'rDisplacementLimitX = %f;\n',value);
end

fprintf(fid, 'stAddParamsFile = ''%s'';\n',handles.additionalParam);

fclose(fid);
copyfile(fullFileTmp,fullFile,'f');
delete(fullFileTmp);
handles.projectFile = fullFile;
handles.Design.Models = Models;
guidata(handles.controller_design,handles);



function menu_disp_Callback(hObject, eventdata, handles)




function key_press(source,event)



function controller_design_CloseRequestFcn(hObject, evd, handles)
handle_tempFig = figureMLS('visible', 'off', 'handleVisibility', 'off');
guidata(handle_tempFig, 'Cancel');
hWarn = wrndlgMLS(handle_tempFig, sprintf('This will close all controller design tools. Continue?'), 'invisible');
uiwait(hWarn);
button = guidata(handle_tempFig);
close(handle_tempFig);
if strcmp(button, 'OK')
    hFig{1} = findall(0, 'type', 'figure', 'tag', 'controller_design');
    hFig{2} = findall(0, 'type', 'figure', 'tag', 'MLS_paramSetting');
    hFig{3} = findall(0, 'type', 'figure', 'tag', 'MLS_icon');
    % delete temporary files for model
    path = fullfile(matlabroot,'toolbox','IMPACT', 'temp');
    AllFile = dir(fullfile(path, 'tempModel*.m'));
    for m = 1:numel(AllFile)
        fullFile = fullfile(path, AllFile(m).name);
        try
            delete(fullFile);
        end
    end
    allFig = [hFig{:}];
    delete(allFig);
end



% --- Executes on selection change in popupmenu_model.
function popupmenu_model_Callback(hObject, eventdata, handles)

if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

val = get(hObject, 'value');

if ~exist(handles.Design.Models(val).saveFullFile,'file')
    errordlgMLS(sprintf('The file %s cannot be found',handles.Design.Models(val).saveFullFile),'Error');
    set(handles.popupmenu_model,'Value',handles.model);
    return;
end
% retrieve data
handles.wtConfig = handles.Design.Models(val).wtConfig;
handles.allFilepath = handles.Design.Models(val).allFilepath;
handles.wtPath = handles.Design.Models(val).wtPath;
handles.model = val;
handles.iWecType = handles.Design.Models(val).iWecType;

% file for Save&Load button
% may be different from loaded
handles.saveFullFile = handles.Design.Models(val).saveFullFile;

enableAsPerWEcType(handles);

guidata(hObject, handles);

radiobutton_CL_Callback(handles.radiobutton_CL,[],handles);
radiobutton_OL_Callback(handles.radiobutton_OL,[],handles);
handles.model = get(handles.popupmenu_model,'Value');
guidata(hObject, handles);


% --- Executes during object creation, after setting all properties.
function popupmenu_model_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in popupmenu_controller.
function popupmenu_controller_Callback(hObject, eventdata, handles)

nCs = get(hObject, 'Value');
str = get(hObject, 'String');
if ~iscell(str)
    str = {str};
end
if cellfun('isempty', str)
    return;
end

Cs = handles.Design.Cs;

% set controller strings
set(handles.edit_ptoCont, 'String', Cs(nCs).ptoCont);
set(handles.edit_floaterImpedance, 'String', Cs(nCs).floaterImpedance);
set(handles.edit_sparImpedance, 'String', Cs(nCs).sparImpedance);
set(handles.edit_floaterFexc, 'String', Cs(nCs).floaterFexc);
set(handles.edit_sparFexc, 'String', Cs(nCs).sparFexc);
set(handles.edit_floaterImpedanceX, 'String', Cs(nCs).floaterImpedanceX);
set(handles.edit_sparImpedanceX, 'String', Cs(nCs).sparImpedanceX);
set(handles.edit_floaterFexcX, 'String', Cs(nCs).floaterFexcX);
set(handles.edit_sparFexcX, 'String', Cs(nCs).sparFexcX);
set(handles.edit_ptoContX, 'String', Cs(nCs).ptoContX);

guidata(hObject, handles);


% --- Executes during object creation, after setting all properties.
function popupmenu_controller_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in pushbutton_addC.
function pushbutton_addC_Callback(hObject, eventdata, handles)
if handles.wtConfig == 0
    errordlgMLS('Please load an IMPACT model');
    return;
end
handle_tempFig = figureMLS('visible', 'off', 'handleVisibility', 'off');
guidata(handle_tempFig, 'Cancel');
hWarn = wrndlgMLS(handle_tempFig, sprintf('Do you want to populate the controller with the current controller values?'), 'invisible');
uiwait(hWarn);
button = guidata(handle_tempFig);
close(handle_tempFig);
addControllers(button);



% --- Executes on selection change in popupmenu_designView.
function con_siso = popupmenu_designView_Callback(hObject, eventdata, handles)

if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

% con_siso = get_var_popupmenu(handles);
con_sisostr = get( hObject, 'String' );
con_siso = con_sisostr { get( hObject, 'Value' ) };

% set the input & output in frequency analysis listboxes
outputStr = get(handles.listbox2, 'String');
inputStr = get(handles.listbox1, 'String');
n = [];
switch con_siso
    case 'C1'
        inputInd = find(strcmpi(inputStr,'u1'));
        if ~isempty(inputInd)
            set(handles.listbox1, 'Value', inputInd);
        else
            errordlgMLS('The input ''u1'' does not exist','Error');
            con_siso = [];
            return;
        end
        for m = 1: length(outputStr)
            if strcmp(outputStr{m}, 'Relative velocity')
                n = m;
            end
        end
    case 'C2'
        inputInd = find(strcmpi(inputStr,'u2'));
        if ~isempty(inputInd)
            set(handles.listbox1, 'Value', inputInd);
        else
            errordlgMLS('The input ''u2'' does not exist','Error');
            con_siso = [];
            return;
        end
        for m = 1: length(outputStr)
            if strcmp(outputStr{m}, 'Relative velocity')
                n = m;
            end
        end
end

if ~isempty(n)
    set(handles.listbox2, 'value', n);
else
    errordlgMLS('The required output for the current controller does not exist');
    con_siso = [];
    return
end

listbox1_Callback(handles.listbox1, [], handles);


% --- Executes during object creation, after setting all properties.
function popupmenu_designView_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in pushbutton_designView.
function pushbutton_designView_Callback(hObject, eventdata, handles)

if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

val = get(handles.radiobutton_OL, 'Value');
if ~val
    errordlgMLS('Only Open Loop can be used for controller design');
    return;
end

controller = popupmenu_designView_Callback(handles.popupmenu_designView, [], handles);
if isempty(controller)
    return;
end

zModel = xmodel( 'ol', handles, 'sisotool_analysis' );
if isempty(zModel)
    return
end


% controller value
s = tf('s');
switch controller
    case 'C1'
        [success, C] = checkTf(get(handles.edit_ptoCont, 'String'), 'ptoCont');
    case 'C2'
        [success, C] = checkTf(get(handles.edit_ptoContX, 'String'), 'ptoContX');
end
if ~success
    return;
end
fcnH = @updateCs;

% frequency range
arFreq = getFreqRange(handles,zModel);
Z = transposeComplex(magPhaseToComplex(zModel,arFreq));

wesSisotool(C, tf(0), Z,tf(1), 1, {arFreq}, handles, @updateCs);


% --------------------------------------------------------------------
function menu_modifyModel_Callback(hObject, eventdata, handles)

filename = handles.wtConfig;
filepath = handles.wtPath;

iWecType = handles.iWecType;
if (iWecType~=-1)
    setParams(iWecType, filename, filepath, hObject,handles);
else
    errordlgMLS(sprintf('WEC type cannot be find in file or it has a value different from 1, 2, 3 or 4.\nPlease check the line "iWecType = XX;" in the model file'));
end



function menu_slModel_Callback(hObject, eventdata, handles)

if isequal(handles.wtPath, 0) || isequal(handles.wtConfig,0)
    errordlgMLS( 'A model need to be loaded first');
    return;
end

model_path = fullfile(handles.wtPath,handles.wtConfig);
assignin('base','model_path',model_path);

switch handles.iWecType
    case 1
        stModelType = 'wec1.slx';
    case 2
        stModelType = 'wec2.slx';
    case 3
        stModelType = 'wec3.slx';
    case 4
        stModelType = 'wec4.slx';
end


fullFile = fullfile(matlabroot,'toolbox','IMPACT','simulink',stModelType);

if ~exist(fullFile, 'file')
    errordlgMLS(sprintf('Model %s cannot be found in the path',stModelType));
    return;
end


%Check if a temporary file already exist
pathTemp = fullfile(matlabroot,'toolbox','IMPACT', 'temp');
AllFile = dir(fullfile(pathTemp, 'wecModel*.slx'));
simModelno=1;
for n = 1:numel(AllFile)
    for m = 1:numel(AllFile)
        existTemp = strcmp(sprintf('wecModel%d.mdl',simModelno), AllFile(m).name);
        if existTemp
            break;
        end
    end
    if existTemp
        simModelno=simModelno+1;
    else
        break;
    end
end

newModel = fullfile(matlabroot,'toolbox','IMPACT','temp', sprintf('wecModel%d.slx',simModelno'));
success = copyfile(fullFile, newModel,'f');
if ~success
    errordlgMLS(sprintf('Controller template wecModell.mdl cannot be copied to %s. ', newModel));
    return;
end

open_system(newModel);

% --------------------------------------------------------------------
function menu_slModelOld_Callback(hObject, eventdata, handles)

if isequal(handles.wtPath, 0) || isequal(handles.wtConfig,0)
    errordlgMLS( 'A model need to be loaded first');
    return;
end

% get the Simulink model
[ filename, filepath ] = uigetfile({ '*.mdl','Models (*.mdl)'; ...
    '*.slx','Models (*.slx)';'*.*','All files'  },...
    'Select the Simulink model');

if isequal(filename, 0)
    return;
end
model_path = fullfile(handles.wtPath,handles.wtConfig);
assignin('base','model_path',model_path);
newModel = fullfile(filepath, filename);

open_system(newModel);

function contMenu_tfExport_Callback(hObject, eventdata, handles)

function contextMenu_Export_Callback(hObject, eventdata, handles)
if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

mode = get_mode_type( handles );
zModel = xmodel(mode,handles,[]);
[ var1,var2 ] = get_var_names( handles );

stModelName = [var1, '_', var2];
assignin('base',  matlab.lang.makeValidName(stModelName), zModel);


function ord = ordMag(x)
ord = 0;
if x>1
    while x>1
        x=x/10;
        ord=ord+1;
    end
    ord = ord-1;
else
    while x<1
        x=x*10;
        ord=ord-1;
    end
end


% --------------------------------------------------------------------
function menu_newType1Model_Callback(hObject, eventdata, handles)
paramInitial(1);


% --------------------------------------------------------------------
function menu_newType2Model_Callback(hObject, eventdata, handles)
paramInitial(2);


% --------------------------------------------------------------------
function menu_newType3Model_Callback(hObject, eventdata, handles)
paramInitial(3);

% --------------------------------------------------------------------
function menu_newType4Model_Callback(hObject, eventdata, handles)
paramInitial(4);


function edit_floaterImpedance_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Floater Impedance');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'floaterImpedance', handles);
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function edit_floaterImpedance_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_sparImpedance_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Spar Impedance');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'sparImpedance', handles);
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function edit_sparImpedance_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_floaterFexc_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Floater excitation');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'floaterFexc', handles);
guidata(hObject,handles);



% --- Executes during object creation, after setting all properties.
function edit_floaterFexc_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_sparFexc_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Spar excitation');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'sparFexc', handles);
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function edit_sparFexc_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in popupmenu_fitTfs.
function popupmenu_fitTfs_Callback(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function popupmenu_fitTfs_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in pushbutton_fitTf.
function pushbutton_fitTf_Callback(hObject, eventdata, handles)
if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end
iModel = handles.model;
zModel = handles.Design.Models(iModel);



iValue = get(handles.popupmenu_fitTfs,'Value');
iOrdNum = getValue(handles.edit_orderNum);
iOrdDen = getValue(handles.edit_orderDen);
if ~isFiniteNum(iOrdNum,[0,inf;1,0])
    errordlgMLS('The order of the numerator is incorrect')
    return;
end
if ~isFiniteNum(iOrdDen,[0,inf;1,0])
    errordlgMLS('The order of the denominator is incorrect')
    return;
end

if ~isint(iOrdNum)
    errordlgMLS('The order of the numerator has to be an integer number')
    return;
end
if ~isint(iOrdDen)
    errordlgMLS('The order of the denominator has to be an integer number')
    return;
end

if iOrdNum>iOrdDen
    errordlgMLS('The order of the numerator cannot be greater than the order of the denominator')
    return;
end
[Z, zModeli] = getFromModel(zModel,iValue);
% get the lower and upper frequency
lowerFreq = str2double(get(handles.edit_lowerFreq, 'String'));
upperFreq = str2double(get(handles.edit_upperFreq, 'String'));
arModelFreq = [lowerFreq:(upperFreq-lowerFreq)/400:upperFreq];


arZRealInterp = interp1(zModeli.arFreq,real(Z),arModelFreq,'linear','extrap');
arZImagInterp = interp1(zModeli.arFreq,imag(Z),arModelFreq,'linear','extrap');
h = waitbarMLS(0,'Calculating transfer function ...');
fittedTf = fitTf(arModelFreq,arZRealInterp,arZImagInterp,iOrdNum,iOrdDen,1);
waitbarMLS(1,h);
close(h);
[arZeros, arPoles, rGain]= zpkdata(fittedTf,'v');
stZeros = getCStr(arZeros);
stPoles = getCStr(arPoles);
stGain = getCStr(rGain);
stTf = sprintf('zpk(%s, %s, %s)', stZeros, stPoles, stGain);
set(handles.edit_fittedTf,'String',stTf);


function [Z,zModelTf] = getFromModel(zModel,iValue)
switch iValue
    case 1
        zModelTf = zModel.zModel.zModelFloater;
        Z = magPhaseToComplex(zModelTf);
    case 2
        zModelTf = zModel.zModel.zModelSpar;
        Z = magPhaseToComplex(zModelTf);
    case 3
        zModelTf = zModel.zModel.zModelFeFloater;
        Z = magPhaseToComplex(zModelTf);
    case 4
        zModelTf = zModel.zModel.zModelFeSpar;
        Z = magPhaseToComplex(zModelTf);
    case 5
        zModelTf = zModel.zModelX.zModelFloater;
        Z = magPhaseToComplex(zModelTf);
    case 6
        zModelTf = zModel.zModelX.zModelSpar;
        Z = magPhaseToComplex(zModelTf);
    case 7
        zModelTf = zModel.zModelX.zModelFeFloater;
        Z = magPhaseToComplex(zModelTf);
    case 8
        zModelTf = zModel.zModelX.zModelFeSpar;
        Z = magPhaseToComplex(zModelTf);
end


function edit_fittedTf_Callback(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function edit_fittedTf_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in pushbutton_comparePlot.
function pushbutton_comparePlot_Callback(hObject, eventdata, handles)
if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

iModel = handles.model;
zModel = handles.Design.Models(iModel);

iValue = get(handles.popupmenu_fitTfs,'Value');
[~, zModelTf] = getFromModel(zModel,iValue);
arModelFreq = getFreqRange(handles, zModelTf);
zModelFreq = getModelAtFreq(zModelTf,arModelFreq);
G.arFreq = arModelFreq;


stFittedTf = get(handles.edit_fittedTf,'String');
try
    s = tf('s');
    zFittedTf = eval(stFittedTf);
catch
    errordlgMLS('That is not a correct transfer function');
    return;
end

figure,
[iError, arAxes] = wecBode(zModelFreq,'mp');


if isTf(zFittedTf)
    G.tfModel = eval(stFittedTf);
else
    errordlgMLS('That is not a correct transfer function');
    return;
end
for iCont=1:numel(arAxes)
    hold(arAxes(iCont),'all');
end

wecBode(G,'tf');
legend('Exact','Approximation');


% --- Executes on button press in pushbutton_copyFittedTf.
function pushbutton_copyFittedTf_Callback(hObject, eventdata, handles)
iValue = get(handles.popupmenu_fitTfs,'Value');
switch iValue
    case 1
        hObj = handles.edit_floaterImpedance;
        hFunc = @edit_floaterImpedance_Callback;
    case 2
        hObj = handles.edit_sparImpedance;
        hFunc = @edit_sparImpedance_Callback;
    case 3
        hObj = handles.edit_floaterFexc;
        hFunc = @edit_floaterFexc_Callback;
    case 4
        hObj = handles.edit_sparFexc;
        hFunc = @edit_sparFexc_Callback;
    case 5
        hObj = handles.edit_floaterImpedanceX;
        hFunc = @edit_floaterImpedanceX_Callback;
    case 6
        hObj = handles.edit_sparImpedanceX;
        hFunc = @edit_sparImpedanceX_Callback;
    case 7
        hObj = handles.edit_floaterFexcX;
        hFunc = @edit_floaterFexcX_Callback;
    case 8
        hObj = handles.edit_sparFexcX;
        hFunc = @edit_sparFexcX_Callback;
end
stTf = get(handles.edit_fittedTf,'String');
[success, C] = checkTf(stTf);
if ~success
    errrordlgMLS('The transfer function is not correct and has not been copied');
    return;
end
set(hObj,'String',get(handles.edit_fittedTf,'String'));
feval(hFunc,hObj,[],handles);



% --- Executes on button press in pushbutton_copyFromFitted.
function pushbutton_copyFromFitted_Callback(hObject, eventdata, handles)
iValue = get(handles.popupmenu_fitTfs,'Value');
switch iValue
    case 1
        hObj = handles.edit_floaterImpedance;
    case 2
        hObj = handles.edit_sparImpedance;
    case 3
        hObj = handles.edit_floaterFexc;
    case 4
        hObj = handles.edit_sparFexc;
    case 5
        hObj = handles.edit_floaterImpedanceX;
    case 6
        hObj = handles.edit_sparImpedanceX;
    case 7
        hObj = handles.edit_floaterFexcX;
    case 8
        hObj = handles.edit_sparFexcX;
end
set(handles.edit_fittedTf,'String',get(hObj,'String'));


function value = getValue(hObject)
zVal = get(hObject,'String');
value = str2double(zVal);





function edit_orderNum_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for the order of the numerator is not correct');
end



% --- Executes during object creation, after setting all properties.
function edit_orderNum_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_orderDen_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for the order of the denominator is not correct');
end


% --- Executes during object creation, after setting all properties.
function edit_orderDen_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function str = getCStr(vec)
% return string for given vector

str = '';
for m = 1:numel(vec)
    if isreal(vec(m))
        str = sprintf('%s%g ', str, vec(m));
    else
        str = sprintf('%s%g%+gi ', str, real(vec(m)), imag(vec(m)));
    end
end

str = ['[', str, ']'];


function bTf = isTf(zTf)
if isa(zTf,'tf') || isa(zTf,'ss') || isa(zTf,'lti')
    bTf = 1;
else
    bTf = 0;
end

function [rLowerFreq,rUpperFreq] = getRangeFreq(handles)
rLowerFreq = str2double(get(handles.edit_lowerFreq, 'String'));
rUpperFreq = str2double(get(handles.edit_upperFreq, 'String'));

function enable(hndl)
set(hndl,'Enable','on');


function disable(hndl)
set(hndl,'Enable','off');




% --- Executes on button press in pushbutton_EKF.
function pushbutton_EKF_Callback(hObject, eventdata, handles)
EKFParam(handles.Design.EKFFloater,handles.controller_design,'Floater');


% --- Executes on button press in pushbutton_EKFX.
function pushbutton_EKFX_Callback(hObject, eventdata, handles)
EKFParam(handles.Design.EKFSpar,handles.controller_design,'Spar');


function arFreq = getFreqRange(handles, zModel)
% get the lower and upper frequency
lowerFreq = str2double(get(handles.edit_lowerFreq, 'String'));
upperFreq = str2double(get(handles.edit_upperFreq, 'String'));
upperModelFreq = max(zModel.arFreq);
lowerModelFreq = min(zModel.arFreq);

minFreq = max(lowerFreq,lowerModelFreq);
maxFreq = min(upperFreq,upperModelFreq);
[minVal, minInd] = min(abs(zModel.arFreq-minFreq));
[maxVal, maxInd] = min(abs(zModel.arFreq-maxFreq));
arFreq = zModel.arFreq(minInd:maxInd);
% arFreq = minFreq:(maxFreq-minFreq)/399:maxFreq;




function edit_outputSampleTime_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;0 0])
    errordlgMLS('The value for the output sample is not correct');
end


% --- Executes during object creation, after setting all properties.
function edit_outputSampleTime_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in popupmenu_controlType.
function popupmenu_controlType_Callback(hObject, ~, handles)
iVal = get(hObject,'Value');
switch iVal
    case 1
        handles.iControlType = 1;
    case 2
        handles.iControlType = 2;
        handles.iAdaptiveDamping = 1;
    case 3
        handles.iControlType = 2;
        handles.iAdaptiveDamping = 0;
end
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function popupmenu_controlType_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in radiobutton_ptoPositionConstraint.
function radiobutton_ptoPositionConstraint_Callback(hObject, eventdata, handles)
handles.iPtoPositionConstraint = get(hObject,'Value');
guidata(hObject,handles);



function edit_startRampTime_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for the start of the ramp is not correct');
end

% --- Executes during object creation, after setting all properties.
function edit_startRampTime_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_rampTimeLength_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for the duration of the ramp is not correct');
end

% --- Executes during object creation, after setting all properties.
function edit_rampTimeLength_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_displacementLimit_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;0 0])
    errordlgMLS('The value for maximum displacement is not correct');
end


% --- Executes during object creation, after setting all properties.
function edit_displacementLimit_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_maxForcePto_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for the maximum force of the PTO is not correct');
end


% --- Executes during object creation, after setting all properties.
function edit_maxForcePto_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_minForcePto_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[-inf inf;0 0])
    errordlgMLS('The value for the minimum force of the PTO is not correct');
end

% --- Executes during object creation, after setting all properties.
function edit_minForcePto_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function checkbox_bode_hold_Callback(hObject, eventdata, handles)
if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end


% --- Executes on button press in pushbutton_simController.
function pushbutton_simController_Callback(hObject, eventdata, handles)
if handles.wtConfig == 0
    errordlgMLS('Please load a model first');
    return;
end

h = waitbarMLS(0,'Passing parameters to MATLAB workspace ...');

% parameter file
iModelNum = handles.model;
Model = handles.Design.Models(iModelNum);

stParameterPath = fullfile(Model.wtPath,Model.wtConfig);
% stH5FilePath <- read from model file

% Create the model
zModelSimple = Model.zModel;

% Adaptive law
arAdaptiveLawData = 1/2*zModelSimple.zModelPto.arFreq.*...
    zModelSimple.zModelPto.arMagnitude./...
    cos(zModelSimple.zModelPto.arPhase*pi/180+pi/2);
arFrequencyRange = zModelSimple.zModelPto.arFreq;

if updateWaitBar(h,0.2) return; end;
% Controller
s = tf('s');
iController = get(handles.popupmenu_controller, 'Value');
zController = handles.Design.Cs(iController);
tfController = eval(zController.ptoCont);

tfImpedanceFloater = eval(zController.floaterImpedance);
tfImpedanceSpar = eval(zController.sparImpedance);

if updateWaitBar(h,0.4) return; end;


iControlType = handles.iControlType;
iAdaptiveDamping = handles.iAdaptiveDamping;
iPtoPositionConstraint  = handles.iPtoPositionConstraint;

if updateWaitBar(h,0.5) return; end;
% Pto Constraints
iPtoPositionConstraint = handles.iPtoPositionConstraint;

rDisplacementLimit = getValue(handles.edit_displacementLimit);
if ~isFiniteNum(rDisplacementLimit,[0, inf;0 0])
    errordlgMLS('Incorrect value for PTO displacement');
    return
end

rMaxForcePto = getValue(handles.edit_maxForcePto);
if ~isFiniteNum(rMaxForcePto,[0, inf;0 0])
    errordlgMLS('Incorrect value for maximum PTO force');
    return
end

rMinForcePto = getValue(handles.edit_minForcePto);
if ~isFiniteNum(rMinForcePto,[-inf, inf;0 0])
    errordlgMLS('Incorrect value for minimum PTO force');
    return;
end

rOutputSampleTime = getValue(handles.edit_outputSampleTime);
if ~isFiniteNum(rOutputSampleTime,[0, inf;0 0])
    errordlgMLS('Incorrect value for output sample time');
    return
end

% Ramp the controller
rStartRampTime = getValue(handles.edit_startRampTime);
if ~isFiniteNum(rStartRampTime,[0, inf;1 0])
    errordlgMLS('Incorrect value for start of ramp time');
    return
end

rRampTimeLength = getValue(handles.edit_rampTimeLength);
if ~isFiniteNum(rRampTimeLength,[0, inf;1 0])
    errordlgMLS('Incorrect value for duration of ramp time');
    return
end

% Ramp for when the OVT controller is passed
arControllerRampGain = [0,0,1,1];
arControllerRampTime = [0 rStartRampTime rStartRampTime+rRampTimeLength 8000];

if updateWaitBar(h,0.7) return; end;
iSensorNoise = 0;

% Read in BEM data
% Set the parameters for the model
readFile(stParameterPath);
% Set path
zH5Data = getParamH5(stH5File);

if iWecType ==4
    zModelSimpleX = Model.zModelX;
    % Adaptive law
    arAdaptiveLawDataX = 1/2*zModelSimpleX.zModelPto.arFreq.*...
        zModelSimpleX.zModelPto.arMagnitude./...
        cos(zModelSimpleX.zModelPto.arPhase*pi/180+pi/2);
    arImpedanceX = 1./zModelSimpleX.zModelPto.arMagnitude./zModelSimpleX.zModelPto.arFreq;
    arFrequencyX = zModelSimpleX.zModelPto.arFreq;
    
    rDisplacementLimitX = getValue(handles.edit_displacementLimitX);
    if ~isFiniteNum(rDisplacementLimitX,[0, inf;0 0])
        errordlgMLS('Incorrect value for PTO displacement X');
        return
    end
end

if updateWaitBar(h,0.85) return; end;

% Adaptation for non-infinite gain
% arPlant=zModelSimple.zModelPto.arMagnitude.*...
%     exp(1i*zModelSimple.zModelPto.arPhase*pi/180);
% arInverseAdaptiveLaw = 1./arAdaptiveLawData;
% arControllerGain = dcgain(tfController);
% arReferenceSpeedGain=1./(real(arPlant*arControllerGain./...
%     (1 + arPlant*arControllerGain).*...
%     (arInverseAdaptiveLaw/arControllerGain + 1)));


% Impedance and corresponding frequencies for the damping controller
arImpedance = 1./zModelSimple.zModelPto.arMagnitude./zModelSimple.zModelPto.arFreq;
arFrequency = zModelSimple.zModelPto.arFreq;

% Controller - Passive Linear Damping
rPassiveDampingGain = getValue(handles.edit_gainPLD);
if ~isFiniteNum(rPassiveDampingGain,[-inf, 0;0 0])
    errordlgMLS('Incorrect value for gain of the PLD');
    return
end

% Force excitation
% Floater
tfFExcitementFloater = eval(zController.floaterFexc);
[arFexcFloaterNum,arFexcFloaterDen]=tfdata(tfFExcitementFloater,'v');

% Spar
if iWecType == 3 || iWecType == 4
    tfFExcitementSpar = eval(zController.sparFexc);
    [arFexcSparNum,arFexcSparDen]=tfdata(tfFExcitementSpar,'v');
end

% Floater
[tfFloater2,rAccelerationGainFloater,rDampingGainFloater,rBuoyancyGainFloater]...
    = get2Zeros(1/eval(zController.floaterImpedance));
[arExcForceFloaterNum,arExcForceFloaterDen] = tfdata(tfFloater2,'v');


% Spar
if iWecType == 3 || iWecType == 4
    [tfImpedanceSpar,rAccelerationGainSpar,rDampingGainSpar,rBuoyancyGainSpar]...
        = get2Zeros(1/eval(zController.sparImpedance));
    [arExcForceSparNum,arExcForceSparDen]=tfdata(tfImpedanceSpar,'v');
end

if iWecType ==4
    % Floater
    tfFExcitementFloaterX = eval(zController.floaterFexcX);
    [arFexcFloaterXNum,arFexcFloaterXDen]=tfdata(tfFExcitementFloaterX,'v');
    
    % Spar
    tfFExcitementSparX = eval(zController.sparFexcX);
    [arFexcSparXNum,arFexcSparXDen]=tfdata(tfFExcitementSparX,'v');
    
    % Floater
    [tfImpedanceFloaterX,rAccelerationGainFloaterX,rDampingGainFloaterX,rBuoyancyGainFloaterX]...
        = get2Zeros(1/eval(zController.floaterImpedanceX));
    [arExcForceFloaterXNum,arExcForceFloaterXDen] = tfdata(tfImpedanceFloaterX,'v');
    
    
    % Spar
    [tfImpedanceSparX,rAccelerationGainSparX,rDampingGainSparX,rBuoyancyGainSparX]...
        = get2Zeros(1/eval(zController.sparImpedanceX));
    [arExcForceSparXNum,arExcForceSparXDen]=tfdata(tfImpedanceSparX,'v');
    
    % Controller - Passive Linear Damping
    rPassiveDampingGainX = getValue(handles.edit_gainPLDX);
    if ~isFiniteNum(rPassiveDampingGainX,[-inf, 0;0 0])
        errordlgMLS('Incorrect value for gain of the PLD X');
        return
    end
end

if updateWaitBar(h,0.9) return; end;
% EKF initialisation
EKFFloater = handles.Design.EKFFloater;
rKalmanFilterSampleTime = EKFFloater.sampleTime;
rUpperFrequencyLimit = EKFFloater.upperFreq;
% Put parameters into a matrix for ease of reading into EKF code
arEkfInitialisation = zeros(1,11);
arEkfInitialisation(1) = EKFFloater.freq_0;
arEkfInitialisation(2) = EKFFloater.Fexc_0;
arEkfInitialisation(3) = 0;
arEkfInitialisation(4) = EKFFloater.sampleTime;
arEkfInitialisation(5) = EKFFloater.procCovariance1;
arEkfInitialisation(6) = EKFFloater.procCovariance2;
arEkfInitialisation(7) = EKFFloater.procCovariance3;
arEkfInitialisation(8) = EKFFloater.measCovariance;
arEkfInitialisation(9) = EKFFloater.procCovariance1_0;
arEkfInitialisation(10) = EKFFloater.procCovariance2_0;
arEkfInitialisation(11) = EKFFloater.procCovariance3_0;

EKFSpar = handles.Design.EKFSpar;
rKalmanFilterSampleTime = EKFSpar.sampleTime;
arEkfInitialisationX = zeros(1,11);
arEkfInitialisationX(1) = EKFSpar.freq_0;
arEkfInitialisationX(2) = EKFSpar.Fexc_0;
arEkfInitialisationX(3) = 0;
arEkfInitialisationX(4) = EKFSpar.sampleTime;
arEkfInitialisationX(5) = EKFSpar.procCovariance1;
arEkfInitialisationX(6) = EKFSpar.procCovariance2;
arEkfInitialisationX(7) = EKFSpar.procCovariance3;
arEkfInitialisationX(8) = EKFSpar.measCovariance;
arEkfInitialisationX(9) = EKFSpar.procCovariance1_0;
arEkfInitialisationX(10) = EKFSpar.procCovariance2_0;
arEkfInitialisationX(11) = EKFSpar.procCovariance3_0;

rControllerSampleTime = rKalmanFilterSampleTime;


% Discretise the user controller
tfControllerDiscrete = discretiseTf(tfController,rControllerSampleTime);
[arControllerDiscreteNum, arControllerDiscreteDen] = tfdata(tfControllerDiscrete.tfContinuous,'v');
rGainForAntiWIndUp = tfControllerDiscrete.rGain;

tfControllerX = eval(zController.ptoContX);
tfControllerXDiscrete = discretiseTf(tfControllerX,rControllerSampleTime);
[arControllerDiscreteXNum, arControllerDiscreteXDen] = tfdata(tfControllerXDiscrete.tfContinuous,'v');
rGainForAntiWIndUpX = tfControllerXDiscrete.rGain;


rBalancingForce = -(rFloaterVolume*rDENSITY - rFloaterMass)*rGRAVITY;

iSensorNoise = 0;
rAccNoisePower = 1e-6;
rVelNoisePower = 1e-6;
rPosNoisePower = 1e-6;

azVarsToPass = {'arAdaptiveLawData','arFrequencyRange','arControllerDiscreteNum', 'arControllerDiscreteDen','rGainForAntiWIndUp',...
    'iControlType','iAdaptiveDamping','iPtoPositionConstraint','rDisplacementLimit','rMaxForcePto','rMinForcePto','rOutputSampleTime',...
    'arControllerRampGain','arControllerRampTime','iSensorNoise','arImpedance','arFrequency','arEkfInitialisation'...
    'rPassiveDampingGain','rKalmanFilterSampleTime','rAccelerationGainFloater','rDampingGainFloater','rBuoyancyGainFloater'...
    'rCogFloater','arExcForceFloaterNum','arExcForceFloaterDen','rUpperFrequencyLimit','rControllerSampleTime',...
    'iSensorNoise','rAccNoisePower','rVelNoisePower','rPosNoisePower'};

azVarsWEC1Or2 = {'rBalancingForce'};

azVarsToPassSpar = {'arFexcFloaterNum','arFexcFloaterDen','arFexcSparNum',...
    'arFexcSparDen','arExcForceSparNum','arExcForceSparDen','rAccelerationGainSpar','rDampingGainSpar','rBuoyancyGainSpar'...
    'rCogSpar','rMooringX','rMooringY','rMooringZ'};

azVarsToPassWec4 = {'arAdaptiveLawDataX','arFexcFloaterXNum','arFexcFloaterXDen','arFexcSparXNum','arFexcSparXDen',...
    'arExcForceFloaterXNum','arExcForceFloaterXDen','arExcForceSparXNum','arExcForceSparXDen','rAccelerationGainFloaterX',...
    'rDampingGainFloaterX','rBuoyancyGainFloaterX','rAccelerationGainSparX','rDampingGainSparX','rBuoyancyGainSparX',...
    'rTetherLength0','rTetherPretension','rTetherSpring','arImpedanceX','arFrequencyX','arControllerDiscreteXNum', ...
    'arControllerDiscreteXDen','rGainForAntiWIndUpX','rDisplacementLimitX','arEkfInitialisationX','rPassiveDampingGainX'};

for iCont = 1:numel(azVarsToPass)
    assignin('base',azVarsToPass{iCont},eval(azVarsToPass{iCont}));
end
if iWecType == 1 || iWecType == 2
    for iCont = 1:numel(azVarsWEC1Or2)
        assignin('base',azVarsWEC1Or2{iCont},eval(azVarsWEC1Or2{iCont}));
    end
end

if iWecType == 3 || iWecType == 4
    for iCont = 1:numel(azVarsToPassSpar)
        assignin('base',azVarsToPassSpar{iCont},eval(azVarsToPassSpar{iCont}));
    end
end

if iWecType == 4
    for iCont = 1:numel(azVarsToPassWec4)
        assignin('base',azVarsToPassWec4{iCont},eval(azVarsToPassWec4{iCont}));
    end
end

if ~isempty(handles.additionalParam)
    try
        evalin('base',sprintf('run(''%s'');',handles.additionalParam));
    catch
        warndlgMLS(sprintf('Errors reading file %s',handles.additionalParam));
    end
end
if updateWaitBar(h,1) return; end;

function error = updateWaitBar(h,rPerc)
if ishandle(h)
    error = 0;
    waitbarMLS(rPerc,h);
    if rPerc ==1
        close(h);
    end
else
    error = 1;
end

function zVelocityModel = getVelocityModel(zModel)
zVelocityModel.arMagnitude = zModel.arMagnitude.*zModel.arFreq;
zVelocityModel.arPhase = zModel.arPhase +90;
zVelocityModel.arFreq = zModel.arFreq;


function zAccelerationModel = getAccelerationModel(zModel)
zAccelerationModel.arMagnitude = zModel.arMagnitude.*(zModel.arFreq).^2;
zAccelerationModel.arPhase = zModel.arPhase + 180;
zAccelerationModel.arFreq = zModel.arFreq;





function edit_floaterImpedanceX_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Floater Impedance X');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'floaterImpedanceX', handles);
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function edit_floaterImpedanceX_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_sparImpedanceX_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Spar Impedance X');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'sparImpedanceX', handles);
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function edit_sparImpedanceX_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_floaterFexcX_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Floater Excitation X');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'floaterFexcX', handles);
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function edit_floaterFexcX_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edit_sparFexcX_Callback(hObject, eventdata, handles)
str = get(hObject, 'String');
[success, C] = checkTf(str, 'Spar Excitation X');
if ~success
    return;
end

% update controller
handles = updateCs(str, 'sparFexcX', handles);
guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function edit_sparFexcX_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in pushbutton_addAddParamsFile.
function pushbutton_addAddParamsFile_Callback(hObject, eventdata, handles)
cd1 = cd;
% change the current path into previous one
if ~isempty( handles.allFilepath )
    cd( handles.allFilepath );
end

% get the file name and path for the project file
[ fileName, filePath ] = uigetfile({ '*.m' },...
    'Select the additional parameters file');

cd( cd1 );

if isequal(fileName, 0)
    return;
end

handles.additionalParam = fullfile(filePath,fileName);
set(handles.edit_AdditionalParams,'String',handles.additionalParam,'TooltipString',handles.additionalParam);
guidata(hObject,handles);


function edit_AdditionalParams_Callback(hObject, eventdata, handles)



% --- Executes during object creation, after setting all properties.
function edit_AdditionalParams_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --------------------------------------------------------------------
function menu_helpMain_Callback(hObject, eventdata, handles)



function edit_gainPLD_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[-inf 0;0 1])
    errordlgMLS('The value for the gain of the PLD is not correct');
end



% --- Executes during object creation, after setting all properties.
function edit_gainPLD_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function edit_gainPLDX_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[-inf 0;0 1])
    errordlgMLS('The value for the gain of the PLD X is not correct');
end


% --- Executes during object creation, after setting all properties.
function edit_gainPLDX_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in pushbutton_edit.
function pushbutton_edit_Callback(hObject, eventdata, handles)
if ~isempty(handles.additionalParam) && exist(handles.additionalParam,'file')
    open(handles.additionalParam);
end



function edit_displacementLimitX_Callback(hObject, eventdata, handles)
if ~isFiniteNum(getValue(hObject),[0 inf;1 0])
    errordlgMLS('The value for maximum displacement X is not correct');
end


% --- Executes during object creation, after setting all properties.
function edit_displacementLimitX_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on key press with focus on controller_design and none of its controls.
function controller_design_KeyPressFcn(hObject, eventdata, handles)

