|
| 1 | +within OpenIPSL.Electrical.Solar.PowerFactory.WECC.PVD1; |
| 2 | + |
| 3 | +model Controller |
| 4 | + parameter Types.PerUnit Imax = 1.1 "Maximum allowable total converter current"; |
| 5 | + parameter Boolean PqFlag "Priority on current limit flag: 1=P prio.; 0 = Q prio."; |
| 6 | + parameter Types.Time Tg = 0.02 "Inverter current regulator time constat"; |
| 7 | + parameter Types.PerUnit Xc = 0 "Line drop compensation reactance"; |
| 8 | + parameter Types.PerUnit Qmx = 0.328 "Maximum reactive power"; |
| 9 | + parameter Types.PerUnit Qmn = -0.328 "Minimum reactive power"; |
| 10 | + parameter Types.PerUnit v0 = 0.9 "Low voltage threshold for Volt/Var Control"; |
| 11 | + parameter Types.PerUnit v1 = 1.1 "High voltage threshold for Volt/Var Control"; |
| 12 | + parameter Real dqdv = 0 "Voltage/Var droop compensation"; |
| 13 | + parameter Types.PerUnit fdbd = -99 "Frequency deadband over frequency response"; |
| 14 | + parameter Real Ddn = 0 "Down regulation droop"; |
| 15 | + parameter Real vr_recov = 1 "Amount of generation to reconnect after voltage disconnection"; |
| 16 | + parameter Real fr_recov = 1 "Amount of generation to reconnect after frequency disconnection"; |
| 17 | + parameter Types.PerUnit Ft0 = 0.99 "Frequency tripping repose curve point 0"; |
| 18 | + parameter Types.PerUnit Ft1 = 0.995 "Frequency tripping repose curve point 1"; |
| 19 | + parameter Types.PerUnit Ft2 = 1.005 "Frequency tripping repose curve point 2"; |
| 20 | + parameter Types.PerUnit Ft3 = 1.01 "Frequency tripping repose curve point 2"; |
| 21 | + parameter Types.PerUnit Vt0 = 0.88 "Voltage tripping repose curve point 0"; |
| 22 | + parameter Types.PerUnit Vt1 = 0.9 "Voltage tripping repose curve point 1"; |
| 23 | + parameter Types.PerUnit Vt2 = 1.1 "Voltage tripping repose curve point 2"; |
| 24 | + parameter Types.PerUnit Vt3 = 1.2 "Voltage tripping repose curve point 3"; |
| 25 | + Modelica.Blocks.Interfaces.RealInput Vt annotation( |
| 26 | + Placement(visible = true, transformation(origin = {-200, -10}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, 140}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); |
| 27 | + Modelica.Blocks.Interfaces.RealInput It annotation( |
| 28 | + Placement(visible = true, transformation(origin = {-200, -70}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, 60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); |
| 29 | + Modelica.Blocks.Math.Gain compensation(k = Xc) annotation( |
| 30 | + Placement(visible = true, transformation(origin = {-150, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 31 | + Modelica.Blocks.Math.Add add annotation( |
| 32 | + Placement(visible = true, transformation(origin = {-110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 33 | + Modelica.Blocks.Nonlinear.Limiter numerical_limit(limitsAtInit = true, uMax = Modelica.Constants.inf, uMin = 0.01) annotation( |
| 34 | + Placement(visible = true, transformation(origin = {-70, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 35 | + Modelica.Blocks.Math.Division division annotation( |
| 36 | + Placement(visible = true, transformation(origin = {90, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 37 | + OpenIPSL.Electrical.Solar.PowerFactory.WECC.PVD1.QPPriority qppriority(Imax = Imax, PqFlag = PqFlag) annotation( |
| 38 | + Placement(visible = true, transformation(origin = {130, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 39 | + Modelica.Blocks.Math.Division division1 annotation( |
| 40 | + Placement(visible = true, transformation(origin = {90, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 41 | + Modelica.Blocks.Continuous.FirstOrder PCurrentController(T = Tg, initType = Modelica.Blocks.Types.Init.InitialOutput, k = 1, y_start = Pref / u_0) annotation( |
| 42 | + Placement(visible = true, transformation(origin = {182, 90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 43 | + Modelica.Blocks.Continuous.FirstOrder QCurrentController(T = Tg, initType = Modelica.Blocks.Types.Init.InitialOutput, k = -1, y_start = -Qref / u_0) annotation( |
| 44 | + Placement(visible = true, transformation(origin = {182, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 45 | + Modelica.Blocks.Interfaces.RealInput freq annotation( |
| 46 | + Placement(visible = true, transformation(origin = {-200, 150}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {-200, -60}, extent = {{-20, -20}, {20, 20}}, rotation = 0))); |
| 47 | + Modelica.Blocks.Sources.Constant freq_ref(k = 1) annotation( |
| 48 | + Placement(visible = true, transformation(origin = {-182, 110}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 49 | + Modelica.Blocks.Math.Add add2(k1 = -1) annotation( |
| 50 | + Placement(visible = true, transformation(origin = {-130, 144}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 51 | + Modelica.Blocks.Nonlinear.DeadZone deadZone(deadZoneAtInit = true, uMax = Modelica.Constants.inf, uMin = fdbd) annotation( |
| 52 | + Placement(visible = true, transformation(origin = {-90, 144}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 53 | + Modelica.Blocks.Math.Gain frequency_droop(k = Ddn) annotation( |
| 54 | + Placement(visible = true, transformation(origin = {-50, 144}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 55 | + Modelica.Blocks.Sources.Constant active_power_reference(k = Pref) annotation( |
| 56 | + Placement(visible = true, transformation(origin = {-150, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 57 | + Modelica.Blocks.Nonlinear.DeadZone deadband_voltage(deadZoneAtInit = true, uMax = v1, uMin = v0) annotation( |
| 58 | + Placement(visible = true, transformation(origin = {-70, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 59 | + Modelica.Blocks.Math.Gain voltage_droop(k = dqdv) annotation( |
| 60 | + Placement(visible = true, transformation(origin = {-30, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 61 | + Modelica.Blocks.Nonlinear.Limiter limiter(limitsAtInit = true, uMax = Qmx, uMin = Qmn) annotation( |
| 62 | + Placement(visible = true, transformation(origin = {50, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 63 | + Modelica.Blocks.Math.Add add1 annotation( |
| 64 | + Placement(visible = true, transformation(origin = {14, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 65 | + Modelica.Blocks.Sources.Constant reactive_power_reference(k = Qref) annotation( |
| 66 | + Placement(visible = true, transformation(origin = {-70, -110}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 67 | + Modelica.Blocks.Interfaces.RealOutput Ip annotation( |
| 68 | + Placement(visible = true, transformation(origin = {210, 90}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {210, 110}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 69 | + Modelica.Blocks.Interfaces.RealOutput Iq annotation( |
| 70 | + Placement(visible = true, transformation(origin = {210, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {210, -90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 71 | + Modelica.Blocks.Math.Add add4 annotation( |
| 72 | + Placement(visible = true, transformation(origin = {-50, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 73 | + parameter Types.PerUnit Qref; |
| 74 | + parameter Types.PerUnit Pref; |
| 75 | + parameter Types.PerUnit u_0; |
| 76 | + Modelica.Blocks.Math.Product product1 annotation( |
| 77 | + Placement(visible = true, transformation(origin = {150, 90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 78 | + Modelica.Blocks.Math.Product product annotation( |
| 79 | + Placement(visible = true, transformation(origin = {70, 150}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 80 | + OpenIPSL.Electrical.Solar.PowerFactory.WECC.PVD1.GenerationTripping frequency_tripping(Lv0 = Ft0, Lv1 = Ft1, Lv2 = Ft2, Lv3 = Ft3, recov = fr_recov) annotation( |
| 81 | + Placement(visible = true, transformation(origin = {30, 150}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 82 | + OpenIPSL.Electrical.Solar.PowerFactory.WECC.PVD1.GenerationTripping voltage_tripping(Lv0 = Vt0, Lv1 = Vt1, Lv2 = Vt2, Lv3 = Vt3, recov = vr_recov) annotation( |
| 83 | + Placement(visible = true, transformation(origin = {30, 110}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 84 | + Modelica.Blocks.Math.Product product2 annotation( |
| 85 | + Placement(visible = true, transformation(origin = {70, 110}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 86 | + Modelica.Blocks.Math.Product product3 annotation( |
| 87 | + Placement(visible = true, transformation(origin = {110, 130}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 88 | + Modelica.Blocks.Math.Product product4 annotation( |
| 89 | + Placement(visible = true, transformation(origin = {150, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); |
| 90 | +equation |
| 91 | + connect(It, compensation.u) annotation( |
| 92 | + Line(points = {{-200, -70}, {-162, -70}}, color = {0, 0, 127})); |
| 93 | + connect(compensation.y, add.u2) annotation( |
| 94 | + Line(points = {{-139, -70}, {-130.5, -70}, {-130.5, -76}, {-122, -76}}, color = {0, 0, 127})); |
| 95 | + connect(Vt, add.u1) annotation( |
| 96 | + Line(points = {{-200, -10}, {-128, -10}, {-128, -63}, {-122, -63}, {-122, -64}}, color = {0, 0, 127})); |
| 97 | + connect(numerical_limit.u, Vt) annotation( |
| 98 | + Line(points = {{-82, -10}, {-200, -10}}, color = {0, 0, 127})); |
| 99 | + connect(numerical_limit.y, division.u2) annotation( |
| 100 | + Line(points = {{-59, -10}, {-8, -10}, {-8, -36}, {78, -36}}, color = {0, 0, 127})); |
| 101 | + connect(division.y, qppriority.Iq) annotation( |
| 102 | + Line(points = {{101, -30}, {106, -30}, {106, -5}, {120, -5}}, color = {0, 0, 127})); |
| 103 | + connect(division1.u2, numerical_limit.y) annotation( |
| 104 | + Line(points = {{78, 24}, {-8, 24}, {-8, -10}, {-59, -10}}, color = {0, 0, 127})); |
| 105 | + connect(division1.y, qppriority.Ip) annotation( |
| 106 | + Line(points = {{101, 30}, {106, 30}, {106, 5}, {120, 5}}, color = {0, 0, 127})); |
| 107 | + connect(freq, add2.u1) annotation( |
| 108 | + Line(points = {{-200, 150}, {-142, 150}}, color = {0, 0, 127})); |
| 109 | + connect(deadZone.y, frequency_droop.u) annotation( |
| 110 | + Line(points = {{-79, 144}, {-62, 144}}, color = {0, 0, 127})); |
| 111 | + connect(freq_ref.y, add2.u2) annotation( |
| 112 | + Line(points = {{-171, 110}, {-160, 110}, {-160, 138}, {-142, 138}}, color = {0, 0, 127})); |
| 113 | + connect(add2.y, deadZone.u) annotation( |
| 114 | + Line(points = {{-119, 144}, {-102, 144}}, color = {0, 0, 127})); |
| 115 | + connect(add.y, deadband_voltage.u) annotation( |
| 116 | + Line(points = {{-99, -70}, {-82, -70}}, color = {0, 0, 127})); |
| 117 | + connect(voltage_droop.u, deadband_voltage.y) annotation( |
| 118 | + Line(points = {{-42, -70}, {-59, -70}}, color = {0, 0, 127})); |
| 119 | + connect(add1.y, limiter.u) annotation( |
| 120 | + Line(points = {{25, -70}, {38, -70}}, color = {0, 0, 127})); |
| 121 | + connect(voltage_droop.y, add1.u1) annotation( |
| 122 | + Line(points = {{-19, -70}, {-10, -70}, {-10, -69}, {2, -69}, {2, -64}}, color = {0, 0, 127})); |
| 123 | + connect(reactive_power_reference.y, add1.u2) annotation( |
| 124 | + Line(points = {{-59, -110}, {-10, -110}, {-10, -95}, {2, -95}, {2, -76}}, color = {0, 0, 127})); |
| 125 | + connect(limiter.y, division.u1) annotation( |
| 126 | + Line(points = {{61, -70}, {62.5, -70}, {62.5, -24}, {78, -24}}, color = {0, 0, 127})); |
| 127 | + connect(QCurrentController.y, Iq) annotation( |
| 128 | + Line(points = {{193, -70}, {210, -70}}, color = {0, 0, 127})); |
| 129 | + connect(PCurrentController.y, Ip) annotation( |
| 130 | + Line(points = {{193, 90}, {210, 90}}, color = {0, 0, 127})); |
| 131 | + connect(active_power_reference.y, add4.u2) annotation( |
| 132 | + Line(points = {{-138, 30}, {-80, 30}, {-80, 44}, {-62, 44}, {-62, 44}}, color = {0, 0, 127})); |
| 133 | + connect(frequency_droop.y, add4.u1) annotation( |
| 134 | + Line(points = {{-39, 144}, {-34, 144}, {-34, 104}, {-80, 104}, {-80, 56}, {-62, 56}}, color = {0, 0, 127})); |
| 135 | + connect(add4.y, division1.u1) annotation( |
| 136 | + Line(points = {{-38, 50}, {52, 50}, {52, 36}, {78, 36}, {78, 36}}, color = {0, 0, 127})); |
| 137 | + connect(product1.y, PCurrentController.u) annotation( |
| 138 | + Line(points = {{162, 90}, {170, 90}, {170, 90}, {170, 90}}, color = {0, 0, 127})); |
| 139 | + connect(product1.u2, qppriority.Ipcmd) annotation( |
| 140 | + Line(points = {{138, 84}, {126, 84}, {126, 20}, {144, 20}, {144, 6}, {142, 6}, {142, 6}}, color = {0, 0, 127})); |
| 141 | + connect(frequency_tripping.TrpLow, product.u1) annotation( |
| 142 | + Line(points = {{42, 156}, {58, 156}, {58, 156}, {58, 156}}, color = {0, 0, 127})); |
| 143 | + connect(frequency_tripping.TrpHigh, product.u2) annotation( |
| 144 | + Line(points = {{42, 144}, {58, 144}, {58, 144}, {58, 144}}, color = {0, 0, 127})); |
| 145 | + connect(frequency_tripping.u, freq) annotation( |
| 146 | + Line(points = {{20, 150}, {0, 150}, {0, 184}, {-188, 184}, {-188, 150}, {-200, 150}}, color = {0, 0, 127})); |
| 147 | + connect(voltage_tripping.u, Vt) annotation( |
| 148 | + Line(points = {{20, 110}, {-128, 110}, {-128, -10}, {-200, -10}}, color = {0, 0, 127})); |
| 149 | + connect(voltage_tripping.TrpLow, product2.u1) annotation( |
| 150 | + Line(points = {{42, 116}, {58, 116}, {58, 116}, {58, 116}}, color = {0, 0, 127})); |
| 151 | + connect(voltage_tripping.TrpHigh, product2.u2) annotation( |
| 152 | + Line(points = {{42, 106}, {56, 106}, {56, 104}, {58, 104}}, color = {0, 0, 127})); |
| 153 | + connect(product.y, product3.u1) annotation( |
| 154 | + Line(points = {{82, 150}, {90, 150}, {90, 136}, {98, 136}, {98, 136}}, color = {0, 0, 127})); |
| 155 | + connect(product2.y, product3.u2) annotation( |
| 156 | + Line(points = {{82, 110}, {90, 110}, {90, 124}, {98, 124}, {98, 124}}, color = {0, 0, 127})); |
| 157 | + connect(product3.y, product1.u1) annotation( |
| 158 | + Line(points = {{122, 130}, {128, 130}, {128, 96}, {138, 96}, {138, 96}}, color = {0, 0, 127})); |
| 159 | + connect(product4.y, QCurrentController.u) annotation( |
| 160 | + Line(points = {{162, -70}, {168, -70}, {168, -70}, {170, -70}}, color = {0, 0, 127})); |
| 161 | + connect(qppriority.Iqcmd, product4.u1) annotation( |
| 162 | + Line(points = {{142, -4}, {144, -4}, {144, -52}, {130, -52}, {130, -64}, {138, -64}, {138, -64}}, color = {0, 0, 127})); |
| 163 | + connect(product4.u2, product3.y) annotation( |
| 164 | + Line(points = {{138, -76}, {112, -76}, {112, 100}, {128, 100}, {128, 130}, {122, 130}, {122, 130}}, color = {0, 0, 127})); |
| 165 | + annotation( |
| 166 | + Diagram(coordinateSystem(extent = {{-200, -200}, {200, 200}}, initialScale = 0.05), graphics = {Text(origin = {-186, 179}, lineColor = {255, 0, 0}, extent = {{-8, 3}, {76, -9}}, textString = "Frequency filtering has to be done outside of this block", horizontalAlignment = TextAlignment.Left), Rectangle(origin = {-67, 141}, lineColor = {0, 170, 0}, pattern = LinePattern.Dash, lineThickness = 1, extent = {{-85, 21}, {51, -45}}), Text(origin = {-186, 179}, lineColor = {255, 0, 0}, extent = {{-8, 3}, {76, -9}}, textString = "Frequency filtering has to be done outside of this block", horizontalAlignment = TextAlignment.Left), Text(origin = {-186, 179}, lineColor = {255, 0, 0}, extent = {{-8, 3}, {76, -9}}, textString = "Frequency filtering has to be done outside of this block", horizontalAlignment = TextAlignment.Left), Text(origin = {-92, 171}, lineColor = {0, 170, 0}, lineThickness = 1, extent = {{-8, 3}, {76, -9}}, textString = "Underfrequency Droop Control", horizontalAlignment = TextAlignment.Left), Rectangle(origin = {-67, 141}, lineColor = {0, 170, 0}, pattern = LinePattern.Dash, lineThickness = 1, extent = {{-85, 21}, {51, -45}}), Rectangle(origin = {-5, -71}, lineColor = {0, 170, 0}, pattern = LinePattern.Dash, lineThickness = 1, extent = {{-85, 21}, {79, -57}}), Text(origin = {-120, -41}, lineColor = {0, 170, 0}, lineThickness = 1, extent = {{30, -1}, {76, -9}}, textString = "Volt/Var Control", horizontalAlignment = TextAlignment.Left)}), |
| 167 | + Icon(coordinateSystem(extent = {{-200, -200}, {200, 200}}, initialScale = 0.05), graphics = {Rectangle(origin = {-52, 50}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-150, 150}, {252, -250}}), Text(origin = {26, 194}, extent = {{-228, -34}, {174, 6}}, textString = "PVD1")}), |
| 168 | + experiment(StartTime = 0, StopTime = 1, Tolerance = 1e-6, Interval = 0.002), |
| 169 | + __OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl")); |
| 170 | +end Controller; |
0 commit comments