71 |
86 |
|
return |
72 |
87 |
|
if any(pd.isnull(sgen.sn_mva)): |
73 |
88 |
|
raise ValueError("sn_mva needs to be specified for all sgens in net.sgen.sn_mva") |
74 |
|
- |
baseI = ppc["internal"]["baseI"] |
|
89 |
+ |
baseI = ppci["internal"]["baseI"] |
75 |
90 |
|
sgen_buses = sgen.bus.values |
76 |
91 |
|
sgen_buses_ppc = bus_lookup[sgen_buses] |
77 |
92 |
|
if not "k" in sgen: |
78 |
93 |
|
raise ValueError("Nominal to short-circuit current has to specified in net.sgen.k") |
79 |
94 |
|
i_sgen_pu = sgen.sn_mva.values / net.sn_mva * sgen.k.values |
80 |
95 |
|
buses, ikcv_pu, _ = _sum_by_group(sgen_buses_ppc, i_sgen_pu, i_sgen_pu) |
81 |
|
- |
ppc["bus"][buses, IKCV] = ikcv_pu |
|
96 |
+ |
ppci["bus"][buses, IKCV] = ikcv_pu |
82 |
97 |
|
if net["_options"]["inverse_y"]: |
83 |
|
- |
Zbus = ppc["internal"]["Zbus"] |
84 |
|
- |
ppc["bus"][:, IKSS2] = abs(1 / np.diag(Zbus) * np.dot(Zbus, ppc["bus"][:, IKCV] * -1j) / baseI) |
|
98 |
+ |
Zbus = ppci["internal"]["Zbus"] |
|
99 |
+ |
ppci["bus"][:, IKSS2] = abs(1 / np.diag(Zbus) * np.dot(Zbus, ppci["bus"][:, IKCV] * -1j) / baseI) |
85 |
100 |
|
else: |
86 |
|
- |
ybus_fact = ppc["internal"]["ybus_fact"] |
87 |
|
- |
diagZ = _calc_zbus_diag(net, ppc) |
88 |
|
- |
ppc["bus"][:, IKSS2] = abs(ybus_fact(ppc["bus"][:, IKCV] * -1j) / diagZ / baseI) |
89 |
|
- |
ppc["bus"][buses, IKCV] /= baseI[buses] |
|
101 |
+ |
ybus_fact = ppci["internal"]["ybus_fact"] |
|
102 |
+ |
diagZ = _calc_zbus_diag(net, ppci) |
|
103 |
+ |
ppci["bus"][:, IKSS2] = abs(ybus_fact(ppci["bus"][:, IKCV] * -1j) / diagZ / baseI) |
|
104 |
+ |
ppci["bus"][buses, IKCV] /= baseI[buses] |
90 |
105 |
|
|
91 |
106 |
|
|
92 |
|
- |
def _calc_ip(net, ppc): |
93 |
|
- |
ip = np.sqrt(2) * (ppc["bus"][:, KAPPA] * ppc["bus"][:, IKSS1] + ppc["bus"][:, IKSS2]) |
94 |
|
- |
ppc["bus"][:, IP] = ip |
|
107 |
+ |
def _calc_ip(net, ppci): |
|
108 |
+ |
ip = np.sqrt(2) * (ppci["bus"][:, KAPPA] * ppci["bus"][:, IKSS1] + ppci["bus"][:, IKSS2]) |
|
109 |
+ |
ppci["bus"][:, IP] = ip |
95 |
110 |
|
|
96 |
111 |
|
|
97 |
|
- |
def _calc_ith(net, ppc): |
|
112 |
+ |
def _calc_ith(net, ppci): |
98 |
113 |
|
tk_s = net["_options"]["tk_s"] |
99 |
|
- |
kappa = ppc["bus"][:, KAPPA] |
|
114 |
+ |
kappa = ppci["bus"][:, KAPPA] |
100 |
115 |
|
f = 50 |
101 |
116 |
|
n = 1 |
102 |
117 |
|
m = (np.exp(4 * f * tk_s * np.log(kappa - 1)) - 1) / (2 * f * tk_s * np.log(kappa - 1)) |
103 |
118 |
|
m[np.where(kappa > 1.99)] = 0 |
104 |
|
- |
ppc["bus"][:, M] = m |
105 |
|
- |
ith = (ppc["bus"][:, IKSS1] + ppc["bus"][:, IKSS2]) * np.sqrt(m + n) |
106 |
|
- |
ppc["bus"][:, ITH] = ith |
107 |
|
- |
|
108 |
|
- |
|
109 |
|
- |
def _calc_ib_generator(net, ppci): |
110 |
|
- |
Zbus = ppci["internal"]["Zbus"] |
111 |
|
- |
baseI = ppci["internal"]["baseI"] |
112 |
|
- |
tk_s = net._options['tk_s'] |
113 |
|
- |
c = 1.1 |
114 |
|
- |
|
115 |
|
- |
z_equiv = ppci["bus"][:, R_EQUIV] + ppci["bus"][:, X_EQUIV] * 1j |
116 |
|
- |
I_ikss = c / z_equiv / ppci["bus"][:, BASE_KV] / np.sqrt(3) * ppci["baseMVA"] |
117 |
|
- |
|
118 |
|
- |
# calculate voltage source branch current |
119 |
|
- |
# I_ikss = ppci["bus"][:, IKSS1] |
120 |
|
- |
V_ikss = (I_ikss * baseI) * Zbus |
121 |
|
- |
|
122 |
|
- |
gen = net["gen"][net._is_elements["gen"]] |
123 |
|
- |
gen_vn_kv = gen.vn_kv.values |
|
119 |
+ |
ppci["bus"][:, M] = m |
|
120 |
+ |
ith = (ppci["bus"][:, IKSS1] + ppci["bus"][:, IKSS2]) * np.sqrt(m + n) |
|
121 |
+ |
ppci["bus"][:, ITH] = ith |
124 |
122 |
|
|
125 |
|
- |
gen_buses = ppci['gen'][:, GEN_BUS].astype(np.int64) |
126 |
|
- |
gen_mbase = ppci['gen'][:, MBASE] |
127 |
|
- |
gen_i_rg = gen_mbase / (np.sqrt(3) * gen_vn_kv) |
128 |
123 |
|
|
129 |
|
- |
gen_buses_ppc, gen_sn_mva, I_rG = _sum_by_group(gen_buses, gen_mbase, gen_i_rg) |
|
124 |
+ |
# TODO: Ib for generation close bus |
|
125 |
+ |
# def _calc_ib_generator(net, ppci): |
|
126 |
+ |
# # Zbus = ppci["internal"]["Zbus"] |
|
127 |
+ |
# # baseI = ppci["internal"]["baseI"] |
|
128 |
+ |
# tk_s = net._options['tk_s'] |
|
129 |
+ |
# c = 1.1 |
130 |
130 |
|
|
131 |
|
- |
# shunt admittance of generator buses and generator short circuit current |
132 |
|
- |
# YS = ppci["bus"][gen_buses_ppc, GS] + ppci["bus"][gen_buses_ppc, BS] * 1j |
133 |
|
- |
# I_kG = V_ikss.T[:, gen_buses_ppc] * YS / baseI[gen_buses_ppc] |
|
131 |
+ |
# z_equiv = ppci["bus"][:, R_EQUIV] + ppci["bus"][:, X_EQUIV] * 1j |
|
132 |
+ |
# I_ikss = c / z_equiv / ppci["bus"][:, BASE_KV] / np.sqrt(3) * ppci["baseMVA"] |
134 |
133 |
|
|
135 |
|
- |
xdss_pu = gen.xdss_pu.values |
136 |
|
- |
rdss_pu = gen.rdss_pu.values |
137 |
|
- |
cosphi = gen.cos_phi.values |
138 |
|
- |
X_dsss = xdss_pu * np.square(gen_vn_kv) / gen_mbase |
139 |
|
- |
R_dsss = rdss_pu * np.square(gen_vn_kv) / gen_mbase |
|
134 |
+ |
# # calculate voltage source branch current |
|
135 |
+ |
# # I_ikss = ppci["bus"][:, IKSS1] |
|
136 |
+ |
# # V_ikss = (I_ikss * baseI) * Zbus |
140 |
137 |
|
|
141 |
|
- |
K_G = ppci['bus'][gen_buses, BASE_KV] / gen_vn_kv * c / (1 + xdss_pu * np.sin(np.arccos(cosphi))) |
142 |
|
- |
Z_G = (R_dsss + 1j * X_dsss) |
|
138 |
+ |
# gen = net["gen"][net._is_elements["gen"]] |
|
139 |
+ |
# gen_vn_kv = gen.vn_kv.values |
143 |
140 |
|
|
144 |
|
- |
I_kG = c * ppci['bus'][gen_buses, BASE_KV] / np.sqrt(3) / (Z_G * K_G) * ppci["baseMVA"] |
|
141 |
+ |
# # Check difference ext_grid and gen |
|
142 |
+ |
# gen_buses = ppci['gen'][:, GEN_BUS].astype(np.int64) |
|
143 |
+ |
# gen_mbase = ppci['gen'][:, MBASE] |
|
144 |
+ |
# gen_i_rg = gen_mbase / (np.sqrt(3) * gen_vn_kv) |
145 |
145 |
|
|
146 |
|
- |
dV_G = 1j * X_dsss * K_G * I_kG |
147 |
|
- |
V_Is = c * ppci['bus'][gen_buses, BASE_KV] / np.sqrt(3) |
|
146 |
+ |
# gen_buses_ppc, gen_sn_mva, I_rG = _sum_by_group(gen_buses, gen_mbase, gen_i_rg) |
148 |
147 |
|
|
149 |
|
- |
# I_kG_contribution = I_kG.sum(axis=1) |
150 |
|
- |
# ratio_SG_ikss = I_kG_contribution / I_ikss |
151 |
|
- |
# close_to_SG = ratio_SG_ikss > 5e-2 |
|
148 |
+ |
# # shunt admittance of generator buses and generator short circuit current |
|
149 |
+ |
# # YS = ppci["bus"][gen_buses_ppc, GS] + ppci["bus"][gen_buses_ppc, BS] * 1j |
|
150 |
+ |
# # I_kG = V_ikss.T[:, gen_buses_ppc] * YS / baseI[gen_buses_ppc] |
152 |
151 |
|
|
153 |
|
- |
close_to_SG = I_kG / I_rG > 2 |
|
152 |
+ |
# xdss_pu = gen.xdss_pu.values |
|
153 |
+ |
# rdss_pu = gen.rdss_pu.values |
|
154 |
+ |
# cosphi = gen.cos_phi.values |
|
155 |
+ |
# X_dsss = xdss_pu * np.square(gen_vn_kv) / gen_mbase |
|
156 |
+ |
# R_dsss = rdss_pu * np.square(gen_vn_kv) / gen_mbase |
154 |
157 |
|
|
155 |
|
- |
if tk_s == 2e-2: |
156 |
|
- |
mu = 0.84 + 0.26 * np.exp(-0.26 * abs(I_kG) / I_rG) |
157 |
|
- |
elif tk_s == 5e-2: |
158 |
|
- |
mu = 0.71 + 0.51 * np.exp(-0.3 * abs(I_kG) / I_rG) |
159 |
|
- |
elif tk_s == 10e-2: |
160 |
|
- |
mu = 0.62 + 0.72 * np.exp(-0.32 * abs(I_kG) / I_rG) |
161 |
|
- |
elif tk_s >= 25e-2: |
162 |
|
- |
mu = 0.56 + 0.94 * np.exp(-0.38 * abs(I_kG) / I_rG) |
163 |
|
- |
else: |
164 |
|
- |
raise UserWarning('not implemented for other tk_s than 20ms, 50ms, 100ms and >=250ms') |
|
158 |
+ |
# K_G = ppci['bus'][gen_buses, BASE_KV] / gen_vn_kv * c / (1 + xdss_pu * np.sin(np.arccos(cosphi))) |
|
159 |
+ |
# Z_G = (R_dsss + 1j * X_dsss) |
165 |
160 |
|
|
166 |
|
- |
mu = np.clip(mu, 0, 1) |
|
161 |
+ |
# I_kG = c * ppci['bus'][gen_buses, BASE_KV] / np.sqrt(3) / (Z_G * K_G) * ppci["baseMVA"] |
167 |
162 |
|
|
168 |
|
- |
I_ikss_G = abs(I_ikss - np.sum((1 - mu) * I_kG, axis=1)) |
|
163 |
+ |
# dV_G = 1j * X_dsss * K_G * I_kG |
|
164 |
+ |
# V_Is = c * ppci['bus'][gen_buses, BASE_KV] / np.sqrt(3) |
169 |
165 |
|
|
170 |
|
- |
# I_ikss_G = I_ikss - np.sum(abs(V_ikss.T[:, gen_buses_ppc]) * (1-mu) * I_kG, axis=1) |
|
166 |
+ |
# # I_kG_contribution = I_kG.sum(axis=1) |
|
167 |
+ |
# # ratio_SG_ikss = I_kG_contribution / I_ikss |
|
168 |
+ |
# # close_to_SG = ratio_SG_ikss > 5e-2 |
171 |
169 |
|
|
172 |
|
- |
I_ikss_G = abs(I_ikss - np.sum(dV_G / V_Is * (1 - mu) * I_kG, axis=1)) |
|
170 |
+ |
# close_to_SG = I_kG / I_rG > 2 |
173 |
171 |
|
|
174 |
|
- |
return I_ikss_G |
|
172 |
+ |
# if tk_s == 2e-2: |
|
173 |
+ |
# mu = 0.84 + 0.26 * np.exp(-0.26 * abs(I_kG) / I_rG) |
|
174 |
+ |
# elif tk_s == 5e-2: |
|
175 |
+ |
# mu = 0.71 + 0.51 * np.exp(-0.3 * abs(I_kG) / I_rG) |
|
176 |
+ |
# elif tk_s == 10e-2: |
|
177 |
+ |
# mu = 0.62 + 0.72 * np.exp(-0.32 * abs(I_kG) / I_rG) |
|
178 |
+ |
# elif tk_s >= 25e-2: |
|
179 |
+ |
# mu = 0.56 + 0.94 * np.exp(-0.38 * abs(I_kG) / I_rG) |
|
180 |
+ |
# else: |
|
181 |
+ |
# raise UserWarning('not implemented for other tk_s than 20ms, 50ms, 100ms and >=250ms') |
175 |
182 |
|
|
|
183 |
+ |
# mu = np.clip(mu, 0, 1) |
176 |
184 |
|
|
177 |
|
- |
def _calc_single_bus_sc(net, ppc, bus): |
178 |
|
- |
# case = net._options["case"] |
179 |
|
- |
bus_idx = net._pd2ppc_lookups["bus"][bus] |
180 |
|
- |
n = ppc["bus"].shape[0] |
181 |
|
- |
Zbus = ppc["internal"]["Zbus"] |
182 |
|
- |
# Yf = ppc["internal"]["Yf"] |
183 |
|
- |
# Yt = ppc["internal"]["Yf"] |
184 |
|
- |
baseI = ppc["internal"]["baseI"] |
185 |
|
- |
# fb = np.real(ppc["branch"][:, 0]).astype(int) |
186 |
|
- |
# tb = np.real(ppc["branch"][:, 1]).astype(int) |
187 |
|
- |
# c = ppc["bus"][:, C_MIN] if case == "min" else ppc["bus"][:, C_MAX] |
|
185 |
+ |
# I_ikss_G = abs(I_ikss - np.sum((1 - mu) * I_kG, axis=1)) |
188 |
186 |
|
|
189 |
|
- |
# calculate voltage source branch current |
190 |
|
- |
V_ikss = (ppc["bus"][:, IKSS1] * baseI) * Zbus |
191 |
|
- |
V = V_ikss[:, bus_idx] |
192 |
|
- |
# ikss_all_f = np.conj(Yf.dot(V_ikss)) |
193 |
|
- |
# ikss_all_t = np.conj(Yt.dot(V_ikss)) |
194 |
|
- |
current_sources = any(ppc["bus"][:, IKCV]) > 0 |
195 |
|
- |
if current_sources: |
196 |
|
- |
current = np.tile(-ppc["bus"][:, IKCV], (n, 1)) |
197 |
|
- |
np.fill_diagonal(current, current.diagonal() + ppc["bus"][:, IKSS2]) |
198 |
|
- |
V_source = np.dot((current * baseI), Zbus).T |
199 |
|
- |
V = V + V_source[:, bus_idx] |
200 |
|
- |
# add current source branch current if there is one |
201 |
|
- |
# ppc["branch"][:, IKSS_F] = abs(ikss_all_f[:, bus_idx] / baseI[fb]) |
202 |
|
- |
# ppc["branch"][:, IKSS_T] = abs(ikss_all_t[:, bus_idx] / baseI[tb]) |
203 |
|
- |
calc_branch_results(net, ppc, V) |
204 |
|
- |
|
205 |
|
- |
def _calc_single_bus_sc_no_y_inv(net, ppc, bus): |
206 |
|
- |
# Vectorized for multiple bus |
207 |
|
- |
if bus is None: |
208 |
|
- |
# Slice(None) is equal to : select |
209 |
|
- |
bus_idx = slice(None) |
210 |
|
- |
else: |
211 |
|
- |
bus_idx = net._pd2ppc_lookups["bus"][bus] #bus where the short-circuit is calculated (j) |
212 |
|
- |
|
213 |
|
- |
ybus = ppc["internal"]["Ybus"] |
214 |
|
- |
ybus_fact = ppc["internal"]["ybus_fact"] |
215 |
|
- |
# case = net._options["case"] |
216 |
|
- |
baseI = ppc["internal"]["baseI"] |
217 |
|
- |
# vqj = ppc["bus"][:, C_MIN] if case == "min" else ppc["bus"][:, C_MAX] #this is the source voltage in per unit (VQj) |
218 |
|
- |
|
219 |
|
- |
# Solve Ikss from voltage source |
220 |
|
- |
n_bus = ybus.shape[0] |
221 |
|
- |
|
222 |
|
- |
# ybus_sub_mask = (np.arange(ybus.shape[0]) != bus_idx) |
223 |
|
- |
# V_ikss = np.zeros(n_bus, dtype=np.complex) |
224 |
|
- |
# V_ikss[bus_idx] = vqj[bus_idx] |
225 |
|
- |
|
226 |
|
- |
# # Solve Ax = b |
227 |
|
- |
# b = np.zeros(n_bus-1, dtype=np.complex) -\ |
228 |
|
- |
# (ybus[:, ~ybus_sub_mask].toarray())[ybus_sub_mask].ravel() * V_ikss[bus_idx] |
229 |
|
- |
# ybus_sub = ybus[ybus_sub_mask, :][:, ybus_sub_mask] |
230 |
|
- |
# x = spsolve(ybus_sub, b) |
231 |
|
- |
|
232 |
|
- |
# V_ikss[ybus_sub_mask] = x |
233 |
|
- |
# I_ikss = np.zeros(n_bus, dtype=np.complex) |
234 |
|
- |
# I_ikss[bus_idx] = np.dot(ybus[bus_idx, :].toarray(), V_ikss) |
235 |
|
- |
# V = V_ikss |
236 |
|
- |
|
237 |
|
- |
# Version 2 |
238 |
|
- |
I_ikss = np.zeros(n_bus, dtype=np.complex) |
239 |
|
- |
I_ikss[bus_idx] = ppc["bus"][bus_idx, IKSS1] |
240 |
|
- |
V_ikss = ybus_fact(I_ikss * baseI) |
241 |
|
- |
V = V_ikss |
242 |
|
- |
|
243 |
|
- |
#TODO include current sources |
244 |
|
- |
current_sources = any(ppc["bus"][:, IKCV]) > 0 |
245 |
|
- |
if current_sources: |
246 |
|
- |
current = -ppc["bus"][:, IKCV] |
247 |
|
- |
current[bus_idx] += ppc["bus"][bus_idx, IKSS2] |
248 |
|
- |
V_source = ybus_fact(current) |
249 |
|
- |
V += V_source |
250 |
|
- |
|
251 |
|
- |
calc_branch_results(net, ppc, V) |
|
187 |
+ |
# # I_ikss_G = I_ikss - np.sum(abs(V_ikss.T[:, gen_buses_ppc]) * (1-mu) * I_kG, axis=1) |
252 |
188 |
|
|
|
189 |
+ |
# I_ikss_G = abs(I_ikss - np.sum(dV_G / V_Is * (1 - mu) * I_kG, axis=1)) |
253 |
190 |
|
|
254 |
|
- |
def calc_branch_results(net, ppci, V): |
255 |
|
- |
Ybus = ppci["internal"]["Ybus"] |
256 |
|
- |
Yf = ppci["internal"]["Yf"] |
257 |
|
- |
Yt = ppci["internal"]["Yt"] |
258 |
|
- |
baseMVA, bus, gen, branch, ref, _, _, _, _, _, ref_gens = _get_pf_variables_from_ppci(ppci) |
259 |
|
- |
bus, gen, branch = pfsoln_pypower(baseMVA, bus, gen, branch, Ybus, Yf, Yt, V, ref, ref_gens) |
260 |
|
- |
ppci["bus"], ppci["gen"], ppci["branch"] = bus, gen, branch |
|
191 |
+ |
# return I_ikss_G |
261 |
192 |
|
|
262 |
193 |
|
|
263 |
|
- |
def _calc_branch_currents(net, ppc, bus): |
264 |
|
- |
# Vectorized for multiple bus |
265 |
|
- |
if bus is None: |
266 |
|
- |
# Slice(None) is equal to select all |
267 |
|
- |
bus = net.bus.index |
268 |
|
- |
|
269 |
|
- |
bus_idx = net._pd2ppc_lookups["bus"][bus] |
270 |
|
- |
# Select only in service bus for sc calculation |
271 |
|
- |
bus_idx = bus_idx[bus_idx < ppc['bus'].shape[0]] |
|
194 |
+ |
def _calc_branch_currents(net, ppci, bus_idx): |
272 |
195 |
|
n_sc_bus = np.shape(bus_idx)[0] |
273 |
196 |
|
|
274 |
197 |
|
case = net._options["case"] |
275 |
|
- |
|
276 |
|
- |
Yf = ppc["internal"]["Yf"] |
277 |
|
- |
Yt = ppc["internal"]["Yt"] |
278 |
|
- |
baseI = ppc["internal"]["baseI"] |
279 |
|
- |
n_bus = ppc["bus"].shape[0] |
280 |
|
- |
fb = np.real(ppc["branch"][:, 0]).astype(int) |
281 |
|
- |
tb = np.real(ppc["branch"][:, 1]).astype(int) |
282 |
198 |
|
minmax = np.nanmin if case == "min" else np.nanmax |
283 |
199 |
|
|
|
200 |
+ |
Yf = ppci["internal"]["Yf"] |
|
201 |
+ |
Yt = ppci["internal"]["Yt"] |
|
202 |
+ |
baseI = ppci["internal"]["baseI"] |
|
203 |
+ |
n_bus = ppci["bus"].shape[0] |
|
204 |
+ |
fb = np.real(ppci["branch"][:, 0]).astype(int) |
|
205 |
+ |
tb = np.real(ppci["branch"][:, 1]).astype(int) |
|
206 |
+ |
|
284 |
207 |
|
# calculate voltage source branch current |
285 |
208 |
|
if net["_options"]["inverse_y"]: |
286 |
|
- |
Zbus = ppc["internal"]["Zbus"] |
287 |
|
- |
V_ikss = (ppc["bus"][:, IKSS1] * baseI) * Zbus |
|
209 |
+ |
Zbus = ppci["internal"]["Zbus"] |
|
210 |
+ |
V_ikss = (ppci["bus"][:, IKSS1] * baseI) * Zbus |
288 |
211 |
|
V_ikss = V_ikss[:, bus_idx] |
289 |
212 |
|
else: |
290 |
|
- |
ybus_fact = ppc["internal"]["ybus_fact"] |
|
213 |
+ |
ybus_fact = ppci["internal"]["ybus_fact"] |
291 |
214 |
|
V_ikss = np.zeros((n_bus, n_sc_bus), dtype=np.complex) |
292 |
215 |
|
for ix, b in enumerate(bus_idx): |
293 |
216 |
|
ikss = np.zeros(n_bus, dtype=np.complex) |
294 |
|
- |
ikss[b] = ppc["bus"][b, IKSS1] * baseI[b] |
|
217 |
+ |
ikss[b] = ppci["bus"][b, IKSS1] * baseI[b] |
295 |
218 |
|
V_ikss[:, ix] = ybus_fact(ikss) |
296 |
219 |
|
|
297 |
220 |
|
ikss1_all_f = np.conj(Yf.dot(V_ikss)) |