Source code for VeraGridEngine.Templates.Emt.converter_emt_multilinear_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

from __future__ import annotations

import numpy as np

import VeraGridEngine.Utils.Symbolic.symbolic as sym
from VeraGridEngine.Devices.Dynamic.emt_template import EmtModelTemplate
from VeraGridEngine.Devices.Dynamic.var_factory import VarFactory
from VeraGridEngine.Templates.Emt.converter_emt_template import (
    _converter_control_type_code,
    _resolve_converter_control_reference_exprs,
)
from VeraGridEngine.Utils.Symbolic.block import VarPowerFlowReferenceType
from VeraGridEngine.Utils.Symbolic.symbolic import Expr, Var
from VeraGridEngine.enumerations import DeviceType, ParamPowerFlowReferenceType


[docs] def get_emt_ideal_converter_multilinear( vf: VarFactory, name: str = "ideal_converter_emt_ml", ) -> EmtModelTemplate: """ Build one averaged EMT converter model using trig-transform states. This variant keeps the exact averaged converter equations from ``get_emt_ideal_converter`` and only replaces direct ``sin(theta)`` and ``cos(theta)`` occurrences with ``symbolic_ml.trig_transform`` variables. """ templ = EmtModelTemplate() templ.tpe = DeviceType.VscDevice templ.name = name templ.block.name = name v_A: Var = vf.add_var(name=f"v_A_{name}", reference=VarPowerFlowReferenceType.v_A) v_B: Var = vf.add_var(name=f"v_B_{name}", reference=VarPowerFlowReferenceType.v_B) v_C: Var = vf.add_var(name=f"v_C_{name}", reference=VarPowerFlowReferenceType.v_C) v_dc: Var = vf.add_var(name=f"v_dc_{name}", reference=VarPowerFlowReferenceType.Vdc) i_A: Var = vf.add_var(name=f"i_A_{name}", reference=VarPowerFlowReferenceType.i_A) i_B: Var = vf.add_var(name=f"i_B_{name}", reference=VarPowerFlowReferenceType.i_B) i_C: Var = vf.add_var(name=f"i_C_{name}", reference=VarPowerFlowReferenceType.i_C) i_dc: Var = vf.add_var(name=f"i_dc_{name}", reference=VarPowerFlowReferenceType.Idc) P: Var = vf.add_var(name=f"P_{name}", reference=VarPowerFlowReferenceType.P) Q: Var = vf.add_var(name=f"Q_{name}", reference=VarPowerFlowReferenceType.Q) theta: Var = vf.add_var(name=f"theta_{name}") d_theta: Var = vf.add_diff_var(name=f"d_theta_{name}", base_var=theta) P_ref: Var = vf.add_var(name=f"P_ref_{name}") Q_ref: Var = vf.add_var(name=f"Q_ref_{name}") Vdc_ref: Var = vf.add_var(name=f"Vdc_ref_{name}") P_loss: Var = vf.add_var(name=f"P_loss_{name}") P0: Var = vf.add_var(name=f"P0_{name}") omega_base: Var = vf.add_var(name=f"omega_base_{name}") sbase: Var = vf.add_var(name=f"sbase_{name}") control1: Var = vf.add_var(name=f"control1_{name}") control2: Var = vf.add_var(name=f"control2_{name}") control1_val: Var = vf.add_var(name=f"control1_val_{name}") control2_val: Var = vf.add_var(name=f"control2_val_{name}") phi_v: Var = vf.add_var(name=f"phi_v_{name}") Vpk: Var = vf.add_var(name=f"Vpk_{name}") Vdc_nom: Var = vf.add_var(name=f"Vdc_nom_{name}") p_ref_expr: Expr q_ref_expr: Expr vdc_ref_expr: Expr regulate_vdc: Expr regulate_q: Expr _unused_regulate_active: Expr p_ref_expr, q_ref_expr, vdc_ref_expr, regulate_vdc, regulate_q, _unused_regulate_active = _resolve_converter_control_reference_exprs( control1=control1, control2=control2, control1_val=control1_val, control2_val=control2_val, p0=P0, vdc_nom=Vdc_nom, ) eps = vf.add_const(1e-10) c0 = vf.add_const(0.0) c_half = vf.add_const(0.5) c_two_over_three = vf.add_const(2.0 / 3.0) c_sqrt3_over_two = vf.add_const(np.sqrt(3.0) / 2.0) i_d_cmd: Var = vf.add_var(name=f"i_d_cmd_{name}") i_q_cmd: Var = vf.add_var(name=f"i_q_cmd_{name}") u_cos: Var = vf.add_var(name=f"u_cos_{name}") u_sin: Var = vf.add_var(name=f"u_sin_{name}") d_u_cos_var: Var = vf.add_diff_var(name=f"d_u_cos_{name}", base_var=u_cos) d_u_sin_var: Var = vf.add_diff_var(name=f"d_u_sin_{name}", base_var=u_sin) P_dc_cmd = P_ref + vf.add_const(2.0) * (v_dc - Vdc_ref) * regulate_vdc Q_cmd = Q_ref * regulate_q P_dc_cmd_pu = P_dc_cmd / (sbase + eps) Q_cmd_pu = Q_cmd / (sbase + eps) P_ac_cmd_pu = P_dc_cmd_pu + P_loss / (sbase + eps) i_A_cmd = i_d_cmd * u_cos + i_q_cmd * u_sin i_B_cmd = ((-c_half * i_d_cmd - c_sqrt3_over_two * i_q_cmd) * u_cos + ((c_sqrt3_over_two * i_d_cmd) - c_half * i_q_cmd) * u_sin) i_C_cmd = ((-c_half * i_d_cmd + c_sqrt3_over_two * i_q_cmd) * u_cos + ((-c_sqrt3_over_two * i_d_cmd) - c_half * i_q_cmd) * u_sin) Q_init_pu = q_ref_expr * regulate_q / (sbase + eps) P_dc_init_pu = p_ref_expr / (sbase + eps) P_ac_init_pu = P_dc_init_pu + P_loss / (sbase + eps) i_d_init = c_two_over_three * Q_init_pu / (Vpk + eps) i_q_init = c_two_over_three * P_ac_init_pu / (Vpk + eps) i_A_init = i_d_init * sym.cos(phi_v) + i_q_init * sym.sin(phi_v) i_B_init = ((-c_half * i_d_init - c_sqrt3_over_two * i_q_init) * sym.cos(phi_v) + ((c_sqrt3_over_two * i_d_init) - c_half * i_q_init) * sym.sin(phi_v)) i_C_init = ((-c_half * i_d_init + c_sqrt3_over_two * i_q_init) * sym.cos(phi_v) + ((-c_sqrt3_over_two * i_d_init) - c_half * i_q_init) * sym.sin(phi_v)) templ.block.state_eqs = [ omega_base, -(omega_base * u_sin), omega_base * u_cos, ] templ.block.state_vars = [theta, u_cos, u_sin] templ.block.diff_vars = [d_theta, d_u_cos_var, d_u_sin_var] templ.block.algebraic_vars = [ P_ref, Q_ref, Vdc_ref, i_A, i_B, i_C, i_dc, P, Q, i_d_cmd, i_q_cmd, ] templ.block.algebraic_eqs = [ P_ref - p_ref_expr, Q_ref - q_ref_expr, Vdc_ref - vdc_ref_expr, i_d_cmd - c_two_over_three * Q_cmd_pu / (Vpk + eps), i_q_cmd - c_two_over_three * P_ac_cmd_pu / (Vpk + eps), i_A - i_A_cmd, i_B - i_B_cmd, i_C - i_C_cmd, v_dc * i_dc + P_dc_cmd_pu, P - (v_A * i_A + v_B * i_B + v_C * i_C), Q - (1 / np.sqrt(3.0)) * ((v_A - v_B) * i_C + (v_B - v_C) * i_A + (v_C - v_A) * i_B), ] templ.block.init_eqs = { theta: phi_v, i_A: i_A_init, i_B: i_B_init, i_C: i_C_init, u_cos: sym.cos(phi_v), u_sin: sym.sin(phi_v), i_d_cmd: i_d_init, i_q_cmd: i_q_init, i_dc: -P_dc_init_pu / (Vdc_ref + eps), P_ref: p_ref_expr, Q_ref: q_ref_expr, Vdc_ref: vdc_ref_expr, P: P_ac_init_pu, Q: Q_init_pu, } templ.block.diff_init_eqs = { d_theta: omega_base, d_u_cos_var: -(omega_base * u_sin), d_u_sin_var: omega_base * u_cos, } templ.block.in_vars = [v_A, v_B, v_C, v_dc] templ.block.out_vars = [i_A, i_B, i_C, i_dc] templ.block.children = [] templ.block.event_dict.update({ P_loss: vf.add_const(0.0), P0: vf.add_const(0.0), omega_base: vf.add_const(2.0 * np.pi * 50.0), sbase: vf.add_const(1.0), control1: vf.add_const(float(_converter_control_type_code(None))), control2: vf.add_const(float(_converter_control_type_code(None))), control1_val: vf.add_const(0.0), control2_val: vf.add_const(0.0), phi_v: vf.add_const(0.0), Vpk: vf.add_const(np.sqrt(2.0)), Vdc_nom: vf.add_const(1.0), }) templ.block.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.Idc: i_dc, VarPowerFlowReferenceType.P: P, VarPowerFlowReferenceType.Q: Q, VarPowerFlowReferenceType.phi_v: phi_v, VarPowerFlowReferenceType.Vpk: Vpk, } templ.block.api_obj_mapping = { ParamPowerFlowReferenceType.Sbase: sbase, ParamPowerFlowReferenceType.converter_loss_power_0: P_loss, ParamPowerFlowReferenceType.P0: P0, ParamPowerFlowReferenceType.omega_base: omega_base, ParamPowerFlowReferenceType.converter_control_mode_1: control1, ParamPowerFlowReferenceType.converter_control_mode_2: control2, ParamPowerFlowReferenceType.converter_control_target_1: control1_val, ParamPowerFlowReferenceType.converter_control_target_2: control2_val, } return templ