## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples

### Package Content

Name | Description
--- | ---
designCraneController | Design pole assignment and LQ controller for an overhead crane
designCraneControllerWithObserver | Design pole assignment controller and observer for an overhead crane
designInverseDoublePendulumController | Design pole assignment for an inverse double pedulum
designInverseDoublePendulumControllerWithObserver | Design pole assignment for an inverse double pedulum
designInversePendulumController | Design pole assignment for an inverse pedulum
designStateSpaceController | Demonstration of controller design for a state space system
analysis2 | Example to check controllability of a state space system
plotBodeSISODiscrete | Plots the Bode diagram of continuous state space system and the corresponding discrete state space system and with automatic determination of the frequency range to plot

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.designCraneController

Design pole assignment and LQ controller for an overhead crane

### Information

This example demonstrates how to design a lq-controller or a pole placement controller respectively. Compared with example craneController, the plant is smaller to achieve suitable dynamics for animation. The feedback matrices and a simple pre filter for tracking are save to MATLAB files which can be used in ModelicaController library.
It is also shown how to linearize a model of a crane trolley system [1]. The linear model is used as a base for control design

References

      [1] Föllinger, O. "Regelungstechnik", Hüthig-Verlag

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | modelName | "Modelica_Controller.Example... | name of the model to linearize
Complex | pa[4] | {-3.5 + 0*j,-3.5 + 0*j,-3.5 ... | assigned poles

### Outputs

Type | Name | Description
--- | --- | ---
Real | K_lq[:, :] | feedback matrix LQ controller
Real | K_pa[:, :] | feedback matrix pole assigment controller
Real | M_lq[:, :] | pre filter LQ controller
Real | M_pa[:, :] | pre filter pole assignment controller

### Modelica definition

    function designCraneController
      "Design pole assignment and LQ controller for an overhead crane"
      import Modelica.Utilities.Streams.print;
      import Modelica_LinearSystems2;
      import Modelica_LinearSystems2.Math.Complex;
      import Modelica_LinearSystems2.Math.Matrices;
      import Modelica_LinearSystems2.TransferFunction;
      import Modelica_LinearSystems2.ZerosAndPoles;

      input String modelName=
          "Modelica_Controller.Examples.Components.Pendulum_small"
        "name of the model to linearize";

      input Complex pa[4]={-3.5 + 0*j,-3.5 + 0*j,-3.5 - 0.5*j,-3.5 + 0.5*j}
        "assigned poles";

      output Real K_lq[:,:] "feedback matrix LQ controller";
      output Real K_pa[:,:] "feedback matrix pole assigment controller";
      output Real M_lq[:,:] "pre filter LQ controller";
      output Real M_pa[:,:] "pre filter pole assignment controller";
    protected
      input Complex j=Modelica_LinearSystems2.Math.Complex.j();

    protected
      Real Q[:,:];
      Real R[:,:];

    // Determine linear System from Modelica_Controller.Examples.Pendulum.mo
      Modelica_LinearSystems2.StateSpace ss=
          Modelica_LinearSystems2.StateSpace.Import.fromModel(modelName);
    //Modelica_LinearSystems2.StateSpace ss=Modelica_LinearSystems2.StateSpace(A= [0,1,0,0;0,0,39.24,0;0,0,0,1;0,0,-4.904,0], B=[0;1e-3;0;-1e-4], C=[1,0,1,0], D=[0]);

      Complex p[:]=Modelica_LinearSystems2.Math.Complex.eigenValues(ss.A);
      Modelica_LinearSystems2.StateSpace ss_lq=ss;
      Modelica_LinearSystems2.StateSpace ss_pa=ss;

    algorithm
      print("The linearized state space system is determined to:\n" + String(ss));

    // ####### LQ CONTROLLER #######

    // eigenvalues of open loop system
      p := Modelica_LinearSystems2.Math.Complex.eigenValues(ss.A);
      print("eigenvalues of the open loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev", p);

    // Calculate feesback matrix of a lq controller (Riccati) with weighting matrices Q and R
      Q := [1,0,300,1000; 0,100,0,3000; 0,0,1000,0; 0,10,0,1];
      Q := Q*transpose(Q);
      R := identity(size(ss.B, 2));
      (K_lq) := Modelica_LinearSystems2.StateSpace.Design.lqr(
        ss,
        Q,
        R);

    print("\nXXXXXXXXXXX:\n");

      ss_lq.A := ss.A - ss.B*K_lq;
      print("The feedback matrix of the lq controller is:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        K_lq,
        6,
        "K_lq"));
      writeMatrix(
        DataDir + "craneController_small.mat",
        "K_lq",
        K_lq);

    // eigenvalues of closed loop system
      p := Modelica_LinearSystems2.Math.Complex.eigenValues(ss_lq.A);
      print("eigenvalues of the closed loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev_lq", p);

    // Pre filter calculation
      M_lq := -Modelica.Math.Matrices.inv([1,0,0,0]*Matrices.solve2(ss_lq.A, ss_lq.B));
      print("Gain for pre filtering:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        M_lq,
        6,
        "M_lq"));
      writeMatrix(
        DataDir + "craneController_small.mat",
        "M_lq",
        M_lq,
        true);

    //####### POLE ASSIGNMENT ##########

    // feedback matrix of a pole assignment controller with assigned eigenvalues pa
      (K_pa,,p) := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss, pa);
      ss_pa.A := ss.A - ss.B*K_pa;
      print("The feedback matrix of the pole assignment controller is:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        K_pa,
        6,
        "K_pa"));
      print("eigenvalues of the closed loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev_pa", p);

      writeMatrix(
        DataDir + "craneController_small.mat",
        "K_pa",
        K_pa,
        true);

    // Pre filter calculation
      M_pa := -Modelica.Math.Matrices.inv([1,0,0,0]*Matrices.solve2(ss_pa.A, ss_pa.B));
      print("Gain for pre filtering:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        M_pa,
        6,
        "M_pa"));
      writeMatrix(
        DataDir + "craneController_small.mat",
        "M_pa",
        M_pa,
        true);

      print("\nok!");
    end designCraneController;

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.designCraneControllerWithObserver

Design pole assignment controller and observer for an overhead crane

### Information

This example demonstrates how to use pole placement function assignPolesMI to design a pole placement controller and an observer also using assignPolesMI as well. Function assignPoles is based on the Schur form of the state space matrix an also allows partial poles shifting [1].
An observer can be designed by applying assignPolesMI to the dual system (A', C', B').
The results, which are controller feedback matrix, observer feedback matrix, system model for usage in observer and a simple pre filter for tracking are saved to MATLAB files which can be used in ModelicaController library.
It is also shown how to linearize a model of a crane trolley system [1]. The linear model is then used as a base for controller design.

References

      [1] Varga A., "A Schur method for pole assignment",
          IEEE Trans. Autom. Control, Vol. AC-26, pp. 517-519, 1981.

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | modelName | "Modelica_Controller.Example... | name of the model to linearize
Complex | pa[4] | {-3.5 + 0*j,-3.5 + 0*j,-3.5 ... | assigned system poles
Complex | pob[4] | {-10 + 0*j,-10 + 0*j,-10 + 0... | assigned observer poles
String | fileName | DataDir + "craneController_s... | file name for results

### Outputs

Type | Name | Description
--- | --- | ---
Real | K_ob[:, :] | feedback matrix pole assigment controller
Real | K_pa[:, :] | feedback matrix pole assigment controller
Real | M_pa[:, :] | pre filter LQ controller

### Modelica definition

    function designCraneControllerWithObserver
      "Design pole assignment controller and observer for an overhead crane"
      import Modelica.Utilities.Streams.print;
      import Modelica_LinearSystems2;
      import Modelica_LinearSystems2.StateSpace;
      import Modelica_LinearSystems2.Math.Complex;
      import Modelica_LinearSystems2.Math.Matrices;

      input String modelName="Modelica_Controller.Examples.Components.Pendulum_small"
        "name of the model to linearize";

      input Complex pa[4]={-3.5+0*j,-3.5+0*j, -3.5-0.5*j, -3.5+0.5*j}
        "assigned system poles";

      input Complex pob[4]={-10+0*j,-10+0*j,-10+0*j,-10+0*j}
        "assigned observer poles";
     input String fileName=DataDir + "craneController_small.mat"
        "file name for results";

    protected
     input Complex j = Modelica_LinearSystems2.Math.Complex.j();
    public
      output Real K_ob[:,:] "feedback matrix pole assigment controller";
      output Real K_pa[:,:] "feedback matrix pole assigment controller";
      output Real M_pa[:,:] "pre filter LQ controller";

    // Determine linear System from Modelica_Controller.Examples.Pendulum.mo
    protected
      Modelica_LinearSystems2.StateSpace ss=
      Modelica_LinearSystems2.StateSpace.Import.fromModel(modelName);

      Complex p[:];//=Modelica_LinearSystems2.Math.Complex.eigenValues(ss.A);
      Modelica_LinearSystems2.StateSpace ss_pa=ss;
      Modelica_LinearSystems2.StateSpace ss_ob=StateSpace(A=transpose(ss.A), B=[1,0;0,1;0,0;0,0], C=transpose(ss.B), D=[0,0]);
      Modelica_LinearSystems2.StateSpace ssPlant=StateSpace(A=ss.A, B=ss.B,C=[1,0,0,0;0,1,0,0], D=[0;0]);

    algorithm
      print("The linearized state space system is determined to:\n" + String(ssPlant));

     // eigenvalues of open loop system
      p := Modelica_LinearSystems2.Math.Complex.eigenValues(ss.A);
      print("eigenvalues of the open loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev", p);

    //####### POLE ASSIGNMENT ##########

    // feedback matrix of a pole assignment controller with assigned eigenvalues pa
      (K_pa,,p) := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss, pa);
      ss_pa.A := ss.A - ss.B*K_pa;
      print("The feedback matrix of the pole assignment controller is:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        K_pa,
        6,
        "K_pa"));
      print("eigenvalues of the closed loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev_pa", p);

      writeMatrix(
        fileName,
        "K_pa",
        K_pa,
        false);

    // Pre filter calculation
      M_pa := -Modelica.Math.Matrices.inv([1,0,0,0]*Matrices.solve2(ss_pa.A, ss_pa.B));
      print("Gain for pre filtering:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        M_pa,
        6,
        "M_pa"));
      writeMatrix(
        fileName,
        "M_pa",
        M_pa,
        true);

    // observer feedback
      (K_ob,,p) := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss_ob, pob);
      K_ob := transpose(K_ob);

      writeMatrix(
        fileName,
        "stateSpace",
        [ssPlant.A,ssPlant.B; ssPlant.C,ssPlant.D],
        true);
    // write matrix dimension nx
      writeMatrix(
        fileName,
        "nx",
        [size(ssPlant.A,1)],
        true);
      print("The feedback matrix of the observer system is:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        K_ob,
        6,
        "K_ob"));
      ss_ob.A := ss.A - K_ob*ssPlant.C;

      print("eigenvalues of the observer system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev_pob", pob);
      writeMatrix(
        fileName,
        "K_ob",
        K_ob,
        true);

      print("\nok!");
    end designCraneControllerWithObserver;

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.designInverseDoublePendulumController

Design pole assignment for an inverse double pedulum

### Information

This example demonstrates how to design pole placement controller to balance an inverted double pendulum. For controller design a linearized model of a (simple) physical system model is used. The controller is applied to the physical model in Moldelica_Controller library.
It is also shown how to linearize a modelica model. The linear model is used as a base for control design

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | modelName | "Modelica_Controller.Example... | name of the model to linearize
Complex | pa[6] | {Complex(-2, 0),Complex(-2, ... | assigned poles
String | fileName | DataDir + "inverseDoublePend... | file name for results

### Outputs

Type | Name | Description
--- | --- | ---
Real | K_pa[:, :] | feedback matrix pole assigment controller
Real | M_pa[:, :] | pre filter LQ controller

### Modelica definition

    function designInverseDoublePendulumController
      "Design pole assignment for an inverse double pedulum"

      import Modelica.Utilities.Streams.print;
      import Modelica_LinearSystems2;
      import Modelica_LinearSystems2.Math.Complex;
      import Modelica_LinearSystems2.Math.Matrices;
      import Modelica_LinearSystems2.StateSpace;

     input String modelName="Modelica_Controller.Examples.Components.InverseDoublePendulum"
        "name of the model to linearize";

    //   input Complex pa[6]={Complex(-2), -2+0*j, -6-0.2*j,-6+0.2*j,-6-0.2*j,-6+0.2*j}
    //      "assigned poles";

    input Complex pa[6]={Complex(-2,0), Complex(-2,0), Complex(-15,-0.2),Complex(-15,0.2),Complex(-20,-0),Complex(-20,0)}
        "assigned poles";

    //  input Complex pob[6]=fill(-10+0*j,6) "assigned observer poles";

     input String fileName=DataDir + "inverseDoublePendulumController.mat"
        "file name for results";

     output Real K_pa[:,:] "feedback matrix pole assigment controller";
     output Real M_pa[:,:] "pre filter LQ controller";

    // output Real K_ob[:,:] "feedback matrix pole assigment controller";

    protected
     input Complex j = Modelica_LinearSystems2.Math.Complex.j();
    protected
     Real Q[:,:];
     Real R[:,:];
     Boolean isControllable;
     Boolean isObservable;

      // Determine linear System from Modelica_Controller.Examples.Components.InverseDoublePendulum.mo
     Modelica_LinearSystems2.StateSpace ss = Modelica_LinearSystems2.StateSpace.Import.fromModel(modelName);

     Complex p[:]=Modelica_LinearSystems2.Math.Complex.eigenValues(ss.A);
     Modelica_LinearSystems2.StateSpace ss_pa=ss;
    //  Modelica_LinearSystems2.StateSpace ss_ob=StateSpace(A=transpose(ss.A), B=transpose([1,0,0,0,0,0;0,0,1,0,0,0;0,0,0,0,1,0]), C=transpose(ss.B), D=fill(0,size(ss.B,2),3));
      Modelica_LinearSystems2.StateSpace ssPlant=Modelica_LinearSystems2.StateSpace(A=ss.A, B=ss.B,C=[1,0,0,0,0,0;0,0,1,0,0,0;0,0,0,0,1,0],D=zeros(3,size(ss.B,2)));

    algorithm
     ss.C:=identity(6);
    print("The linearized state space system is determined to:\n" + String(ss));
      Modelica_LinearSystems2.Math.Matrices.printMatrix(ss.C,6,"C");
     Modelica_LinearSystems2.Math.Matrices.printMatrix(ss.D,6,"D");

    StateSpace.Analysis.analysis(ssPlant,fileName="inverseDoublePendulum.html");

    isControllable := StateSpace.Analysis.isControllable(ssPlant);

      if isControllable then
          Modelica.Utilities.Streams.print("ssPlant is controllable");
        else
          Modelica.Utilities.Streams.print("ssPlant is not controllable");
        end if;
    isObservable := StateSpace.Analysis.isObservable(ssPlant);
      if isObservable then
          Modelica.Utilities.Streams.print("ssPlant is observable");
        else
          Modelica.Utilities.Streams.print("ssPlant is not observable");
        end if;

     print("The eigenvalues are:\n");
    Complex.Vectors.print("p",p);

      //####### POLE ASSIGNMENT ##########

      // feedback matrix of a pole assignment controller with assigned eigenvalues pa
      (K_pa,,p) := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss, pa);
      ss_pa.A := ss.A - ss.B*K_pa;

      print("The feedback matrix of the pole assignment controller is:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        K_pa,
        6,
        "K_pa"));
      print("eigenvalues of the closed loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev_pa", p);

      writeMatrix(
        fileName,
        "K_pa",
        K_pa,
        true);

      // Pre filter calculation
      M_pa := -Modelica.Math.Matrices.inv([1,0,0,0,0,0]*Matrices.solve2(ss_pa.A,
        ss_pa.B));
      print("Gain for pre filtering:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        M_pa,
        6,
        "M_pa"));
      writeMatrix(
        fileName,
        "M_pa",
        M_pa,
        true);

    //   K_ob := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss_ob, pob);
    //   K_ob := transpose(K_ob);
    //
    //   writeMatrix(
    //     fileName,
    //     "nx",
    //     [size(ssPlant.A,1)],
    //     true);
    //  writeMatrix(
    //     fileName,
    //     "stateSpace",
    //     [ssPlant.A,ssPlant.B; ssPlant.C,ssPlant.D],
    //     true);
    //
    //   writeMatrix(
    //     fileName,
    //     "K_ob",
    //     K_ob,
    //     true);

    //StateSpace.Analysis.analysis(ss_pa,fileName="inverseDoublePendulumControlled.html");

      print("\nok!");
    end designInverseDoublePendulumController;

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.designInverseDoublePendulumControllerWithObserver

Design pole assignment for an inverse double pedulum

### Information

This example demonstrates how to design pole placement controller to balance an inverted double pendulum. For controller design a linearized model of a (simple) physical system model is used. The controller is applied to the physical model in Moldelica_Controller library.
It is also shown how to linearize a modelica model. The linear model is used as a base for control design

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | modelName | "Modelica_Controller.Example... | name of the model to linearize
Complex | pa[6] | {Complex(-1, 0),Complex(-1, ... | assigned poles
Complex | pob[6] | cat(1, fill(-15 + 0*j, 4), f... | assigned observer poles
String | fileName | DataDir + "inverseDoublePend... | file name for results
Boolean | makeAnalysis | false |

### Outputs

Type | Name | Description
--- | --- | ---
Real | K_pa[:, :] | feedback matrix pole assigment controller
Real | M_pa[:, :] | pre filter LQ controller
Real | K_ob[:, :] | feedback matrix pole assigment controller

### Modelica definition

    function designInverseDoublePendulumControllerWithObserver
      "Design pole assignment for an inverse double pedulum"

      import Modelica.Utilities.Streams.print;
      import Modelica_LinearSystems2;
      import Modelica_LinearSystems2.Math.Complex;
      import Modelica_LinearSystems2.Math.Matrices;
      import Modelica_LinearSystems2.StateSpace;

     input String modelName="Modelica_Controller.Examples.Components.InverseDoublePendulum"
        "name of the model to linearize";

    //input Complex pa[6]={-1+0*j, -1+0*j, -6-0.2*j,-6+0.2*j,-6-0.2*j,-6+0.2*j}     "assigned poles";
    input Complex pa[6]={Complex(-1,0), Complex(-1,0), Complex(-12,-0.2),Complex(-12,0.2),Complex(-15,-0),Complex(-15,0)}
        "assigned poles";
      input Complex pob[6]=cat(1,fill(-15+0*j,4),fill(-20+0*j,2))
        "assigned observer poles";

     input String fileName=DataDir + "inverseDoublePendulumControllerO.mat"
        "file name for results";

      input Boolean makeAnalysis=false;

     output Real K_pa[:,:] "feedback matrix pole assigment controller";
     output Real M_pa[:,:] "pre filter LQ controller";
     output Real K_ob[:,:] "feedback matrix pole assigment controller";

    protected
     input Complex j = Modelica_LinearSystems2.Math.Complex.j();
    protected
     Real Q[:,:];
     Real R[:,:];
     Boolean isControllable;
     Boolean isObservable;

      // Determine linear System from Modelica_Controller.Examples.Components.InverseDoublePendulum.mo
     Modelica_LinearSystems2.StateSpace ss = Modelica_LinearSystems2.StateSpace.Import.fromModel(modelName);

     Complex p[:]=Modelica_LinearSystems2.Math.Complex.eigenValues(ss.A);
     Modelica_LinearSystems2.StateSpace ss_pa=ss;
    // Modelica_LinearSystems2.StateSpace ss_ob=StateSpace(A=transpose(ss.A), B=transpose([1,0,0,0,0,0;0,0,1,0,0,0]), C=transpose(ss.B), D=fill(0,size(ss.B,2),2));
    // Modelica_LinearSystems2.StateSpace ssPlant=Modelica_LinearSystems2.StateSpace(A=ss.A, B=ss.B,C=[1,0,0,0,0,0;0,0,1,0,0,0],D=zeros(2,size(ss.B,2)));

    // Observer with 3 meassurements
    //   Modelica_LinearSystems2.StateSpace ss_ob=StateSpace(A=transpose(ss.A), B=transpose([1,0,0,0,0,0;0,0,1,0,0,0;0,0,0,0,1,0]), C=transpose(ss.B), D=fill(0,size(ss.B,2),3));
    //   Modelica_LinearSystems2.StateSpace ssPlant=Modelica_LinearSystems2.StateSpace(A=ss.A, B=ss.B,C=[1,0,0,0,0,0;0,0,1,0,0,0;0,0,0,0,1,0],D=zeros(3,size(ss.B,2)));

    // Observer with 2 meassurements
      Modelica_LinearSystems2.StateSpace ss_ob=StateSpace(A=transpose(ss.A), B=transpose([1,0,0,0,0,0;0,0,1,0,0,0]), C=transpose(ss.B), D=fill(0,size(ss.B,2),2));
      Modelica_LinearSystems2.StateSpace ssPlant=Modelica_LinearSystems2.StateSpace(A=ss.A, B=ss.B,C=[1,0,0,0,0,0;0,0,1,0,0,0],D=zeros(2,size(ss.B,2)), yNames={"s","phi1"}, xNames=ss.xNames, uNames=ss.uNames);

    algorithm
     ss.C:=identity(6);
    print("The linearized state space system is determined to:\n" + String(ss));
      Modelica_LinearSystems2.Math.Matrices.printMatrix(ss.C,6,"C");
     Modelica_LinearSystems2.Math.Matrices.printMatrix(ss.D,6,"D");

    if makeAnalysis then
    StateSpace.Analysis.analysis(ssPlant,fileName="inverseDoublePendulum.html");
    end if;

    isControllable := StateSpace.Analysis.isControllable(ssPlant);

      if isControllable then
          Modelica.Utilities.Streams.print("ssPlant is controllable");
        else
          Modelica.Utilities.Streams.print("ssPlant is not controllable");
        end if;
    isObservable := StateSpace.Analysis.isObservable(ssPlant);
      if isObservable then
          Modelica.Utilities.Streams.print("ssPlant is observable");
        else
          Modelica.Utilities.Streams.print("ssPlant is not observable");
        end if;

     print("The eigenvalues are:\n");
    Complex.Vectors.print("p",p);

      //####### POLE ASSIGNMENT ##########

      // feedback matrix of a pole assignment controller with assigned eigenvalues pa
      (K_pa,,p) := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss, pa);
      ss_pa.A := ss.A - ss.B*K_pa;

      print("The feedback matrix of the pole assignment controller is:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        K_pa,
        6,
        "K_pa"));
      print("eigenvalues of the closed loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev_pa", p);

      writeMatrix(
        fileName,
        "K_pa",
        K_pa,
        true);

      // Pre filter calculation
      M_pa := -Modelica.Math.Matrices.inv([1,0,0,0,0,0]*Matrices.solve2(ss_pa.A,
        ss_pa.B));
      print("Gain for pre filtering:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        M_pa,
        6,
        "M_pa"));
      writeMatrix(
        fileName,
        "M_pa",
        M_pa,
        true);

      K_ob := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss_ob, pob);
      K_ob := transpose(K_ob);

      writeMatrix(
        fileName,
        "nx",
        [size(ssPlant.A,1)],
        true);
     writeMatrix(
        fileName,
        "stateSpace",
        [ssPlant.A,ssPlant.B; ssPlant.C,ssPlant.D],
        true);

      writeMatrix(
        fileName,
        "K_ob2",
        K_ob,
        true);

    if makeAnalysis then
    StateSpace.Analysis.analysis(ss_pa,fileName="inverseDoublePendulumControlled.html");
    end if;
      print("\nok!");
    end designInverseDoublePendulumControllerWithObserver;

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.designInversePendulumController

Design pole assignment for an inverse pedulum

### Information

This example demonstrates how to design pole placement controller to balance an inverted pendulum. For controller design a linearized model of a (simple) physical system model is used. The controller is applied to the physical model in Moldelica_Controller library.
It is also shown how to linearize a modelica model. The linear model is used as a base for control design

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
String | modelName | "Modelica_Controller.Example... | name of the model to linearize
Complex | pa[4] | {-5 + 0*j,-5 + 0*j,-5.0 - 0.... | assigned poles
String | fileName | DataDir + "inversePendulumCo... | file name for results

### Outputs

Type | Name | Description
--- | --- | ---
Real | K_pa[:, :] | feedback matrix pole assigment controller
Real | M_pa[:, :] | pre filter LQ controller

### Modelica definition

    function designInversePendulumController
      "Design pole assignment for an inverse pedulum"

      import Modelica.Utilities.Streams.print;
      import Modelica_LinearSystems2;
      import Modelica_LinearSystems2.Math.Complex;
      import Modelica_LinearSystems2.Math.Matrices;

      input String modelName="Modelica_Controller.Examples.Components.InversePendulum_small"
        "name of the model to linearize";
       input Complex pa[4]={-5+0*j,-5+0*j,-5.0-0.25*j,-5.0+0.25*j} "assigned poles";

      input String fileName=DataDir + "inversePendulumController_small.mat"
        "file name for results";
    protected
       input Complex j = Modelica_LinearSystems2.Math.Complex.j();
    public
      output Real K_pa[:,:] "feedback matrix pole assigment controller";
      output Real M_pa[:,:] "pre filter LQ controller";
    // Determine linear System from Modelica_Controller.Examples.Pendulum.mo
    protected
      Modelica_LinearSystems2.StateSpace ss = Modelica_LinearSystems2.StateSpace.Import.fromModel(modelName);

      Complex p[:]=Modelica_LinearSystems2.Math.Complex.eigenValues(ss.A);

      Modelica_LinearSystems2.StateSpace ss_pa=ss;

    algorithm
      print("The linearized state space system is determined to:\n" +String(ss));

    //####### POLE ASSIGNMENT ##########

    // feedback matrix of a pole assignment controller with assigned eigenvalues pa
      (K_pa,,p) := Modelica_LinearSystems2.StateSpace.Design.assignPolesMI(ss, pa);
      ss_pa.A := ss.A - ss.B*K_pa;

      print("The feedback matrix of the pole assignment controller is:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        K_pa,
        6,
        "K_pa"));
      print("eigenvalues of the closed loop system are:\n");
      Modelica_LinearSystems2.Math.Complex.Vectors.print("ev_pa", p);
      writeMatrix(
       fileName,
        "K_pa",
        K_pa,
        true);

    // Pre filter calculation
      M_pa := -Modelica.Math.Matrices.inv([1,0,0,0]*Matrices.solve2(ss_pa.A, ss_pa.B));
      print("Gain for pre filtering:\n" +
        Modelica_LinearSystems2.Math.Matrices.printMatrix(
        M_pa,
        6,
        "M_pa"));
      writeMatrix(
       fileName,
        "M_pa",
        M_pa,
        true);

      print("\nok!");
    end designInversePendulumController;

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.designStateSpaceController

Demonstration of controller design for a state space system

### Information

This example demonstrates how to design a lq-controller or a pole placement controller respectively. Compared with example craneController, the plant is smaller to achieve suitable dynamics for animation. The feedback matrices and a simple pre filter for tracking are save to MATLAB files which can be used in ModelicaController library.
It is also shown how to linearize a model of a crane trolley system [1]. The linear model is used as a base for control design

References

      [1] Föllinger, O. "Regelungstechnik", Hüthig-Verlag

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
StateSpace | ss | StateSpace(A=[0, 1, 0, 0; 0,... |
Complex | pa[:] | {Complex(-1, 0),Complex(-2, ... | assigned poles

### Outputs

Type | Name | Description
--- | --- | ---
Real | K_pa[:, :] | feedback matrix pole assigment controller
Real | M_pa[:, :] | pre filter pole assignment controller
Complex | po[size(ss.A, 1)] |

### Modelica definition

    function designStateSpaceController
      "Demonstration of controller design for a state space system"
      import Modelica.Utilities.Streams.print;
      import Modelica_LinearSystems2;
      import Modelica_LinearSystems2.Math.Complex;
      import Modelica_LinearSystems2.Math.Matrices;
      import Modelica_LinearSystems2.TransferFunction;
      import Modelica_LinearSystems2.ZerosAndPoles;
      import Modelica_LinearSystems2.StateSpace;

      input StateSpace ss=StateSpace(
          A=[0,1,0,0; 0,0,39.2,0; 0,0,0,1; 0,0,-49.0,0],
          B=[1,1,0,0;0,1,1,0;0,0,1,1;1,1,1,1],
          C=identity(4),
          D=zeros(4,4),
          yNames={"s","v","phi","w"},
          uNames={"f","u2","u3","u4"},
          xNames={"s","v","phi","w"});

       input Complex pa[:]={Complex(-1,0),Complex(-2,0),Complex(-2, -0.2),Complex(-2,0.2)}
        "assigned poles";

      output Real K_pa[:,:] "feedback matrix pole assigment controller";
      output Real M_pa[:,:] "pre filter pole assignment controller";
      output Complex po[size(ss.A,1)];

    protected
      Complex assignedPoles[:]=pa;
      StateSpace ss_pa=ss;

    algorithm
    //####### POLE ASSIGNMENT ##########
    // return the Schur form representation
      (,,po) := StateSpace.Design.assignPolesMI2(ss,assignedPoles,size(assignedPoles,1),true);
      Complex.Vectors.print("poSchur", po);
      StateSpace.Analysis.analysis(ss,fileName="openloopSystem.html");

    // feedback matrix of a pole assignment controller with assigned eigenvalues pa
      (K_pa,,po) := StateSpace.Design.assignPolesMI2(ss, assignedPoles);
      ss_pa.A := ss.A - ss.B*K_pa;
      StateSpace.Analysis.analysis(ss_pa,fileName="closedloopSystem.html");
      print("The feedback matrix of the pole assignment controller is:\n" +
        Matrices.printMatrix(K_pa, 6, "K_pa"));
      print("eigenvalues of the closed loop system are:\n");
      Complex.Vectors.print("ev_pa", po);
    // Pre filter calculation
    //   M_pa := -Modelica.Math.Matrices.inv([1,0,0,0;0,0,1,0]*Matrices.solve2(ss_pa.A, ss_pa.B));
    //   print("Gain for pre filtering:\n" +
    //     Matrices.printMatrix(M_pa, 6, "M_pa"));

      assignedPoles := Complex.Vectors.reverse(assignedPoles);
      assignedPoles[3]:=Complex(-1);
      assignedPoles[4]:=Complex(-2);
    // feedback matrix of a pole assignment controller with assigned eigenvalues pa
      (K_pa,,po) := StateSpace.Design.assignPolesMI2(ss, assignedPoles);
      ss_pa.A := ss.A - ss.B*K_pa;
      StateSpace.Analysis.analysis(ss_pa,fileName="closedloopSystem2.html");
      print("The feedback matrix of the pole assignment controller is:\n" +
        Matrices.printMatrix(K_pa, 6, "K_pa"));
      print("eigenvalues of the closed loop system are:\n");
      Complex.Vectors.print("ev_pa", po);
    // Pre filter calculation
    //   M_pa := -Modelica.Math.Matrices.inv([1,0,0,0;0,0,1,0]*Matrices.solve2(ss_pa.A, ss_pa.B));
    //   print("Gain for pre filtering:\n" +
    //     Matrices.printMatrix(M_pa, 6, "M_pa"));

      print("\nok!");
    end designStateSpaceController;

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.analysis2

Example to check controllability of a state space system

### Information

This example shows the usage of function Modelica_LinearSystems2.StateSpace.Analysis.isControllable which is to check whether a system is controllable or not.

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
StateSpace | ssi | Modelica_LinearSystems2.Stat... |
AnalyseOptions | analyseOptions | Modelica_LinearSystems2.Inte... |
system data definition
Boolean | systemOnFile | false | true, if state space system is defined on file
String | fileName | "NoName" | file where matrix [A, B; C, D] is stored
String | matrixName | "ABCD" | Name of the state space system matrix

### Outputs

Type | Name | Description
--- | --- | ---
Boolean | ok |

### Modelica definition

    function analysis2
      "Example to check controllability of a state space system"
      import Modelica_LinearSystems2;
      import Modelica_LinearSystems2.StateSpace;
      import Modelica_LinearSystems2.Math.Complex;
      import Re = Modelica_LinearSystems2.Math.Complex.real;
      import Im = Modelica_LinearSystems2.Math.Complex.imag;

      input StateSpace ssi=Modelica_LinearSystems2.StateSpace(
          A=[-6.0,0,2,-13.0; -9.0,-12.0,-3.25,19.25; 0,0,1,34.0; 0,0,-34.0,-31.0]/6,
          B=[1; 1; 1; 1],
          C=identity(4),
          D=zeros(4, 1),
          xNames={"x1","x2","x3","x4"},
          uNames={"u"},
          yNames={"y1","y2","y3","y4"});
      input Modelica_LinearSystems2.Internal.AnalyseOptions analyseOptions=
          Modelica_LinearSystems2.Internal.AnalyseOptions(
          plotEigenValues=true,
          plotInvariantZeros=true,
          plotStepResponse=true,
          plotFrequencyResponse=false,
          printEigenValues=true,
          printEigenValueProperties=true,
          printInvariantZeros=true,
          printControllability=false,
          printObservability=false,
          headingEigenValues="Eigenvalues",
          headingInvariantzeros="Invariant zeros",
          headingStepResponse="Step response",
          headingFrequencyResponse="Frequency response");

      input Boolean systemOnFile=false
        "true, if state space system is defined on file";
      input String fileName="NoName" "file where matrix [A, B; C, D] is stored";
      input String matrixName="ABCD" "Name of the state space system matrix";

      output Boolean ok;

    protected
      StateSpace ss=if systemOnFile then Modelica_LinearSystems2.StateSpace.Import.fromFile(fileName) else ssi;
      StateSpace ssModal=ss;
      Complex ceigvec[4,4] "complex eigen values of the system";

      Complex T[4,4]=fill(Complex(0),4,4);
      Complex Vs[4,4];
      Real VsRe[4,4];
      Real Lambda[4,4];
      Real eigvec[4,4] "eigen values of the system";
      Real eigvecRe[4,4]=fill(0, 4, 4) "eigen values of the system";
      Real eigvecIm[4,4]=fill(0, 4, 4) "eigen values of the system";
      Complex eigval[4]=fill(Complex(0), 4);
      Complex j= Modelica_LinearSystems2.Math.Complex.j();
      Complex Tp[2,2]=sqrt(0.5)*[1+0*j, -j; 1+0*j, j];
      Integer i;

      Real x0[size(ss.A, 1)]=ones(size(ss.A, 1)) "Initial state vector";
      Real z0[size(ss.A, 1)]=ones(size(ss.A, 1)) "Initial state vector";

    algorithm
      ok := false;
      StateSpace.Analysis.analysis(ss, fileName="analysis.html", analyseOptions=analyseOptions, description="Description of the system");
      (eigvec,eigval) := Modelica_LinearSystems2.StateSpace.Analysis.eigenVectors(ss, false);
      Complex.Vectors.print("eval",eigval);
      Modelica_LinearSystems2.Math.Matrices.printMatrix(eigvec, 6, "leftEigenVectors");

      i := 1;
      while i <= 4 loop
        if abs(Im(eigval[i])) > 1e-12 then
          eigvecRe[:, i] := eigvec[:, i];
          eigvecIm[:, i] := eigvec[:, i + 1];
          eigvecRe[:, i + 1] := eigvec[:, i];
          eigvecIm[:, i + 1] := -eigvec[:, i + 1];
          T[i,i] := Tp[1,1];
          T[i,i+1] := Tp[1,2];
          T[i+1,i] := Tp[2,1];
          T[i+1,i+1] := Tp[2,2];
          i := i + 2;
        else
          eigvecRe[:, i] := eigvec[:, i];
          eigvecIm[:, i] := fill(0, 4);
          T[i,i] := Complex(1);
          i := i + 1;
        end if;
      end while;
      ceigvec := Complex(1)*eigvecRe + j*eigvecIm;
      Vs := ceigvec*T;
      VsRe := Re(Vs);
      Lambda:= Modelica.Math.Matrices.inv(VsRe)*ss.A*VsRe;

      ssModal.A := Lambda;
      ssModal.B := Modelica.Math.Matrices.solve2(VsRe,ss.B);
    //  ssModal.C := ss.C*VsRe;
      ssModal.C := ss.C;
      ssModal.D := ss.D;
      z0 := x0;//Modelica.Math.Matrices.solve(VsRe,x0);

      Modelica_LinearSystems2.Math.Matrices.printMatrix(Re(ceigvec), 6, "cevRe");
      Modelica_LinearSystems2.Math.Matrices.printMatrix(Im(ceigvec), 6, "cevIm");
      Modelica_LinearSystems2.Math.Matrices.printMatrix(Re(T), 6, "TRe");
      Modelica_LinearSystems2.Math.Matrices.printMatrix(Im(T), 6, "TIm");
      Modelica_LinearSystems2.Math.Matrices.printMatrix(Re(Vs), 6, "VsRe");
      Modelica_LinearSystems2.Math.Matrices.printMatrix(Im(Vs), 6, "VsIm");
      Modelica_LinearSystems2.Math.Matrices.printMatrix(Lambda, 6, "Lam");

      Modelica_LinearSystems2.StateSpace.Plot.initialResponse(ss=ss, tSpan=4, x0=x0, defaultDiagram=Modelica_LinearSystems2.Internal.DefaultDiagramTimeResponse(
            heading="Initial response system states"),subPlots=false);
      Modelica_LinearSystems2.StateSpace.Plot.initialResponse(ss=ssModal, tSpan=4, x0=z0, defaultDiagram=Modelica_LinearSystems2.Internal.DefaultDiagramTimeResponse(
            heading="Initial response modal states"),subPlots=false);

      ok := true;
    end analysis2;

## Modelica_LinearSystems2.WorkInProgress.StateSpace.Examples.plotBodeSISODiscrete

Plots the Bode diagram of continuous state space system and the corresponding discrete state space system and with automatic determination of the frequency range to plot

### Inputs

Type | Name | Default | Description
--- | --- | --- | ---
Boolean | systemOnFile | false | true, if state space system is defined on file
String | fileName | "NoName" | file where matrix [A, B; C, D] is stored
Real | A[:, size(A, 1)] | [-1.0, 0.0, 0.0; 0.0, -2.0, ... |
Real | B[size(A, 2), :] | [0.0, 1.0; 1.0, 1.0; -1.0, 0... |
Real | C[:, size(A, 1)] | [0.0, 1.0, 1.0; 1.0, 1.0, 1.0] |
Real | D[size(C, 1), size(B, 2)] | [1.0, 0.0; 0.0, 1.0] |
Time | Ts | 0.1 | Sample time [s]
Method | method | Modelica_LinearSystems2.Type... | Discretization method
Integer | iu | 1 | index of inout
Integer | iy | 1 | index of output

### Outputs

Type | Name | Description
--- | --- | ---
Boolean | ok |

### Modelica definition

    function plotBodeSISODiscrete
      "Plots the Bode diagram of continuous state space system and the corresponding discrete state space system and  with automatic determination of the frequency range to plot "

      import Modelica;
      import Modelica_LinearSystems2.StateSpace;
      import Modelica_LinearSystems2.WorkInProgress.DiscreteStateSpace;
      import Modelica_LinearSystems2.TransferFunction;

      input Boolean systemOnFile=false
        "true, if state space system is defined on file";
      input String fileName="NoName" "file where matrix [A, B; C, D] is stored";

      input Real A[:,size(A, 1)]=[-1.0,0.0,0.0; 0.0,-2.0,0.0; 0.0,0.0,-3.0];
      input Real B[size(A, 2),:]=[0.0,1.0; 1.0,1.0; -1.0,0.0];
      input Real C[:,size(A, 1)]=[0.0,1.0,1.0; 1.0,1.0,1.0];
      input Real D[size(C, 1),size(B, 2)]=[1.0,0.0; 0.0,1.0];

      input Modelica.SIunits.Time Ts = 0.1 "Sample time";
      input Modelica_LinearSystems2.Types.Method method=Modelica_LinearSystems2.Types.Method.StepExact
        "Discretization method";

      input Integer iu=1 "index of inout";
      input Integer iy=1 "index of output";
      output Boolean ok;

    protected
      StateSpace ss=if systemOnFile then Modelica_LinearSystems2.StateSpace.Import.fromFile(fileName) else
          StateSpace(A=A, B=B, C=C, D=D);

     Modelica_LinearSystems2.WorkInProgress.DiscreteStateSpace dss=
                            Modelica_LinearSystems2.WorkInProgress.DiscreteStateSpace(
                                               ss,Ts,method);

    algorithm
      assert(iu <= size(ss.B, 2) and iu > 0, "index for input is " + String(iu) +
        " which is not in [1, " + String(size(ss.B, 2)) + "].");
      assert(iy <= size(ss.C, 1) and iy > 0, "index for output is " + String(iy) +
        " which is not in [1, " + String(size(ss.C, 1)) + "].");

      Modelica_LinearSystems2.StateSpace.Plot.bodeSISO(
        ss,
        iu,
        iy);
      Modelica_LinearSystems2.DiscreteStateSpace.Plot.bodeSISO(
        dss,
        iu,
        iy);
      ok := true;

    end plotBodeSISODiscrete;