VoltageController

model VoltageController "Voltage controller"
    import Modelica.Constants.pi;

    constant Integer m = 3 "Number of phases";
    parameter Integer p "Number of pole pairs";
    parameter Modelica.SIunits.Frequency fsNominal "Nominal frequency";
    parameter Modelica.SIunits.Voltage VsOpenCircuit "Open circuit RMS voltage per phase @ fsNominal";
    parameter Modelica.SIunits.Resistance Rs "Stator resistance per phase";
    parameter Modelica.SIunits.Inductance Ld "Inductance in d-axis";
    parameter Modelica.SIunits.Inductance Lq "Inductance in q-axis";
    parameter Boolean decoupling = false "Use decoupling network";
    final parameter Modelica.SIunits.MagneticFlux psiM = sqrt(2) * VsOpenCircuit / (2 * pi * fsNominal);
    Modelica.SIunits.AngularVelocity omega = p * der(phi);
    Modelica.SIunits.Voltage Vd = sqrt(2) * (Rs * id_rms - omega * Lq * iq_rms);
    Modelica.SIunits.Voltage Vq = sqrt(2) * (Rs * iq_rms + omega * Ld * id_rms) + omega * psiM;

    extends Modelica.Blocks.Interfaces.MO(final nout = m);

    Modelica.Blocks.Interfaces.RealInput id_rms annotation (Placement(transformation(extent = {
        {-140, 40}, 
        {-100, 80}})));
    Modelica.Blocks.Interfaces.RealInput iq_rms annotation (Placement(transformation(extent = {
        {-140, -80}, 
        {-100, -40}})));
    Modelica.Blocks.Interfaces.RealInput phi(unit = "rad") annotation (Placement(transformation(
        origin = {60, -120},
        extent = {
            {20, -20}, 
            {-20, 20}},
        rotation = 270)));
    Modelica.Blocks.Interfaces.RealInput iActual[m] annotation (Placement(transformation(
        origin = {-60, -120},
        extent = {
            {20, -20}, 
            {-20, 20}},
        rotation = 270)));
    Machines.Utilities.FromDQ fromDQ(final p = p, final m = m) annotation (Placement(transformation(extent = {
        {70, -10}, 
        {90, 10}})));
    Machines.Utilities.ToDQ toDQ(final p = p, final m = m) annotation (Placement(transformation(
        extent = {
            {-10, -10}, 
            {10, 10}},
        rotation = 90,
        origin = {-60, -80})));
    Modelica.Blocks.Math.Gain toPeak_d(final k = sqrt(2)) annotation (Placement(transformation(
        extent = {
            {-10, -10}, 
            {10, 10}},
        origin = {-70, 60})));
    Modelica.Blocks.Math.Gain toPeak_q(final k = sqrt(2)) annotation (Placement(transformation(
        extent = {
            {-10, -10}, 
            {10, 10}},
        origin = {-70, 0})));
    Modelica.Blocks.Math.Feedback feedback_d annotation (Placement(transformation(extent = {
        {-38, 50}, 
        {-18, 70}})));
    Modelica.Blocks.Math.Feedback feedback_q annotation (Placement(transformation(extent = {
        {-40, -10}, 
        {-20, 10}})));
    Modelica.Blocks.Continuous.PI PI_d(final k = unitResistance / Rs, final T = Ld / Rs, initType = Modelica.Blocks.Types.Init.InitialOutput) annotation (Placement(transformation(extent = {
        {-10, 50}, 
        {10, 70}})));
    Modelica.Blocks.Continuous.PI PI_q(final k = unitResistance / Rs, final T = Lq / Rs, initType = Modelica.Blocks.Types.Init.InitialOutput) annotation (Placement(transformation(extent = {
        {-10, -10}, 
        {10, 10}})));
    Modelica.Blocks.Math.Add add[2](final k1 = fill(1, 2), final k2 = fill(if decoupling then 1 else 0, 2)) annotation (Placement(transformation(extent = {
        {32, -10}, 
        {52, 10}})));
    Modelica.Blocks.Sources.RealExpression deCoupling[2](y = {Vd, Vq}) annotation (Placement(transformation(extent = {
        {-10, -40}, 
        {10, -20}})));
protected
    constant Modelica.SIunits.Resistance unitResistance = 1 annotation (HideResult = true);
equation
    connect(iActual,toDQ.u) annotation (Line(
        points = {
            {-60, -120}, 
            {-60, -92}},
        color = {0, 0, 127}));
    connect(phi,fromDQ.phi) annotation (Line(
        points = {
            {60, -120}, 
            {60, -80}, 
            {80, -80}, 
            {80, -12}},
        color = {0, 0, 127}));
    connect(phi,toDQ.phi) annotation (Line(
        points = {
            {60, -120}, 
            {60, -80}, 
            {-48, -80}},
        color = {0, 0, 127}));
    connect(PI_d.y,add[1].u1) annotation (Line(
        points = {
            {11, 60}, 
            {20, 60}, 
            {20, 6}, 
            {30, 6}},
        color = {0, 0, 127}));
    connect(PI_q.y,add[2].u1) annotation (Line(
        points = {
            {11, 0}, 
            {20, 0}, 
            {20, 6}, 
            {30, 6}},
        color = {0, 0, 127}));
    connect(add.y,fromDQ.u) annotation (Line(
        points = {
            {53, 0}, 
            {68, 0}},
        color = {0, 0, 127}));
    connect(fromDQ.y,y) annotation (Line(
        points = {
            {91, 0}, 
            {110, 0}},
        color = {0, 0, 127}));
    connect(toDQ.y[1],feedback_d.u2) annotation (Line(
        points = {
            {-60, -69}, 
            {-60, -60}, 
            {-50, -60}, 
            {-50, 40}, 
            {-28, 40}, 
            {-28, 52}},
        color = {0, 0, 127}));
    connect(toDQ.y[2],feedback_q.u2) annotation (Line(
        points = {
            {-60, -69}, 
            {-60, -60}, 
            {-50, -60}, 
            {-50, -20}, 
            {-30, -20}, 
            {-30, -8}},
        color = {0, 0, 127}));
    connect(toPeak_d.u,id_rms) annotation (Line(
        points = {
            {-82, 60}, 
            {-120, 60}},
        color = {0, 0, 127}));
    connect(toPeak_d.y,feedback_d.u1) annotation (Line(
        points = {
            {-59, 60}, 
            {-36, 60}},
        color = {0, 0, 127}));
    connect(toPeak_q.u,iq_rms) annotation (Line(
        points = {
            {-82, 0}, 
            {-90, 0}, 
            {-90, -60}, 
            {-120, -60}},
        color = {0, 0, 127}));
    connect(toPeak_q.y,feedback_q.u1) annotation (Line(
        points = {
            {-59, 0}, 
            {-38, 0}},
        color = {0, 0, 127}));
    connect(deCoupling.y,add.u2) annotation (Line(
        points = {
            {11, -30}, 
            {20, -30}, 
            {20, -6}, 
            {30, -6}},
        color = {0, 0, 127}));
    connect(feedback_d.y,PI_d.u) annotation (Line(
        points = {
            {-19, 60}, 
            {-12, 60}},
        color = {0, 0, 127}));
    connect(feedback_q.y,PI_q.u) annotation (Line(
        points = {
            {-21, 0}, 
            {-12, 0}},
        color = {0, 0, 127}));

    annotation (
        Icon(graphics = {
            Text(
                extent = {
                    {-100, 60}, 
                    {20, 40}},
                lineColor = {0, 0, 255},
                textString = "id_rms"), 
            Text(
                extent = {
                    {-100, -40}, 
                    {20, -60}},
                lineColor = {0, 0, 255},
                textString = "iq_rms")}),
        Documentation(info = "<html>\n<p>\nSimple Voltage-Controller\n</p>\n<p>\nThe desired rms values of d- and q-component of the space phasor current in rotor fixed coordinate system are given by inputs \"id_rms\" and \"iq_rms\".\nUsing the given rotor position (input \"phi\"), the actual threephase currents are measured and transformed to the d-q coordinate system.\nTwo PI-controller determine the necessary d- and q- voltages, which are transformed back to threephase (output \"y[3]\").\nThey can be used to feed a voltage source which in turn feeds a permanent magnet synchronous machine.\n</p>\n<p>\nNote: No care is taken for current or voltage limiting, as well as for field weakening.\n</p>\n</html>"));
end VoltageController;