#!/usr/bin/env python3
import math
import numpy as np
import VeraGridEngine.Utils.Symbolic.symbolic as sym
from VeraGridEngine.Utils.Symbolic.block import Block, VarPowerFlowReferenceType
from VeraGridEngine.Utils.Symbolic.block_helpers import tf_to_block
[docs]
def inverse_park_currents_block(vfactory, i_d, i_q, theta):
i_a = vfactory.add_var("i_A_gfm_emt", reference=VarPowerFlowReferenceType.i_A)
i_b = vfactory.add_var("i_B_gfm_emt", reference=VarPowerFlowReferenceType.i_B)
i_c = vfactory.add_var("i_C_gfm_emt", reference=VarPowerFlowReferenceType.i_C)
sqrt3 = vfactory.add_const(np.sqrt(3))
half = vfactory.add_const(0.5)
two = vfactory.add_const(2.0)
eqs = [
i_a - (i_d * sym.cos(theta) + i_q * sym.sin(theta)),
i_b - ((-half * i_d - (sqrt3 / two) * i_q) * sym.cos(theta)
+ ((sqrt3 / two) * i_d - half * i_q) * sym.sin(theta)),
i_c - ((-half * i_d + (sqrt3 / two) * i_q) * sym.cos(theta)
+ ((-sqrt3 / two) * i_d - half * i_q) * sym.sin(theta)),
]
return Block(algebraic_eqs=eqs, algebraic_vars=[i_a, i_b, i_c]), (i_a, i_b, i_c)
[docs]
def build_vsc_gfm_emt_park(vfactory, name: str = "gfm_emt"):
v_a = vfactory.add_var(f"v_A_{name}", reference=VarPowerFlowReferenceType.v_A)
v_b = vfactory.add_var(f"v_B_{name}", reference=VarPowerFlowReferenceType.v_B)
v_c = vfactory.add_var(f"v_C_{name}", reference=VarPowerFlowReferenceType.v_C)
v_dc = vfactory.add_var(f"Vdc_{name}", reference=VarPowerFlowReferenceType.Vdc)
Pt_vsc = vfactory.add_var(f"Pt_vsc_{name}")
Qt_vsc = vfactory.add_var(f"Qt_vsc_{name}")
theta = vfactory.add_var(f"theta_{name}")
omega = vfactory.add_var(f"omega_{name}")
dt_theta = vfactory.add_diff_var(f"dt_theta_{name}", base_var=theta)
Rf = vfactory.add_var(f"Rf_{name}")
Lf = vfactory.add_var(f"Lf_{name}")
Rc = vfactory.add_var(f"Rc_{name}")
Lc = vfactory.add_var(f"Lc_{name}")
Cf = vfactory.add_var(f"Cf_{name}")
Rcap = vfactory.add_var(f"Rcap_{name}")
Kdp = vfactory.add_var(f"Kdp_{name}")
Kdq = vfactory.add_var(f"Kdq_{name}")
fn = vfactory.add_var(f"fn_{name}")
Kp_icl = vfactory.add_var(f"Kp_icl_{name}")
Ki_icl = vfactory.add_var(f"Ki_icl_{name}")
tau_P = vfactory.add_var(f"tau_P_{name}")
tau_Q = vfactory.add_var(f"tau_Q_{name}")
I_max = vfactory.add_var(f"I_max_{name}")
vd_g = vfactory.add_var(f"vd_g_{name}")
vq_g = vfactory.add_var(f"vq_g_{name}")
vd_f = vfactory.add_var(f"vd_f_{name}")
vq_f = vfactory.add_var(f"vq_f_{name}")
vd_c = vfactory.add_var(f"vd_c_{name}")
vq_c = vfactory.add_var(f"vq_c_{name}")
id_g = vfactory.add_var(f"id_g_{name}")
iq_g = vfactory.add_var(f"iq_g_{name}")
id_c = vfactory.add_var(f"id_c_{name}")
iq_c = vfactory.add_var(f"iq_c_{name}")
id_c_ref = vfactory.add_var(f"id_c_ref_{name}")
iq_c_ref = vfactory.add_var(f"iq_c_ref_{name}")
vd_c_ref = vfactory.add_var(f"vd_c_ref_{name}")
vq_c_ref = vfactory.add_var(f"vq_c_ref_{name}")
P = vfactory.add_var(f"P_{name}", reference=VarPowerFlowReferenceType.P)
Q = vfactory.add_var(f"Q_{name}", reference=VarPowerFlowReferenceType.Q)
P_ref = vfactory.add_var(f"P_ref_{name}")
Q_ref = vfactory.add_var(f"Q_ref_{name}")
V_ref = vfactory.add_var(f"V_ref_{name}")
V = vfactory.add_var(f"V_{name}")
park_block, (vd_meas, vq_meas) = park_transform_block(vfactory, [v_a, v_b, v_c], theta, name=f"v_{name}")
eqs = [
vd_g - vd_meas,
vq_g - vq_meas,
vd_f - vd_g - (Rc * id_g - omega * Lc * iq_g),
vq_f - vq_g - (Rc * iq_g + omega * Lc * id_g),
vd_c - vd_f - (Rf * id_c - omega * Lf * iq_c),
vq_c - vq_f - (Rf * iq_c + omega * Lf * id_c),
iq_c - iq_g - (-Cf * omega * vq_f + vd_f / Rcap),
id_c - id_g - (Cf * omega * vd_f + vq_f / Rcap),
P - vfactory.add_const(1.5) * (vq_g * iq_g + vd_g * id_g),
Q - vfactory.add_const(1.5) * (vq_g * id_g - vd_g * iq_g),
]
block_P, P_lp = tf_to_block(vfactory, num=[vfactory.add_const(1)], den=[vfactory.add_const(1), tau_P], x=P, name=f"P_lp_{name}")
block_Q, Q_lp = tf_to_block(vfactory, num=[vfactory.add_const(1)], den=[vfactory.add_const(1), tau_Q], x=Q, name=f"Q_lp_{name}")
block_P.init_eqs = {P_lp: P}
block_Q.init_eqs = {Q_lp: Q}
eqs += [
omega - (1.0 - Kdp * (P_lp - P_ref)),
V - (V_ref - Kdq * (Q_lp - Q_ref)),
dt_theta - 2 * math.pi * fn * (omega - 1.0),
]
vd_ref = vd_f
vq_ref = vq_f
block_vd, id_hat = tf_to_block(vfactory, num=[Ki_icl, Kp_icl], den=[0, 1], x=vd_ref - vd_f, name=f"vd_ctrl_{name}")
block_vq, iq_hat = tf_to_block(vfactory, num=[Ki_icl, Kp_icl], den=[0, 1], x=vq_ref - vq_f, name=f"vq_ctrl_{name}")
i_d_ref_raw = iq_hat + iq_g - Cf * omega * vq_f
i_q_ref_raw = id_hat + id_g + Cf * omega * vd_f
iq_for_lim = sym.max(iq_c, i_q_ref_raw)
id_max = sym.sqrt(sym.max(I_max ** 2 - iq_for_lim ** 2, vfactory.add_const(1e-5)))
i_d_ref_sat = sym.hard_sat(i_d_ref_raw, -id_max, id_max)
i_q_ref_sat = sym.hard_sat(i_q_ref_raw, -I_max, I_max)
i_d_ref_sat_var = vfactory.add_var(f"i_d_ref_sat_{name}")
i_q_ref_sat_var = vfactory.add_var(f"i_q_ref_sat_{name}")
eqs += [
i_d_ref_sat_var - i_d_ref_sat,
i_q_ref_sat_var - i_q_ref_sat,
id_c_ref - i_d_ref_sat_var,
iq_c_ref - i_q_ref_sat_var,
]
block_id, vd_hat = tf_to_block(vfactory, num=[Ki_icl, Kp_icl], den=[0, 1], x=id_c_ref - id_c, name=f"id_ctrl_{name}")
block_iq, vq_hat = tf_to_block(vfactory, num=[Ki_icl, Kp_icl], den=[0, 1], x=iq_c_ref - iq_c, name=f"iq_ctrl_{name}")
eqs += [
vd_c_ref - (vd_hat + vd_f - Lf * omega * iq_c),
vq_c_ref - (vq_hat + vq_f + Lf * omega * id_c),
vd_c - vd_c_ref,
vq_c - vq_c_ref,
Pt_vsc + P,
Qt_vsc + Q,
]
currents_block, (i_A, i_B, i_C) = inverse_park_currents_block(vfactory, id_g, iq_g, theta)
core = Block(
algebraic_eqs=eqs,
algebraic_vars=[
Pt_vsc, Qt_vsc, P, Q, P_ref, Q_ref, V_ref, omega, theta, V,
vd_g, vq_g, vd_f, vq_f, vd_c, vq_c,
id_g, iq_g, id_c, iq_c, id_c_ref, iq_c_ref, vd_c_ref, vq_c_ref,
i_d_ref_sat_var, i_q_ref_sat_var,
],
diff_vars=[dt_theta],
event_dict={
Rf: vfactory.add_const(0.02),
Lf: vfactory.add_const(0.15),
Rc: vfactory.add_const(0.01),
Lc: vfactory.add_const(0.1),
Cf: vfactory.add_const(0.05),
Rcap: vfactory.add_const(1e6),
Kdp: vfactory.add_const(0.05),
Kdq: vfactory.add_const(0.05),
fn: vfactory.add_const(50.0),
Kp_icl: vfactory.add_const(0.05),
Ki_icl: vfactory.add_const(50.0),
tau_P: vfactory.add_const(0.01),
tau_Q: vfactory.add_const(0.01),
I_max: vfactory.add_const(1.2),
},
init_eqs={
theta: vfactory.add_const(0.0),
omega: vfactory.add_const(1.0),
P: -Pt_vsc,
Q: -Qt_vsc,
P_ref: P,
Q_ref: Q,
V_ref: vfactory.add_const(1.0),
V: vfactory.add_const(1.0),
vd_g: vd_meas,
vq_g: vq_meas,
id_g: (2 / 3) * Q / sym.max(vq_g, vfactory.add_const(1e-6)),
iq_g: (2 / 3) * P / sym.max(vq_g, vfactory.add_const(1e-6)),
vd_f: vd_g + (Rc * id_g - omega * Lc * iq_g),
vq_f: vq_g + (Rc * iq_g + omega * Lc * id_g),
id_c: id_g + Cf * omega * vd_f + vq_f / Rcap,
iq_c: iq_g - Cf * omega * vq_f - vd_f / Rcap,
id_c_ref: id_c,
iq_c_ref: iq_c,
i_d_ref_sat_var: id_c,
i_q_ref_sat_var: iq_c,
vd_c_ref: Rf * id_c - Lf * omega * iq_c + vd_f,
vq_c_ref: Rf * iq_c + Lf * omega * id_c + vq_f,
vd_c: vd_c_ref,
vq_c: vq_c_ref,
vd_hat: vd_c_ref - vd_f + Lf * omega * iq_c,
vq_hat: vq_c_ref - vq_f - Lf * omega * id_c,
iq_hat: id_c - iq_g + Cf * vq_f,
id_hat: iq_c - id_g - Cf * vd_f,
},
in_vars=[v_a, v_b, v_c, v_dc],
out_vars=[i_A, i_B, i_C],
external_mapping={
VarPowerFlowReferenceType.v_A: v_a,
VarPowerFlowReferenceType.v_B: v_b,
VarPowerFlowReferenceType.v_C: v_c,
VarPowerFlowReferenceType.Vdc: v_dc,
VarPowerFlowReferenceType.i_A: i_A,
VarPowerFlowReferenceType.i_B: i_B,
VarPowerFlowReferenceType.i_C: i_C,
VarPowerFlowReferenceType.Pt: Pt_vsc,
VarPowerFlowReferenceType.Qt: Qt_vsc,
VarPowerFlowReferenceType.Pf: P,
VarPowerFlowReferenceType.P: P,
VarPowerFlowReferenceType.Q: Q,
},
)
core.add(park_block)
core.add(block_P)
core.add(block_Q)
core.add(block_vd)
core.add(block_vq)
core.add(block_id)
core.add(block_iq)
core.add(currents_block)
core.unify_blocks()
return core