Skip to content

Commit a115273

Browse files
authored
Merge pull request OpenIPSL#267 from tinrabuzin/solar_PVD1
Adding PowerFactory implementation of distributed solar PVD1
2 parents 5b6b1de + 7624ad5 commit a115273

13 files changed

Lines changed: 559 additions & 0 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
within OpenIPSL.Electrical.Solar.PowerFactory.General;
2+
model StaVmea "Voltage Measurement Device"
3+
parameter Types.Time Tfe=3/50 "Measurement delay" annotation (Dialog(enable=use_ref_machine_frequency));
4+
parameter Types.Frequency fn=50 "Nominal frequency";
5+
parameter Types.Angle angle_0=0 "Initial angle";
6+
parameter Boolean use_ref_machine_frequency=false "Use reference machine frequency" annotation (choices(checkBox=true));
7+
OpenIPSL.Interfaces.PwPin p annotation (Placement(transformation(extent={{-120,-10},{-100,10}})));
8+
Real cosphi(start=cos(angle_0));
9+
Real sinphi(start=sin(angle_0));
10+
Types.Frequency df(start=0) "Frequency difference";
11+
Types.PerUnit vx "Voltage component";
12+
Types.PerUnit vy "Voltage component";
13+
Modelica.Blocks.Interfaces.RealOutput u "Voltage magnitude [pu]" annotation (Placement(transformation(extent={{100,50},{120,70}})));
14+
Modelica.Blocks.Interfaces.RealOutput fe "Electrical frequency [Hz]" annotation (Placement(transformation(extent={{100,-70},{120,-50}})));
15+
Modelica.Blocks.Interfaces.RealInput omega if use_ref_machine_frequency "Reference machine frequency [Hz]" annotation (Placement(transformation(extent={{-140,40},{-100,80}})));
16+
17+
protected
18+
Modelica.Blocks.Interfaces.RealInput omega_internal "Helping variable/connector";
19+
Modelica.Blocks.Interfaces.RealInput phi if use_ref_machine_frequency "Conditional angle";
20+
Modelica.Blocks.Interfaces.RealInput phi_internal "Helping variable/connector";
21+
Modelica.Blocks.Interfaces.RealInput local_df if not use_ref_machine_frequency "Conditional frequency difference";
22+
Modelica.Blocks.Interfaces.RealInput local_df_internal "Helping variable/connector";
23+
equation
24+
u = sqrt(p.vr^2 + p.vi^2);
25+
connect(omega, omega_internal);
26+
connect(phi, phi_internal);
27+
connect(local_df, local_df_internal);
28+
if use_ref_machine_frequency then
29+
der(phi_internal) = 2*C.pi*50*(omega_internal - 1) "First this has to be transformed to the rotating reference frame (w.r.t. the frequency of the reference machine) to correspond to PowerFactory implementation
30+
";
31+
vx = p.vr*cos(phi_internal) + p.vi*sin(phi_internal);
32+
vy = (-p.vr*sin(phi_internal)) + p.vi*cos(phi_internal);
33+
der(cosphi) = (vx/u - cosphi)/Tfe;
34+
der(sinphi) = (vy/u - sinphi)/Tfe;
35+
fe = omega_internal + df;
36+
else
37+
cosphi = vx/u;
38+
sinphi = vy/u;
39+
der(local_df_internal) = (df - local_df_internal)/Tfe;
40+
vx = p.vr;
41+
vy = p.vi;
42+
fe = 1 + local_df_internal;
43+
omega_internal = 0 "Balance equation";
44+
phi_internal = 0 "Balance equation";
45+
end if;
46+
if abs(cosphi) > abs(sinphi) then
47+
df = der(sinphi)/cosphi/(2*C.pi*fn);
48+
else
49+
df = -der(cosphi)/sinphi/(2*C.pi*fn);
50+
end if;
51+
p.ii = 0;
52+
p.ir = 0;
53+
annotation (Icon(graphics={
54+
Rectangle(
55+
fillColor={255,255,255},
56+
fillPattern=FillPattern.Solid,
57+
extent={{-100,100},{100,-100}}),
58+
Text(extent={{70,70},{90,50}}, textString="u"),
59+
Text(extent={{70,-50},{90,-70}}, textString="fe"),
60+
Text(
61+
extent={{-100,20},{100,-20}},
62+
lineColor={0,0,0},
63+
textString="%name")}), Documentation(info="<html>
64+
<p>
65+
StaVmea model in PowerFactory measures voltage and frequency.
66+
The frequency in PowerFactory is computed with respect to the frame rotating with frequency
67+
equal to the synchronous machine.
68+
This is supported via the input <code>omega</code> here.
69+
Most of the OpenIPSL examples do not provide <code>omega</code> of the reference machine and thus,
70+
if the input is not connected the frequency is computed with respect to the 50&nbsp;Hz reference frame
71+
and filtered to simulate the measurement delay.
72+
</p>
73+
</html>", revisions="<html>
74+
<table cellspacing=\"1\" cellpadding=\"1\" border=\"1\"><tr>
75+
<td><p>Model Name</p></td>
76+
<td><p>StaVmea</p></td>
77+
</tr>
78+
<tr>
79+
<td><p>Reference</p></td>
80+
<td><p>PowerFactory Manual</p></td>
81+
</tr>
82+
<tr>
83+
<td><p>Last update</p></td>
84+
<td><p>January 2021</p></td>
85+
</tr>
86+
<tr>
87+
<td><p>Author</p></td>
88+
<td><p>Tin Rabuzin, KTH Royal Institute of Technology</p></td>
89+
</tr>
90+
<tr>
91+
<td><p>Contact</p></td>
92+
<td><p>see <a href=\"modelica://OpenIPSL.UsersGuide.Contact\">UsersGuide.Contact</a></p></td>
93+
</tr>
94+
<tr>
95+
<td><p>Model Verification</p></td>
96+
<td><p>This model has not been verified against PowerFactory.</p></td>
97+
</tr>
98+
<tr>
99+
<td><p>Description</p></td>
100+
<td></td>
101+
</tr>
102+
</table>
103+
</html>"));
104+
end StaVmea;

OpenIPSL/Electrical/Solar/PowerFactory/General/package.order

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

0 commit comments

Comments
 (0)