classdef (CaseInsensitiveProperties = true, TruncatedProperties = true) ...
        MaxLoopGain < TuningGoal.BandLimited & TuningGoal.Unstable & ...
        TuningGoal.ScaledLoop & TuningGoal.SystemLevel
    % Maximum loop gain constraint for control system tuning.
    %
    %   This requirement is useful to enforce small loop gain and adequate
    %   roll-off in a particular frequency band.
    %
    %   R = TuningGoal.MaxLoopGain(LOC,LOOPGAIN) creates a tuning requirement
    %   R for limiting the gain of a SISO or MIMO feedback loop. The string
    %   or string vector LOC specifies the loop opening location(s) where the
    %   open-loop response L is measured (see below). The magnitude of the
    %   SISO transfer function LOOPGAIN specifies the maximum gain of L as a
    %   function of frequency. You can use an FRD model to sketch the desired
    %   gain profile with just a few frequency points. For example,
    %      LG = frd([1 1e-1 1e-3],[1 10 100]);
    %      R = TuningGoal.MaxLoopGain('PILoop',LG)
    %   specifies a maximum gain of 1 (0 dB) at 1 rad/s, rolling off at
    %   -20 dB/dec up to 10 rad/s and at -40 dB/dec thereafter. Only gain
    %   values smaller than 1 are taken into account. For MIMO feedback loops,
    %   the specified gain profile is interpreted as an upper bound on the
    %   largest singular value of L (minimum roll-off).
    %
    %   R = TuningGoal.MaxLoopGain(LOC,FMAX,GMAX) specifies a maximum gain
    %   profile of the form LOOPGAIN=K/s (integral action) where K is chosen
    %   so that GMAX is the maximum gain (in absolute value) at the frequency
    %   FMAX (in rad/TimeUnit).
    %
    %   In MATLAB, use AnalysisPoint blocks to mark loop opening locations (LOC
    %   can contain any name listed in the "Location" property of such blocks).
    %   For example,
    %      AP = AnalysisPoint('PILoop');
    %      G = tf(1,[1 2]);
    %      C = tunablePID('C','pi');
    %      T = feedback(AP*G*C,1);
    %   creates a SISO PI loop with a "PILoop" switch at the plant output.
    %   You can then use LOC='PILoop' to refer to the open-loop response
    %   measured at the plant output. In Simulink, LOC can contain any
    %   Linear Analysis point marked in the model or flagged using the
    %   addPoint method of the slTuner interface.
    %
    %   Set properties to further configure the requirement. For example,
    %      R = TuningGoal.MaxLoopGain('InnerLoop',10,0.1)
    %      R.Name = 'Max gain for inner loop'
    %      R.Openings = 'OuterLoop'
    %      R.Focus = [10 Inf]
    %      R.Models = 2
    %   names the requirement, specifies that the loop gain is measured with
    %   the outer loop open, and restricts the requirement to the frequency
    %   band [10,Inf] and to the second plant model. For details on individual
    %   properties, type "help TuningGoal.MaxLoopGain.<property name>".
    %
    %   Use VIEWGOAL(R) to visualize this requirement and use SYSTUNE and
    %   related commands to tune the control system parameters subject to
    %   this and other requirements.
    %
    %   Algorithm: This goal is turned into a normalized gain constraint
    %      || wT * T ||oo < 1
    %   on the complementary sensitivity function T=1-S. The frequency
    %   weighting function wT is derived from the specified max loop gain,
    %   see GETWEIGHT for details.
    %
    %   See also AnalysisPoint, getPoints, sigma, evalGoal, viewGoal, getWeight,
    %   TuningGoal.MinLoopGain, TuningGoal.LoopShape, TuningGoal.Gain,
    %   TuningGoal.Margins, TuningGoal, systune, looptune, slTuner.

    % Author: P. Gahinet
    %   Copyright 2009-2016 The MathWorks, Inc.

    properties
        % Maximum loop gain (SISO ZPK model).
        %
        % This property specifies the maximum open-loop gain as a function of
        % frequency. You can specify a smooth gain profile using a transfer
        % function or sketch a piecewise gain profile using an FRD model. Both
        % are mapped to a ZPK model whose magnitude reflects the desired gain
        % profile.
        MaxGain
    end

    methods

        % Constructor
        function this = MaxLoopGain(Loc,varargin)
            narginchk(2,3)
            if nargin>2
                % MaxLoopGain(LOC,FMAX,GMAX)
                fmax = varargin{1};
                gmax = varargin{2};
                if ~(isnumeric(fmax) && isscalar(fmax) && isreal(fmax) && isfinite(fmax) && fmax>0)
                    error(message('Control:tuning:MaxLoopGainReq1'))
                elseif ~(isnumeric(gmax) && isscalar(gmax) && isreal(gmax) && isfinite(gmax) && gmax>0)
                    error(message('Control:tuning:MaxLoopGainReq2'))
                end
                LoopGain = zpk([],0,fmax*gmax);
            else
                LoopGain = varargin{1};
            end
            try
                this.Location = Loc;
                this.MaxGain = LoopGain;
            catch ME
                throw(ME)
            end
        end

        function this = set.MaxGain(this,Value)
            % SET function for MaxGain
            [Value,errCode] = TuningGoal.checkMagProfile(Value);
            switch errCode
                case 1
                    % Not scalar or SISO value
                    error(message('Control:tuning:MinLoopGainReq3'))
                case 2
                    % Cannot compute ZPK form
                    error(message('Control:tuning:MinLoopGainReq4'))
                case 3
                    % All zero profile
                    error(message('Control:tuning:MinLoopGainReq5'))
            end
            this.MaxGain = Value;
        end

        function [wT,wc] = getWeight(this,Ts)
            % GETWEIGHT  Computes weighting function wT.
            %
            %   The MaxLoopGain goal is enforced as an H-infinity norm constraint
            %      || wT * T ||oo < 1
            %   on the complementary sensitivity function T=1-S. The frequency
            %   weighting function wT is derived from the specified max loop
            %   gain profile.
            %
            %   WT = getWeight(R,TS) returns the weighting function wT for
            %   the MaxLoopGain goal R and tuning sample time TS. The gains
            %   of 1/WT and R.MaxGain roughly match for gain values ranging
            %   from +20 dB to -60 dB. For numerical reasons, WT levels off
            %   outside this range unless the specified gain profile changes
            %   slope outside this range. Because poles of WT close to s=0 or
            %   s=Inf can adversely impact the SYSTUNE solver, it is not
            %   recommended to specify gain profiles R.MaxGain with very low-
            %   or very high-frequency dynamics.
            %
            %   See also TuningGoal.MaxLoopGain, getSensitivity.
            wT = TuningGoal.resampleWeight(1/this.MaxGain,Ts);
            % Well-posedness
            if getPeakGain(wT,1e-2)<1.01
                % |wT|<1 at all frequencies (ineffective)
                error(message('Control:tuning:MaxLoopGainReq3'))
            end
            % Find gain crossovers
            wc = getGainCrossover(wT,1);
            if ~any(wc>0 & wc<pi/Ts)
                % |wT|>1 at all frequencies: adjust gain level for crossover
                g0 = abs(dcgain(wT));
                if g0>1e8
                    error(message('Control:tuning:MaxLoopGainReq4'))
                end
                wc = getGainCrossover(wT,1.25*g0); % could still be empty, e.g., for constant wT
            end
            % Regularize weight
            wT = TuningGoal.regularizeWeight1(wT,wc,this.Focus);
        end

    end

    methods (Access = protected)

        function [H,fObj] = evalSpec_(this,CL)
            % Evaluates requirement for given closed-loop model
            S = getSensitivity(CL,this.Location,this.Openings,this.Models);
            S = sminreal(getValue(S));
            nL = size(S,1);
            T = eye(nL)-S;
            % Scaling
            T = applyLoopScaling(this,T,getTuningInfo(CL));
            % Evaluate goal
            wT = getWeight(this,T.Ts);
            wT.TimeUnit = T.TimeUnit;
            H = wT * T;
            if nargout>1
                fObj = getPeakGain(H,1e-6,this.Focus);
            end
        end

    end

    methods (Hidden) %% Tuning goal API

        % Compute data for Goal wave forms
        function [MaxG,TBound,Ts,TU] = viewSpecGoalData(this,CL)
            MaxG = this.MaxGain;
            MaxG.Name = getString(message('Control:systunegui:TGPlotMaxLoopGain'));
            if isequal(CL,[])
                Ts = MaxG.Ts;
                TU = MaxG.TimeUnit;
            else
                Ts = CL.Ts;
                TU = CL.TimeUnit;
                MaxG.TimeUnit = TU;
            end
            wT = getWeight(this,Ts);
            wT.TimeUnit = TU;
            TBound = 1/wT;
        end

        % Compute data for Design wave forms
        function [L0,T,Ls] = viewSpecDesignData(this,CL)
            % Compute L0
            L0 = getValue(getLoopTransfer(CL,this.Location,+1,this.Openings,this.Models),'usample');
            L0.Name = getString(message('Control:systunegui:TGPlotLoopGain'));
            % Compute scaled response Ls
            [L,ShowScaled] = applyLoopScaling(this,L0,getTuningInfo(CL));
            if ShowScaled
                Ls = L;
                Ls.Name = getString(message('Control:systunegui:TGPlotScaledLoopGain'));
            else
                Ls = [];
            end
            % Compute T
            T = feedback(L,eye(size(L,1)),+1);
            T.Name = getString(message('Control:systunegui:TGPlotT'));
        end

        % Validate if data is compatible for plotting
        function b = isCompatible(this,CL,CurrentDesignWaveforms)
            % Check for consistent size and sample time
            L0 = viewSpecDesignData(this,CL);
            NewValue = L0;
            if controllib.chart.internal.utils.isChartResponse(CurrentDesignWaveforms.L)
                OldValue = CurrentDesignWaveforms.L.Model;
            else
                OldValue = CurrentDesignWaveforms.L.DataSrc.Model;
            end
            b = isequal(size(NewValue),size(OldValue)) && isequal(NewValue.Ts,OldValue.Ts);
        end

        % Update limits
        function updateLimits(this,Ts,plotHandle,XLimitsFocus,YLimitsFocus)
            if controllib.chart.internal.utils.isChart(plotHandle)
                view = qeGetView(plotHandle);
                axGrid = qeGetAxesGrid(view);
                [~,wc] = getWeight(this,Ts);
                axGrid.XLimitsFocus = {TuningGoal.getFreqLims(XLimitsFocus{1},this.Focus,Ts,wc)};
                YUnits = plotHandle.MagnitudeUnit;
                Ylim = YLimitsFocus{1};
                Ylim(1) = max(min(Ylim(1),unitconv(-40,'dB',YUnits)),unitconv(-80,'dB',YUnits));
                Ylim(2) = unitconv(20,'dB',YUnits);
                axGrid.YLimitsFocus = {Ylim};
            else
                ax = plotHandle;
                XLimMode = XLimitsFocus;
                YLimMode = YLimitsFocus;
                % Adjust X limit to show interesting range
                if strcmp(XLimMode,'auto')
                    [~,wc] = getWeight(this,Ts);
                    Xlim = TuningGoal.getFreqLims(get(ax,'XLim'),this.Focus,Ts,wc);
                    set(ax,'XLim',Xlim)
                end
                if strcmp(YLimMode,'auto')
                    % Get Y units
                    h = gcr(ax);
                    YUnits = h.AxesGrid.YUnits;
                    % Adjust Y limit
                    ax.YLimMode = 'auto';
                    Ylim = get(ax,'Ylim');
                    Ylim(1) = max(min(Ylim(1),unitconv(-40,'dB',YUnits)),unitconv(-80,'dB',YUnits));
                    Ylim(2) = unitconv(20,'dB',YUnits);
                    set(ax,'YLim',Ylim)
                end
            end
        end

        function [h, GoalWaveforms, CurrentDesignWaveforms,Ts] = createPlot(this,CL,ax)
            % Create plot
            [MaxG,TBound,Ts,TU] = viewSpecGoalData(this,CL);
            GoalWaveforms = struct('MaxG',[],'TBound',[]);
            if isequal(CL,[])
                % Just show bounds and target shape
                h = sigmaplot(ax,MaxG,'k--');
                CurrentDesignWaveforms = struct('T',[],'L',[],'LScaled',[]);
                if controllib.chart.internal.utils.isChart(h)
                    GoalWaveforms.MaxG = h.Systems(1);
                    h.Systems(1).Style.SemanticColor = "--mw-graphics-colorNeutral-line-secondary";
                else
                    GoalWaveforms.MaxG = h.Response(1);
                    h.Responses(1).setstyle(SemanticColor="--mw-graphics-colorNeutral-line-secondary");
                end
            else
                [L0,T,Ls] = viewSpecDesignData(this,CL);
                if isempty(Ls)
                    % No scaling
                    h = sigmaplot(ax,T,'r',L0,'b',L0,'b',MaxG,'k--');
                    if controllib.chart.internal.utils.isChart(h)
                        removeSystem(h,3) %change sigmaplot call once charts on
                        CurrentDesignWaveforms = struct('T',h.Systems(1),'L',h.Systems(2));
                        h.Systems(1).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(10).SemanticName;
                        h.Systems(2).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(1).SemanticName;
                        h.Systems(3).Style.SemanticColor = "--mw-graphics-colorNeutral-line-secondary";
                        GoalWaveforms.MaxG = h.Systems(3);
                    else
                        % Make redundant response invisible to legend
                        r = h.Responses(2);
                        set(handle(r.Group),'HandleVisibility','off');
                        r.draw
                        % Adjust response style
                        r = h.Responses;
                        r(1).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(10).SemanticName);
                        r(2).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(6).SemanticName);
                        r(3).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(1).SemanticName);
                        r(4).setstyle(SemanticColor="--mw-graphics-colorNeutral-line-secondary");
                        CurrentDesignWaveforms = struct('T',r(1),'L',r(2),'LScaled',r(3));
                        GoalWaveforms.MaxG = r(4);
                    end
                else
                    h = sigmaplot(ax,T,'r',L0,'b',Ls,'b',MaxG,'k--');
                    if controllib.chart.internal.utils.isChart(h)
                        h.Systems(1).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(10).SemanticName;
                        h.Systems(2).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(6).SemanticName;
                        h.Systems(3).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(1).SemanticName;
                        h.Systems(4).Style.SemanticColor = "--mw-graphics-colorNeutral-line-secondary";
                        CurrentDesignWaveforms = struct('T',h.Systems(1),'L',h.Systems(2),'LScaled',h.Systems(3));
                        GoalWaveforms.MaxG = h.Systems(4);
                    else
                        % Adjust response style
                        r = h.Responses;
                        r(1).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(10).SemanticName);
                        r(2).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(6).SemanticName);
                        r(3).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(1).SemanticName);
                        r(4).setstyle(SemanticColor="--mw-graphics-colorNeutral-line-secondary");
                        CurrentDesignWaveforms = struct('T',r(1),'L',r(2),'LScaled',r(3));
                        GoalWaveforms.MaxG = r(4);
                    end
                end
            end
            % Thicker lines
            if controllib.chart.internal.utils.isChart(h)
                for ct=1:numel(h.Systems)
                    h.Systems(ct).Style.LineWidth = 1.75;
                end
            else
                for ct=1:numel(h.Response)
                    h.Response(ct).setstyle('LineWidth',1.75)
                end
            end
            % Legend
            legend(ax,'location','SouthWest');
            % Title
            if controllib.chart.internal.utils.isChart(h)
                h.Title.String = getString(message('Control:tuning:strMaxLoopGain1',this.Name));
                h.Title.Interpreter = 'none';
                h.Grid = 'on';
            else
                h.AxesGrid.Title = getString(message('Control:tuning:strMaxLoopGain1',this.Name));
                h.AxesGrid.TitleStyle.Interpreter = 'none';
                h.AxesGrid.YUnits = 'dB';
                h.AxesGrid.YScale = {'linear'};
                h.AxesGrid.Grid = 'on';
            end
            % Plot bounds for T (includes regularization and discretization
            % effects)
            if controllib.chart.internal.utils.isChart(h)
                h.addBoundSystem(TBound,BoundType='upper',...
                    Focus=this.Focus * funitconv('rad/TimeUnit','rad/s',TU),...
                    SystemName=getString(message('Control:systunegui:TGPlotEffectiveBound')),...
                    UseFrequencyFocus=false,UseMagnitudeFocus=true);
                h.Systems(end).Style.SemanticFaceColor = controllib.plot.internal.utils.GraphicsColor(10).SemanticName;
                h.Systems(end).Style.SemanticEdgeColor = controllib.plot.internal.utils.GraphicsColor(10).SemanticName;
                h.Systems(end).Style.FaceAlpha = 0.3;
                h.Systems(end).Style.EdgeAlpha = 0.3;
                GoalWaveforms.TBound = h.Systems(end);
            else
                r = h.addSigmaBound(TBound,'upper',...
                    this.Focus * funitconv('rad/TimeUnit','rad/s',TU));
                r.DataSrc.UseFocus = false; % Do not participate in limit picking
                r.Name = getString(message('Control:systunegui:TGPlotTBound'));
                r.setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(10,"secondary").SemanticName);
                % Set Goal wave forms for TBound
                GoalWaveforms.TBound = r;
            end
        end

        % Update Goal waveforms
        function [Ts,TU] = updateGoal(this,CL,hPlot,GoalWaveforms)
            % Compute data for goals
            [MaxG,TBound,Ts,TU] = viewSpecGoalData(this,CL);
            h = getPlotHandle(hPlot);
            % Update plotted goals
            if controllib.chart.internal.utils.isChart(h)
                GoalWaveforms.MaxG.Model = MaxG;
            else
                GoalWaveforms.MaxG.DataSrc.Model = MaxG;
            end
            % Goal Focus
            tau = funitconv('rad/TimeUnit','rad/s',TU);
            wFocus = tau*this.Focus;
            % Update TBound
            if controllib.chart.internal.utils.isChart(h)
                GoalWaveforms.TBound.Model = TBound;
                GoalWaveforms.TBound.Focus = wFocus;
            else
                updateSource(GoalWaveforms.TBound.DataSrc,TBound,wFocus)
            end
            % Set Title for the plot
            setTitle(hPlot,getString(message('Control:tuning:strMaxLoopGain1',this.Name)));
        end

        % Update Design waveforms
        function updateDesign(this,DesignWaveforms,CL)
            % Compute data for design
            [L0,T,Ls] = viewSpecDesignData(this,CL);
            if controllib.chart.internal.utils.isChartResponse(DesignWaveforms.L)
                DesignWaveforms.L.Model = L0;
                DesignWaveforms.T.Model = T;
                if ~isempty(Ls)
                    DesignWaveforms.LScaled.Model = Ls;
                    DesignWaveforms.LScaled.Name = Ls.Name;
                end
            else
                % Update L, T for design
                DesignWaveforms.L.DataSrc.Model = L0;
                DesignWaveforms.T.DataSrc.Model = T;
                % Update and tweak responses associated with L and Ls
                g = handle(DesignWaveforms.L.Group);  % unscaled resp
                if isempty(Ls)
                    % No scaling
                    DesignWaveforms.LScaled.DataSrc.Model = L0;
                    DesignWaveforms.LScaled.Name = L0.Name;
                    set(g,'HandleVisibility','off');
                else
                    DesignWaveforms.LScaled.DataSrc.Model = Ls;
                    DesignWaveforms.LScaled.Name = Ls.Name;
                    set(g,'HandleVisibility','on');
                end
                DesignWaveforms.L.draw
            end
        end

        % Add design
        function DesignWaveforms = addDesign(this,PlotHandle,Design,Name,LineStyle)
            % Compute data for design
            [L0,T,Ls] = viewSpecDesignData(this,Design);
            if controllib.chart.internal.utils.isChart(PlotHandle)
                addSystem(PlotHandle,T,SystemName=Name);
                PlotHandle.Systems(end).Style.LineStyle = LineStyle;
                PlotHandle.Systems(end).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(10,"quaternary").SemanticName;
                PlotHandle.Systems(end).Style.LineWidth = 1.75;
                addSystem(PlotHandle,L0,SystemName=Name);
                PlotHandle.Systems(end).Style.LineStyle = LineStyle;
                PlotHandle.Systems(end).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(1,"quaternary").SemanticName;
                PlotHandle.Systems(end).Style.LineWidth = 1.75;
                if isempty(Ls)
                    DesignWaveforms = struct('T',PlotHandle.Systems(end-1),'L',PlotHandle.Systems(end));
                else
                    addSystem(PlotHandle,Ls,SystemName=Name);
                    PlotHandle.Systems(end).Style.LineStyle = LineStyle;
                    PlotHandle.Systems(end-1).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(6,"quaternary").SemanticName;
                    PlotHandle.Systems(end).Style.SemanticColor = controllib.plot.internal.utils.GraphicsColor(1,"quaternary").SemanticName;
                    PlotHandle.Systems(end).Style.LineWidth = 1.75;
                    DesignWaveforms = struct('T',PlotHandle.Systems(end-2),'L',PlotHandle.Systems(end-1),'LScaled',PlotHandle.Systems(end));
                end
            else
                if isempty(Ls)
                    % No loop scaling
                    Systems = {T,L0,L0};
                    Colors = {'r','b','b'};
                else
                    % Show both scaled and unscaled loop shapes
                    Systems = {T,L0,Ls};
                    Colors = {'r','b','b'};
                end
                r = PlotHandle.addSystem(Systems,Name,Colors,LineStyle);
                r(1).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(10).SemanticName);
                r(2).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(6).SemanticName);
                r(3).setstyle(SemanticColor=controllib.plot.internal.utils.GraphicsColor(1).SemanticName);
                DesignWaveforms = struct('T',r(1),'L',r(2),'LScaled',r(3));
                for ct=1:numel(r)
                    r(ct).setstyle('LineWidth',1.75)
                end
                if isempty(Ls)
                    % Make redundant response invisible to legend
                    set(handle(r(2).Group),'HandleVisibility','off');
                    r(2).draw
                end
            end
        end

    end

    methods (Hidden)

        function validateGoal(this,CL)
            % Note: Needed to validate Models selection
            S = getSensitivity(CL,this.Location,this.Openings,this.Models);
            getWeight(this,S.Ts);
        end

        function [SPEC,LoopConfigs] = getSpecData(this,SPEC,LoopConfigs,uNames,yNames,sNames,Ts)
            % Builds standardized requirement description for SYSTUNE.
            if isempty(this.Location)
                error(message('Control:tuning:TuningReq16',getID(this)))
            end
            SPEC.Type = 3;
            SPEC.Stabilize = this.Stabilize;
            SPEC.Band = [this.Focus(1) , min(this.Focus(2),pi/Ts)];
            if diff(SPEC.Band)<=0
                error(message('Control:tuning:TuningReq15',getID(this)))
            end
            % Locate channels where loop transfer is measured
            [iLoop,MisMatch] = ltipack.resolveSignalID(this.Location,sNames,true);
            error(resolveSignalError(this,'Control:tuning:TuningReq8',MisMatch,sNames))
            SPEC.Input = numel(uNames) + iLoop;
            SPEC.Output = numel(yNames) + iLoop;
            nL = numel(iLoop);
            SPEC.DScaling.Static = (nL>1 && strcmp(this.LoopScaling,'on'));
            % Locate openings
            if isempty(this.Openings)
                iOpen = [];
            else
                [iOpen,MisMatch] = ltipack.resolveSignalID(this.Openings,sNames,true);
                error(resolveSignalError(this,'Control:tuning:TuningReq8',MisMatch,sNames))
                % Ignore loop openings in locations where loop transfer is measured
                iOpen = setdiff(iOpen,iLoop);
            end
            [SPEC.Config,LoopConfigs] = ...
                TuningGoal.SystemLevel.getSwitchConfig(iOpen,LoopConfigs);
            % Get weights
            [aT,bT,cT,dT] = ssdata(getWeight(this,Ts));
            pW = eig(aT);
            if nL>1
                [aT,bT,cT,dT] = TuningGoal.repWeight(aT,bT,cT,dT,nL);
            end
            SPEC.WL = struct('a',aT,'b',bT,'c',cT,'d',dT,'Poles',pW);
        end

    end

end
