Esempio n. 1
0
    def __init__(self, u, T1, T2, T3, T4, zero_out=False, name=None, tex_name=None, info=None):
        super(LeadLag2ndOrd, self).__init__(name=name, tex_name=tex_name, info=info)
        self.u = dummify(u)
        self.T1 = dummify(T1)
        self.T2 = dummify(T2)
        self.T3 = dummify(T3)
        self.T4 = dummify(T4)
        self.zero_out = zero_out
        self.enforce_tex_name((self.T1, self.T2, self.T3, self.T4))

        self.x1 = State(info='State #1 in 2nd order lead-lag', tex_name="x'", t_const=self.T2)
        self.x2 = State(info='State #2 in 2nd order lead-lag', tex_name="x''")
        self.y = Algeb(info='Output of 2nd order lead-lag', tex_name='y', diag_eps=1e-6)

        self.vars = {'x1': self.x1, 'x2': self.x2, 'y': self.y}

        if self.zero_out is True:
            self.LT1 = LessThan(T1, dummify(0), equal=True, enable=zero_out, tex_name='LT',
                                cache=True, z0=1, z1=0)
            self.LT2 = LessThan(T2, dummify(0), equal=True, enable=zero_out, tex_name='LT',
                                cache=True, z0=1, z1=0)
            self.LT3 = LessThan(T4, dummify(0), equal=True, enable=zero_out, tex_name='LT',
                                cache=True, z0=1, z1=0)
            self.LT4 = LessThan(T4, dummify(0), equal=True, enable=zero_out, tex_name='LT',
                                cache=True, z0=1, z1=0)
            self.x2.discrete = (self.LT1, self.LT2, self.LT3, self.LT4)
            self.vars['LT1'] = self.LT1
            self.vars['LT2'] = self.LT2
            self.vars['LT3'] = self.LT3
            self.vars['LT4'] = self.LT4
Esempio n. 2
0
    def __init__(self, system, config):
        PVD1Model.__init__(self, system, config)

        # --- Determine whether the energy storage is in charging or discharging mode ---
        self.LTN = LessThan(self.Ipout_y, 0.0)

        # --- Add integrator. Assume that state-of-charge is the initial condition ---
        self.pIG = Integrator(
            u='-LTN_z1*(v * Ipout_y)*EtaC - LTN_z0*(v * Ipout_y)/EtaD',
            T=self.Tf,
            K='sys_mva / 3600 / En',
            y0=self.SOCinit,
            check_init=False,
        )

        # --- Add hard limiter for SOC ---
        self.SOClim = HardLimiter(u=self.pIG_y,
                                  lower=self.SOCmin,
                                  upper=self.SOCmax)

        # --- Add Ipmax, Ipmin, and Ipcmd ---
        self.Ipmax.v_str = '(1-SOClim_zl)*(SWPQ_s1 * ialim + SWPQ_s0 * sqrt(Ipmaxsq0))'
        self.Ipmax.e_str = '(1-SOClim_zl)*(SWPQ_s1 * ialim + SWPQ_s0 * sqrt(Ipmaxsq)) - Ipmax'

        self.Ipmin = Algeb(
            info='Minimum value of Ip',
            v_str=
            '-(1-SOClim_zu) * (SWPQ_s1 * ialim + SWPQ_s0 * sqrt(Ipmaxsq0))',
            e_str=
            '-(1-SOClim_zu) * (SWPQ_s1 * ialim + SWPQ_s0 * sqrt(Ipmaxsq)) - Ipmin',
        )

        self.Ipcmd.lim.lower = self.Ipmin
        self.Ipcmd.y.deps = ['Ipmin']
Esempio n. 3
0
    def __init__(self,
                 u,
                 T1,
                 T2,
                 K=1,
                 zero_out=True,
                 name=None,
                 tex_name=None,
                 info=None):
        super().__init__(name=name, tex_name=tex_name, info=info)
        self.u = dummify(u)
        self.T1 = dummify(T1)
        self.T2 = dummify(T2)
        self.K = dummify(K)
        self.zero_out = zero_out

        self.enforce_tex_name((self.T1, self.T2))

        self.x = State(info='State in lead-lag',
                       tex_name="x'",
                       t_const=self.T2)
        self.y = Algeb(info='Output of lead-lag', tex_name=r'y', diag_eps=1e-6)
        self.vars = {'x': self.x, 'y': self.y}

        if self.zero_out is True:
            self.LT1 = LessThan(T1,
                                dummify(0),
                                equal=True,
                                enable=zero_out,
                                tex_name='LT',
                                cache=True,
                                z0=1,
                                z1=0)
            self.LT2 = LessThan(T2,
                                dummify(0),
                                equal=True,
                                enable=zero_out,
                                tex_name='LT',
                                cache=True,
                                z0=1,
                                z1=0)
            self.x.discrete = (self.LT1, self.LT2)
            self.vars['LT1'] = self.LT1
            self.vars['LT2'] = self.LT2
Esempio n. 4
0
    def __init__(self, u, T, K, name=None, zero_out=True, tex_name=None, info=None):
        super().__init__(u, T, K, name=name, tex_name=tex_name, info=info)
        self.zero_out = zero_out
        self.LT = LessThan(K,
                           dummify(0),
                           equal=True,
                           enable=zero_out,
                           tex_name='LT',
                           cache=True,
                           z0=1, z1=0)

        self.vars.update({'LT': self.LT})
Esempio n. 5
0
    def __init__(self):

        self.SAT = ExcQuadSat(
            self.E1,
            self.SE1,
            self.E2,
            self.SE2,
            info='Field voltage saturation',
        )

        # Input (VR - VFE)
        self.INT = Integrator(
            u=self.INTin,
            T=self.TE,
            K=1,
            y0=0,
            info='V_E, integrator',
        )
        self.INT.y.v_str = 0.1
        self.INT.y.v_iter = 'INT_y * FEX_y - vf0'

        self.SL = LessThan(u=self.INT_y,
                           bound=self.SAT_A,
                           equal=False,
                           enable=True,
                           cache=False)

        self.Se = Algeb(
            tex_name=r"V_{out}*S_e(|V_{out}|)",
            info='saturation output',
            v_str='Indicator(INT_y > SAT_A) * SAT_B * (INT_y - SAT_A) ** 2',
            e_str='ue * (SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B - Se)',
            diag_eps=True,
        )

        self.VFE = Algeb(
            info='Combined saturation feedback',
            tex_name='V_{FE}',
            unit='p.u.',
            v_str='INT_y * KE + Se + XadIfd * KD',
            e_str='ue * (INT_y * KE + Se + XadIfd * KD - VFE)',
            diag_eps=True,
        )
Esempio n. 6
0
    def __init__(self):
        # parameter checking for `xl`
        self._xlc = InitChecker(u=self.xl, info='(xl <= xd2)', upper=self.xd2)

        self.gd1 = ConstService(v_str='(xd2 - xl) / (xd1 - xl)',
                                tex_name=r"\gamma_{d1}")
        self.gq1 = ConstService(v_str='(xq2 - xl) / (xq1 - xl)',
                                tex_name=r"\gamma_{q1}")
        self.gd2 = ConstService(v_str='(xd1 - xd2) / (xd1 - xl) ** 2',
                                tex_name=r"\gamma_{d2}")
        self.gq2 = ConstService(v_str='(xq1 - xq2) / (xq1 - xl) ** 2',
                                tex_name=r"\gamma_{q2}")
        self.gqd = ConstService(v_str='(xq - xl) / (xd - xl)',
                                tex_name=r"\gamma_{qd}")

        # correct S12 to 1.0 if is zero
        self._fS12 = FlagValue(self.S12, value=0)
        self._S12 = ConstService(v_str='S12 + (1-_fS12)',
                                 info='Corrected S12',
                                 tex_name='S_{1.2}')
        # Saturation services
        # Note:
        # To disable saturation, set S10 = 0, S12 = 1 so that SAT_B = 0.
        self.SAT = ExcQuadSat(1.0, self.S10, 1.2, self.S12, tex_name='S_{AT}')

        # Initialization reference: OpenIPSL at
        #   https://github.com/OpenIPSL/OpenIPSL/blob/master/OpenIPSL/Electrical/Machines/PSSE/GENROU.mo

        # internal voltage and rotor angle calculation
        self._V = ConstService(v_str='v * exp(1j * a)',
                               tex_name='V_c',
                               info='complex bus voltage',
                               vtype=np.complex)
        self._S = ConstService(v_str='p0 - 1j * q0',
                               tex_name='S',
                               info='complex terminal power',
                               vtype=np.complex)
        self._Zs = ConstService(v_str='ra + 1j * xd2',
                                tex_name='Z_s',
                                info='equivalent impedance',
                                vtype=np.complex)
        self._It = ConstService(v_str='_S / conj(_V)',
                                tex_name='I_t',
                                info='complex terminal current',
                                vtype=np.complex)
        self._Is = ConstService(tex_name='I_s',
                                v_str='_It + _V / _Zs',
                                info='equivalent current source',
                                vtype=np.complex)

        self.psi20 = ConstService(
            tex_name=r"\psi''_0",
            v_str='_Is * _Zs',
            info='sub-transient flux linkage in stator reference',
            vtype=np.complex)
        self.psi20_arg = ConstService(tex_name=r"\theta_{\psi''0}",
                                      v_str='arg(psi20)')
        self.psi20_abs = ConstService(tex_name=r"|\psi''_0|",
                                      v_str='abs(psi20)')
        self._It_arg = ConstService(tex_name=r"\theta_{It0}", v_str='arg(_It)')
        self._psi20_It_arg = ConstService(tex_name=r"\theta_{\psi a It}",
                                          v_str='psi20_arg - _It_arg')

        self.Se0 = ConstService(
            tex_name=r"S_{e0}",
            v_str=
            'Indicator(psi20_abs>=SAT_A) * (psi20_abs - SAT_A) ** 2 * SAT_B / psi20_abs'
        )

        self._a = ConstService(tex_name=r"a'",
                               v_str='psi20_abs * (1 + Se0*gqd)')
        self._b = ConstService(tex_name=r"b'",
                               v_str='abs(_It) * (xq2 - xq)')  # xd2 == xq2

        self.delta0 = ConstService(
            tex_name=r'\delta_0',
            v_str=
            'atan(_b * cos(_psi20_It_arg) / (_b * sin(_psi20_It_arg) - _a)) + '
            'psi20_arg')
        self._Tdq = ConstService(tex_name=r"T_{dq}",
                                 v_str='cos(delta0) - 1j * sin(delta0)',
                                 vtype=np.complex)
        self.psi20_dq = ConstService(tex_name=r"\psi''_{0,dq}",
                                     v_str='psi20 * _Tdq',
                                     vtype=np.complex)
        self.It_dq = ConstService(tex_name=r"I_{t,dq}",
                                  v_str='conj(_It * _Tdq)',
                                  vtype=np.complex)

        self.psi2d0 = ConstService(tex_name=r"\psi_{ad0}",
                                   v_str='re(psi20_dq)')
        self.psi2q0 = ConstService(tex_name=r"\psi_{aq0}",
                                   v_str='-im(psi20_dq)')

        self.Id0 = ConstService(v_str='im(It_dq)', tex_name=r'I_{d0}')
        self.Iq0 = ConstService(v_str='re(It_dq)', tex_name=r'I_{q0}')

        self.vd0 = ConstService(v_str='psi2q0 + xq2*Iq0 - ra * Id0',
                                tex_name=r'V_{d0}')
        self.vq0 = ConstService(v_str='psi2d0 - xd2*Id0 - ra*Iq0',
                                tex_name=r'V_{q0}')

        self.tm0 = ConstService(
            tex_name=r'\tau_{m0}',
            v_str='u * ((vq0 + ra * Iq0) * Iq0 + (vd0 + ra * Id0) * Id0)')

        # `vf0` is also equal to `vq + xd*Id +ra*Iq + Se*psi2d` from phasor diagram
        self.vf0 = ConstService(tex_name=r'v_{f0}',
                                v_str='(Se0 + 1)*psi2d0 + (xd - xd2) * Id0')
        self.psid0 = ConstService(tex_name=r"\psi_{d0}",
                                  v_str='u * (ra * Iq0) + vq0')
        self.psiq0 = ConstService(tex_name=r"\psi_{q0}",
                                  v_str='-u * (ra * Id0) - vd0')

        # initialization of internal voltage and delta
        self.e1q0 = ConstService(tex_name="e'_{q0}",
                                 v_str='Id0*(-xd + xd1) - Se0*psi2d0 + vf0')

        self.e1d0 = ConstService(tex_name="e'_{d0}",
                                 v_str='Iq0*(xq - xq1) - Se0*gqd*psi2q0')

        self.e2d0 = ConstService(tex_name="e''_{d0}",
                                 v_str='Id0*(xl - xd) - Se0*psi2d0 + vf0')
        self.e2q0 = ConstService(tex_name="e''_{q0}",
                                 v_str='-Iq0*(xl - xq) - Se0*gqd*psi2q0')

        # begin variables and equations
        self.psi2q = Algeb(
            tex_name=r"\psi_{aq}",
            info='q-axis air gap flux',
            v_str='psi2q0',
            e_str='gq1*e1d + (1-gq1)*e2q - psi2q',
        )

        self.psi2d = Algeb(tex_name=r"\psi_{ad}",
                           info='d-axis air gap flux',
                           v_str='u * psi2d0',
                           e_str='gd1*e1q + gd2*(xd1-xl)*e2d - psi2d')

        self.psi2 = Algeb(
            tex_name=r"\psi_a",
            info='air gap flux magnitude',
            v_str='u * abs(psi20_dq)',
            e_str='psi2d **2 + psi2q ** 2 - psi2 ** 2',
            diag_eps=True,
        )

        # `LT` is a reserved keyword for SymPy
        self.SL = LessThan(u=self.psi2,
                           bound=self.SAT_A,
                           equal=False,
                           enable=True,
                           cache=False)

        self.Se = Algeb(
            tex_name=r"S_e(|\psi_{a}|)",
            info='saturation output',
            v_str='u * Se0',
            e_str='SL_z0 * (psi2 - SAT_A) ** 2 * SAT_B - psi2 * Se',
            diag_eps=True,
        )

        # separated `XadIfd` from `e1q` using \dot(e1q) = (vf - XadIfd) / Td10
        self.XadIfd.e_str = 'u * (e1q + (xd-xd1) * (gd1*Id - gd2*e2d + gd2*e1q) + Se*psi2d) - XadIfd'

        # `XadI1q` can also be given in `(xq-xq1)*gq2*(e1d-e2q+(xq1-xl)*Iq) + e1d - Iq*(xq-xq1) + Se*psi2q*gqd`
        self.XaqI1q =\
            Algeb(tex_name='X_{aq}I_{1q}',
                  info='q-axis reaction',
                  unit='p.u (kV)',
                  v_str='0',
                  e_str='e1d + (xq-xq1) * (gq2*e1d - gq2*e2q - gq1*Iq) + Se*psi2q*gqd - XaqI1q'
                  )

        self.e1q = State(
            info='q-axis transient voltage',
            tex_name=r"e'_q",
            v_str='u * e1q0',
            e_str='(-XadIfd + vf)',
            t_const=self.Td10,
        )

        self.e1d = State(
            info='d-axis transient voltage',
            tex_name=r"e'_d",
            v_str='e1d0',
            e_str='-XaqI1q',
            t_const=self.Tq10,
        )

        self.e2d = State(
            info='d-axis sub-transient voltage',
            tex_name=r"e''_d",
            v_str='u * e2d0',
            e_str='(-e2d + e1q - (xd1 - xl) * Id)',
            t_const=self.Td20,
        )

        self.e2q = State(
            info='q-axis sub-transient voltage',
            tex_name=r"e''_q",
            v_str='e2q0',
            e_str='(-e2q + e1d + (xq1 - xl) * Iq)',
            t_const=self.Tq20,
        )

        self.Iq.e_str += '+ xq2*Iq + psi2q'

        self.Id.e_str += '+ xd2*Id - psi2d'
Esempio n. 7
0
    def __init__(self):
        self.gd1 = ConstService(v_str='(xd2 - xl) / (xd1 - xl)',
                                tex_name=r"\gamma_{d1}")
        self.gq1 = ConstService(v_str='(xq2 - xl) / (xq1 - xl)',
                                tex_name=r"\gamma_{q1}")
        self.gd2 = ConstService(v_str='(xd1 - xd2) / (xd1 - xl) ** 2',
                                tex_name=r"\gamma_{d2}")
        self.gq2 = ConstService(v_str='(xq1 - xq2) / (xq1 - xl) ** 2',
                                tex_name=r"\gamma_{q2}")
        self.gqd = ConstService(v_str='(xq - xl) / (xd - xl)',
                                tex_name=r"\gamma_{qd}")

        # Saturation services
        # when S10 = 0, S12 = 1, Saturation is disabled. Thus, Sat = 0, A = 1, B = 0
        self.Sat = ConstService(v_str='sqrt((S10 * 1) / (S12 * 1.2))',
                                tex_name=r"S_{at}")
        self.SA = ConstService(v_str='1.2 + 0.2 / (Sat - 1)', tex_name='S_A')
        self.SB = ConstService(
            v_str=
            '((Sat < 0) + (Sat > 0)) * 1.2 * S12 * ((Sat - 1) / 0.2) ** 2',
            tex_name='S_B')

        # internal voltage and rotor angle calculation

        # Initialization reference: OpenIPSL at
        #   https://github.com/OpenIPSL/OpenIPSL/blob/master/OpenIPSL/Electrical/Machines/PSSE/GENROU.mo

        self._V = ConstService(v_str='v * exp(1j * a)',
                               tex_name='V_c',
                               info='complex terminal voltage')
        self._S = ConstService(v_str='p0 - 1j * q0',
                               tex_name='S',
                               info='complex terminal power')
        self._Zs = ConstService(v_str='ra + 1j * xd2',
                                tex_name='Z_s',
                                info='equivalent impedance')
        self._It = ConstService(v_str='_S / conj(_V)',
                                tex_name='I_t',
                                info='complex terminal current')
        self._Is = ConstService(tex_name='I_s',
                                v_str='_It + _V / _Zs',
                                info='equivalent current source')

        self.psia0 = ConstService(
            tex_name=r"\psi_{a0}",
            v_str='_Is * _Zs',
            info='subtransient flux linkage in stator reference')
        self.psia0_arg = ConstService(tex_name=r"\theta_{\psi a0}",
                                      v_str='arg(psia0)')
        self.psia0_abs = ConstService(tex_name=r"|\psi_{a0}|",
                                      v_str='abs(psia0)')
        self._It_arg = ConstService(tex_name=r"\theta_{It0}", v_str='arg(_It)')
        self._psia0_It_arg = ConstService(tex_name=r"\theta_{\psi a It}",
                                          v_str='psia0_arg - _It_arg')

        self.Se0 = ConstService(
            tex_name=r"S_{e0}",
            v_str='(psia0_abs >= SA) * (psia0_abs - SA) ** 2 * SB / psia0_abs')

        self._a = ConstService(tex_name=r"a",
                               v_str='psia0_abs + psia0_abs * Se0 * gqd')
        self._b = ConstService(tex_name=r"b",
                               v_str='abs(_It) * (xq2 - xq)')  # xd2 == xq2

        self.delta0 = ConstService(
            tex_name=r'\delta_0',
            v_str=
            'atan(_b * cos(_psia0_It_arg) / (_b * sin(_psia0_It_arg) - _a)) + '
            'psia0_arg')
        self._Tdq = ConstService(tex_name=r"T_{dq}",
                                 v_str='cos(delta0) - 1j * sin(delta0)')
        self.psia0_dq = ConstService(tex_name=r"\psi_{a0,dq}",
                                     v_str='psia0 * _Tdq')
        self.It_dq = ConstService(tex_name=r"I_{t,dq}",
                                  v_str='conj(_It * _Tdq)')

        self.psiad0 = ConstService(tex_name=r"\psi_{ad0}",
                                   v_str='re(psia0_dq)')
        self.psiaq0 = ConstService(tex_name=r"\psi_{aq0}",
                                   v_str='im(psia0_dq)')

        self.Id0 = ConstService(v_str='im(It_dq)', tex_name=r'I_{d0}')
        self.Iq0 = ConstService(v_str='re(It_dq)', tex_name=r'I_{q0}')

        self.vd0 = ConstService(v_str='-(psiaq0 - xq2*Iq0) - ra * Id0',
                                tex_name=r'V_{d0}')
        self.vq0 = ConstService(v_str='psiad0 - xd2*Id0 - ra*Iq0',
                                tex_name=r'V_{q0}')

        self.tm0 = ConstService(
            tex_name=r'\tau_{m0}',
            v_str='u * ((vq0 + ra * Iq0) * Iq0 + (vd0 + ra * Id0) * Id0)')

        self.vf0 = ConstService(tex_name=r'v_{f0}',
                                v_str='(Se0 + 1)*psiad0 + (xd - xd2) * Id0')
        self.psid0 = ConstService(tex_name=r"\psi_{d0}",
                                  v_str='u * (ra * Iq0) + vq0')
        self.psiq0 = ConstService(tex_name=r"\psi_{q0}",
                                  v_str='-u * (ra * Id0) - vd0')

        # initialization of internal voltage and delta
        self.e1q0 = ConstService(tex_name="e'_{q0}",
                                 v_str='Id0*(-xd + xd1) - Se0*psiad0 + vf0')

        self.e1d0 = ConstService(tex_name="e'_{d0}",
                                 v_str='Iq0*(xq - xq1) + Se0*gqd*psiaq0')

        self.e2d0 = ConstService(tex_name="e''_{d0}",
                                 v_str='Id0*(xl - xd) - Se0*psiad0 + vf0')
        self.e2q0 = ConstService(tex_name="e''_{q0}",
                                 v_str='Iq0*(xl - xq) - Se0*gqd*psiaq0')

        # begin variables and equations
        self.psiaq = Algeb(tex_name=r"\psi_{aq}",
                           info='q-axis air gap flux',
                           v_str='psiaq0',
                           e_str='psiq + xq2 * Iq - psiaq')

        self.psiad = Algeb(tex_name=r"\psi_{ad}",
                           info='d-axis air gap flux',
                           v_str='psiad0',
                           e_str='-psiad + gd1 * e1q + gd2 * (xd1 - xl) * e2d')

        self.psia = Algeb(tex_name=r"\psi_{a}",
                          info='air gap flux magnitude',
                          v_str='abs(psia0_dq)',
                          e_str='sqrt(psiad **2 + psiaq ** 2) - psia')

        self.Slt = LessThan(u=self.psia,
                            bound=self.SA,
                            equal=False,
                            enable=True)

        self.Se = Algeb(tex_name=r"S_e(|\psi_{a}|)",
                        info='saturation output',
                        v_str='Se0',
                        e_str='Slt_z0 * (psia - SA) ** 2 * SB / psia - Se')

        self.e1q = State(
            info='q-axis transient voltage',
            tex_name=r"e'_q",
            v_str='e1q0',
            e_str=
            '(-e1q - (xd - xd1) * (Id - gd2 * e2d - (1 - gd1) * Id + gd2 * e1q) - '
            'Se * psiad + vf) / Td10')
        self.e1d = State(
            info='d-axis transient voltage',
            tex_name=r"e'_d",
            v_str='e1d0',
            e_str=
            '(-e1d + (xq - xq1) * (Iq - gq2 * e2q - (1 - gq1) * Iq - gq2 * e1d) + '
            'Se * gqd * psiaq) / Tq10')

        self.e2d = State(info='d-axis sub-transient voltage',
                         tex_name=r"e''_d",
                         v_str='e2d0',
                         e_str='(-e2d + e1q - (xd1 - xl) * Id) / Td20')

        self.e2q = State(info='q-axis sub-transient voltage',
                         tex_name=r"e''_q",
                         v_str='e2q0',
                         e_str='(-e2q - e1d - (xq1 - xl) * Iq) / Tq20')

        self.Id.e_str += '+ xd2 * Id - gd1 * e1q - (1 - gd1) * e2d'
        self.Iq.e_str += '+ xq2 * Iq + gq1 * e1d - (1 - gq1) * e2q'
Esempio n. 8
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)
        self.flags.nr_iter = True

        self.SAT = ExcQuadSat(self.E1, self.SE1, self.E2, self.SE2,
                              info='Field voltage saturation',
                              )
        self.SL = LessThan(u=self.vout, bound=self.SAT_A, equal=False, enable=True, cache=False)

        self.Se0 = ConstService(info='Initial saturation output',
                                tex_name='S_{e0}',
                                v_str='Indicator(vf0>SAT_A) * SAT_B * (SAT_A - vf0) ** 2 / vf0',
                                )

        self.IN = Algeb(tex_name='I_N',
                        info='Input to FEX',
                        v_str='1',
                        v_iter='KC * XadIfd - INT_y * IN',
                        e_str='KC * XadIfd / INT_y - IN',
                        )

        self.FEX = Piecewise(u=self.IN,
                             points=(0, 0.433, 0.75, 1),
                             funs=('1', '1 - 0.577*IN', 'sqrt(0.75 - IN ** 2)', '1.732*(1 - IN)', 0),
                             info='Piecewise function FEX',
                             )
        self.FEX.y.v_iter = '1'
        self.FEX.y.v_iter = self.FEX.y.e_str

        self.LG = Lag(self.v, T=self.TR, K=1,
                      info='Voltage transducer',
                      )

        self.vi = Algeb(info='Total input voltages',
                        tex_name='V_i',
                        unit='p.u.',
                        e_str='-v + vref - WF_y - vi',
                        v_str='-v + vref',
                        )

        self.LL = LeadLag(u=self.vi, T1=self.TC, T2=self.TB,
                          info='Regulator',
                          zero_out=True,
                          )
        self.LA = LagAntiWindup(u=self.LL_y,
                                T=self.TA,
                                K=self.KA,
                                lower=self.VRMIN,
                                upper=self.VRMAX,
                                info='Lag AW on VR',
                                )

        self.INT = Integrator(u='LA_y - VFE',
                              T=self.TE,
                              K=1,
                              y0=0,
                              info='Integrator',
                              )
        self.INT.y.v_str = 0.1
        self.INT.y.v_iter = 'INT_y * FEX_y - vf0'

        self.Se = Algeb(tex_name=r"S_e(|V_{out}|)", info='saturation output',
                        v_str='Se0',
                        e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B / INT_y - Se',
                        )

        self.VFE = Algeb(info='Combined saturation feedback',
                         tex_name='V_{FE}',
                         unit='p.u.',
                         v_str='INT_y * (KE + Se) + XadIfd * KD',
                         e_str='INT_y * (KE + Se) + XadIfd * KD - VFE'
                         )

        self.vref = Algeb(info='Reference voltage input',
                          tex_name='V_{ref}',
                          unit='p.u.',
                          v_str='v + VFE / KA',
                          e_str='vref0 - vref',
                          )

        self.vref0 = PostInitService(info='Initial reference voltage input',
                                     tex_name='V_{ref0}',
                                     v_str='vref',
                                     )

        self.WF = Washout(u=self.VFE,
                          T=self.TF,
                          K=self.KF,
                          info='Stablizing circuit feedback',
                          )

        self.vout.e_str = 'INT_y * FEX_y - vout'