Source code for VeraGridEngine.Templates.Emt.simple_generator_emt_trig_template

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0

import numpy as np

from VeraGridEngine.Devices.Dynamic.var_factory import VarFactory
from VeraGridEngine.Devices.Dynamic.emt_template import EmtModelTemplate
from VeraGridEngine.Utils.Symbolic import symbolic as sym
from VeraGridEngine.Utils.Symbolic.block import Block, find_name_in_block
from VeraGridEngine.enumerations import DeviceType, ParamPowerFlowReferenceType, VarPowerFlowReferenceType
from VeraGridEngine.Templates.Emt.generator_emt_type_template import (
    get_exciter_emt,
    get_governor_emt,
    get_stabilizer_emt,
)


[docs] def get_simple_generator_emt_template_trig_transform( vf: VarFactory, name: str = "simple_emt_type_generator_template_ml", ) -> EmtModelTemplate: """ Multilinear reformulation variant of get_simple_generator_emt_template. This function is intentionally kept equivalent to `Templates/Emt/simple_generator_emt_template.py:get_simple_generator_emt_template` except for replacing direct `sin/cos(theta +/- 2pi/3)` calls with auxiliary `u_sin/u_cos` state variables and trig-identity combinations. """ templ = EmtModelTemplate() templ.tpe = DeviceType.GeneratorDevice templ.name = name templ.block.name = name v_A = vf.add_var(name=f"v_A_{name}", reference=VarPowerFlowReferenceType.v_A) v_B = vf.add_var(name=f"v_B_{name}", reference=VarPowerFlowReferenceType.v_B) v_C = vf.add_var(name=f"v_C_{name}", reference=VarPowerFlowReferenceType.v_C) Tm = vf.add_var(name=f"Tm_{name}") v_f = vf.add_var(name=f"v_f_{name}") Ipk = vf.add_var(name="Ipk", reference=VarPowerFlowReferenceType.Ipk) Vpk = vf.add_var(name="Vpk", reference=VarPowerFlowReferenceType.Vpk) phi = vf.add_var(name="phi", reference=VarPowerFlowReferenceType.phi) phi_v = vf.add_var(name="phi_v", reference=VarPowerFlowReferenceType.phi_v) inputs = [v_A, v_B, v_C] theta = vf.add_var("theta_" + name) omega = vf.add_var(name=f"omega_{name}") psi_d = vf.add_var("psi_d_" + name) psi_q = vf.add_var("psi_q_" + name) psi_f = vf.add_var("psi_f_" + name) psi_0 = vf.add_var("psi_0_" + name) et = vf.add_var("et_" + name) d_omega = vf.add_diff_var(name=f"d_omega_{name}", base_var=omega) d_theta = vf.add_diff_var(name=f"d_theta_{name}", base_var=theta) d_psi_d = vf.add_diff_var(name=f"d_psi_d_{name}", base_var=psi_d) d_psi_q = vf.add_diff_var(name=f"d_psi_q_{name}", base_var=psi_q) d_psi_0 = vf.add_diff_var(name=f"d_psi_0_{name}", base_var=psi_0) d_psi_f = vf.add_diff_var(name=f"d_psi_f_{name}", base_var=psi_f) d_et = vf.add_diff_var(name=f"d_et_{name}", base_var=et) i_A = vf.add_var(name=f"i_A_{name}", reference=VarPowerFlowReferenceType.i_A) i_B = vf.add_var(name=f"i_B_{name}", reference=VarPowerFlowReferenceType.i_B) i_C = vf.add_var(name=f"i_C_{name}", reference=VarPowerFlowReferenceType.i_C) v_d = vf.add_var("v_d_" + name) v_q = vf.add_var("v_q_" + name) v_0 = vf.add_var("v_0_" + name) i_d = vf.add_var("i_d_" + name) i_q = vf.add_var("i_q_" + name) i_0 = vf.add_var("i_0_" + name) i_f = vf.add_var(name=f"i_f_{name}") Te = vf.add_var("Te_" + name) Pe = vf.add_var("Pe_" + name) Qe = vf.add_var("Qe_" + name) Pm = vf.add_var("Pm_" + name) omega_base = vf.add_var("omega_base") H = vf.add_var("H") D = vf.add_var("D") Ra = vf.add_var("Ra") La = vf.add_var("La") Ld = vf.add_var("Ld") Lmd = vf.add_var("Lmd") Lmq = vf.add_var("Lmq") Lf = vf.add_var("Lf") Rf = vf.add_var("Rf") R0 = vf.add_var("R0") L0 = vf.add_var("L0") omega_ref = vf.add_var("omega_ref") delta = vf.add_var("delta_" + name) Kp = vf.add_var("Kp") Ki = vf.add_var("Ki") v_f0 = vf.add_var("v_f0") u_cos = vf.add_var("u_cos") u_sin = vf.add_var("u_sin") d_u_cos = vf.add_diff_var("d_u_cos", base_var=u_cos) d_u_sin = vf.add_diff_var("d_u_sin", base_var=u_sin) c120 = np.cos(2.0 * np.pi / 3.0) s120 = np.sin(2.0 * np.pi / 3.0) sin_t_m120 = u_sin * c120 - u_cos * s120 cos_t_m120 = u_cos * c120 + u_sin * s120 sin_t_p120 = u_sin * c120 + u_cos * s120 cos_t_p120 = u_cos * c120 - u_sin * s120 templ.block = Block( state_eqs=[ -v_d - Ra * i_d + omega * psi_q, -v_q - Ra * i_q - omega * psi_d, -v_0 - R0 * i_0, v_f - Rf * i_f, omega_base * omega, (Tm - Te - D * (omega - omega_ref)) / (2 * H), omega_base * (omega_ref - omega), -(omega_base * omega) * u_sin, (omega_base * omega) * u_cos, ], state_vars=[psi_d, psi_q, psi_0, psi_f, theta, omega, et, u_cos, u_sin], algebraic_eqs=[ psi_d - (Lmd * i_f - (Lmd + La) * i_d), psi_q - (-(Lmq + La) * i_q), psi_0 - (-L0 * i_0), psi_f - ((Lmd + Lf) * i_f - Lmd * i_d), v_d - (2 / 3) * (inputs[0] * u_sin + inputs[1] * sin_t_m120 + inputs[2] * sin_t_p120), v_q - (2 / 3) * (inputs[0] * u_cos + inputs[1] * cos_t_m120 + inputs[2] * cos_t_p120), v_0 - (1 / 3) * (inputs[0] + inputs[1] + inputs[2]), i_A - (i_d * u_sin + i_q * u_cos + i_0), i_B - (i_d * sin_t_m120 + i_q * cos_t_m120 + i_0), i_C - (i_d * sin_t_p120 + i_q * cos_t_p120 + i_0), Te - (3 / 2) * (psi_q * i_d - psi_d * i_q), Pe - (i_A * inputs[0] + i_B * inputs[1] + i_C * inputs[2]), Qe - (1 / np.sqrt(3)) * ((inputs[0] - inputs[1]) * i_C + (inputs[1] - inputs[2]) * i_A + (inputs[2] - inputs[0]) * i_B), Pe - Pm, Tm - (Te + Kp * (omega_ref - omega) + Ki * et), v_f - v_f0, ], algebraic_vars=[i_d, i_q, i_0, i_f, v_d, v_q, v_0, i_A, i_B, i_C, Te, Pe, Qe, Pm, Tm, v_f], in_vars=inputs, out_vars=[i_A, i_B, i_C, omega], ) templ.block.diff_vars = [d_psi_d, d_psi_q, d_psi_0, d_psi_f, d_theta, d_omega, d_et, d_u_cos, d_u_sin] templ.block.external_mapping = { VarPowerFlowReferenceType.P_N: None, VarPowerFlowReferenceType.Q_N: None, VarPowerFlowReferenceType.P_A: None, VarPowerFlowReferenceType.Q_A: None, VarPowerFlowReferenceType.P_B: None, VarPowerFlowReferenceType.Q_B: None, VarPowerFlowReferenceType.P_C: None, VarPowerFlowReferenceType.Q_C: None, VarPowerFlowReferenceType.i_N: None, VarPowerFlowReferenceType.i_A: i_A, VarPowerFlowReferenceType.i_B: i_B, VarPowerFlowReferenceType.i_C: i_C, VarPowerFlowReferenceType.phi_v: phi_v, VarPowerFlowReferenceType.phi: phi, VarPowerFlowReferenceType.Vpk: Vpk, VarPowerFlowReferenceType.Ipk: Ipk, VarPowerFlowReferenceType.d_v_N: None, VarPowerFlowReferenceType.d_v_A: None, VarPowerFlowReferenceType.d_v_B: None, VarPowerFlowReferenceType.d_v_C: None, } templ.block.event_dict = { H: vf.add_const(5.0), D: vf.add_const(2.0), La: vf.add_const(0.15), Lmq: vf.add_const(1.55), Lf: vf.add_const(0.10), Rf: vf.add_const(0.017), R0: vf.add_const(0.001), omega_ref: vf.add_const(1.0), Kp: vf.add_const(2.0), Ki: vf.add_const(2.0), v_f0: vf.add_const(-0.000006702), Lmd: Ld - La, phi_v: vf.add_const(None), phi: vf.add_const(None), Vpk: vf.add_const(None), Ipk: vf.add_const(None), delta: vf.add_const(None), } templ.block.api_obj_mapping = { ParamPowerFlowReferenceType.omega_base: omega_base, ParamPowerFlowReferenceType.R1: Ra, ParamPowerFlowReferenceType.X1: Ld, ParamPowerFlowReferenceType.X0: L0, } templ.block.init_eqs = { et: vf.add_const(0.0), omega: omega_ref, delta: sym.atan((Ra * Ipk * sym.sin(phi) - omega * (Lmq + La) * Ipk * sym.cos(phi)) / (Vpk + Ra * Ipk * sym.cos(phi) + omega * (Lmq + La) * Ipk * sym.sin(phi))), theta: phi_v + delta, u_cos: sym.cos(theta), u_sin: sym.sin(theta), v_d: 2 / 3 * (u_sin * inputs[0] + sin_t_m120 * inputs[1] + sin_t_p120 * inputs[2]), v_q: 2 / 3 * (u_cos * inputs[0] + cos_t_m120 * inputs[1] + cos_t_p120 * inputs[2]), v_0: (1 / 3) * (inputs[0] + inputs[1] + inputs[2]), i_d: 2 / 3 * (u_sin * i_A + sin_t_m120 * i_B + sin_t_p120 * i_C), i_q: 2 / 3 * (u_cos * i_A + cos_t_m120 * i_B + cos_t_p120 * i_C), i_0: (1 / 3) * (i_A + i_B + i_C), psi_q: (v_d + Ra * i_d), psi_d: -(v_q + Ra * i_q), psi_0: -L0 * i_0, i_f: (psi_d + (Lmd + La) * i_d) / Lmd, v_f: i_f * Rf, psi_f: (Lmd + Lf) * i_f - Lmd * i_d, Pe: (i_A * inputs[0] + i_B * inputs[1] + i_C * inputs[2]), Qe: (1 / np.sqrt(3)) * ((inputs[0] - inputs[1]) * i_C + (inputs[1] - inputs[2]) * i_A + (inputs[2] - inputs[0]) * i_B), Te: (3 / 2) * (psi_q * i_d - psi_d * i_q), Pm: Pe, } c0 = vf.add_const(0.0) templ.block.diff_init_eqs = { d_theta: omega_base * omega, d_et: (omega_ref - omega), d_omega: c0, d_psi_d: c0, d_psi_q: c0, d_psi_0: c0, d_psi_f: c0, d_u_cos: -(omega_base * omega) * u_sin, d_u_sin: (omega_base * omega) * u_cos, } return templ
[docs] def get_simple_multilinear_generator_reference_template( vf: VarFactory, name: str = "complete_generator_emt_template_ml", ) -> EmtModelTemplate: templ = EmtModelTemplate(name=name) templ.tpe = DeviceType.GeneratorDevice templ.name = name templ.block.name = name gen_mdl = get_simple_generator_emt_template_trig_transform(vf=vf).block exciter_mdl = get_exciter_emt(vf=vf).block governor_mdl = get_governor_emt(vf=vf).block stabilizer_mdl = get_stabilizer_emt(vf=vf).block gen_i_f = find_name_in_block(f"i_f_{gen_mdl.name}", gen_mdl) gen_te = find_name_in_block(f"Te_{gen_mdl.name}", gen_mdl) gen_omega = find_name_in_block(f"omega_{gen_mdl.name}", gen_mdl) vf.add_connections([gen_mdl.in_vars[4]], [exciter_mdl.out_vars[0]]) vf.add_connections([exciter_mdl.in_vars[0]], [gen_i_f]) vf.add_connections([exciter_mdl.in_vars[1]], [gen_mdl.in_vars[0]]) vf.add_connections([exciter_mdl.in_vars[2]], [gen_mdl.in_vars[1]]) vf.add_connections([exciter_mdl.in_vars[3]], [gen_mdl.in_vars[2]]) vf.add_connections([exciter_mdl.in_vars[4]], [stabilizer_mdl.out_vars[0]]) vf.add_connections([stabilizer_mdl.in_vars[0]], [gen_omega]) vf.add_connections([gen_mdl.in_vars[3]], [governor_mdl.out_vars[0]]) vf.add_connections([governor_mdl.in_vars[0]], [gen_omega]) vf.add_connections([governor_mdl.in_vars[1]], [gen_te]) templ.block.children.append(gen_mdl) templ.block.children.append(governor_mdl) templ.block.children.append(stabilizer_mdl) templ.block.children.append(exciter_mdl) templ.block.unify_blocks() templ.block.external_mapping = { VarPowerFlowReferenceType.v_N: None, VarPowerFlowReferenceType.v_A: gen_mdl.in_vars[0], VarPowerFlowReferenceType.v_B: gen_mdl.in_vars[1], VarPowerFlowReferenceType.v_C: gen_mdl.in_vars[2], VarPowerFlowReferenceType.P_N: None, VarPowerFlowReferenceType.Q_N: None, VarPowerFlowReferenceType.P_A: None, VarPowerFlowReferenceType.Q_A: None, VarPowerFlowReferenceType.P_B: None, VarPowerFlowReferenceType.Q_B: None, VarPowerFlowReferenceType.P_C: None, VarPowerFlowReferenceType.Q_C: None, VarPowerFlowReferenceType.i_N: None, VarPowerFlowReferenceType.i_A: gen_mdl.out_vars[0], VarPowerFlowReferenceType.i_B: gen_mdl.out_vars[1], VarPowerFlowReferenceType.i_C: gen_mdl.out_vars[2], VarPowerFlowReferenceType.phi_v: gen_mdl.in_vars[5], VarPowerFlowReferenceType.phi: gen_mdl.in_vars[6], VarPowerFlowReferenceType.Vpk: gen_mdl.in_vars[7], VarPowerFlowReferenceType.Ipk: gen_mdl.in_vars[8], VarPowerFlowReferenceType.d_v_N: None, VarPowerFlowReferenceType.d_v_A: None, VarPowerFlowReferenceType.d_v_B: None, VarPowerFlowReferenceType.d_v_C: None, } templ.block.api_obj_mapping = { ParamPowerFlowReferenceType.omega_base: gen_mdl.api_obj_mapping[ParamPowerFlowReferenceType.omega_base], ParamPowerFlowReferenceType.R1: gen_mdl.api_obj_mapping[ParamPowerFlowReferenceType.R1], ParamPowerFlowReferenceType.X1: gen_mdl.api_obj_mapping[ParamPowerFlowReferenceType.X1], ParamPowerFlowReferenceType.X0: gen_mdl.api_obj_mapping[ParamPowerFlowReferenceType.X0], } templ.block.in_vars = [gen_mdl.in_vars[0], gen_mdl.in_vars[1], gen_mdl.in_vars[2]] templ.block.out_vars = [gen_mdl.out_vars[0], gen_mdl.out_vars[1], gen_mdl.out_vars[2]] return templ
[docs] def get_complete_generator_template_emt_trig_transform( vf: VarFactory, name: str = "complete_generator_emt_template_ml", ) -> EmtModelTemplate: """ Backward-compatible alias for multilinear reference complete generator. """ return get_simple_multilinear_generator_reference_template(vf=vf, name=name)