Beispiel #1
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        self.LG = Lag(
            u=self.v,
            T=self.TR,
            K=1,
            info='Sensing delay',
        )
        self.vi = Algeb(
            info='Total input voltages',
            tex_name='V_i',
            unit='p.u.',
        )
        self.vi.v_str = 'vf0 / KA'
        self.vi.e_str = '(vref0 - LG_y) - vi'

        self.vref0 = PostInitService(
            info='Const reference voltage',
            tex_name='V_{ref0}',
            v_str='v + vf0 / KA',
        )

        self.HLI = HardLimiter(
            u=self.vi,
            lower=self.VIMIN,
            upper=self.VIMAX,
            info='Hard limiter on input',
        )

        self.LL = LeadLag(
            u='vi * HLI_zi + VIMIN * HLI_zl + VIMAX * HLI_zu',
            T1=self.TC,
            T2=self.TB,
            info='Lead-lag compensator',
            zero_out=True,
        )

        self.LR = Lag(u=self.LL_y, T=self.TA, K=self.KA, info='Regulator')

        # the following uses `XadIfd` for `IIFD` in the PSS/E manual
        self.vfmax = Algeb(
            info='Upper bound of output limiter',
            tex_name='V_{fmax}',
            v_str='VRMAX - KC * XadIfd',
            e_str='VRMAX - KC * XadIfd - vfmax',
        )
        self.vfmin = Algeb(
            info='Lower bound of output limiter',
            tex_name='V_{fmin}',
            v_str='VRMIN - KC * XadIfd',
            e_str='VRMIN - KC * XadIfd - vfmin',
        )

        self.HLR = HardLimiter(u=self.LR_y,
                               lower=self.vfmin,
                               upper=self.vfmax,
                               info='Hard limiter on regulator output')

        self.vout.e_str = 'ue * (LR_y*HLR_zi + vfmin*HLR_zl + vfmax*HLR_zu) - vout'
Beispiel #2
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

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

        self.vref0 = PostInitService(info='constant vref',
                                     v_str='vref',
                                     tex_name='V_{ref0}',
                                     )

        # input excitation voltages; PSS outputs summed at vi
        self.vi = Algeb(info='Total input voltages',
                        tex_name='V_i',
                        unit='p.u.',
                        )
        self.vi.v_str = 'vf0 / KA'
        self.vi.e_str = '(vref - LG_y - WF_y) - vi'

        self.LG = Lag(u=self.v, T=self.TR, K=1,
                      info='Sensing delay',
                      )

        self.HLI = HardLimiter(u=self.vi, lower=self.VIMIN, upper=self.VIMAX,
                               info='Hard limiter on input',
                               )

        self.vl = Algeb(info='Input after limiter',
                        tex_name='V_l',
                        v_str='HLI_zi*vi + HLI_zu*VIMAX + HLI_zl*VIMIN',
                        e_str='HLI_zi*vi + HLI_zu*VIMAX + HLI_zl*VIMIN - vl',
                        )

        self.LL = LeadLag(u=self.vl, T1=self.TC, T2=self.TB, info='Lead-lag compensator', zero_out=True)

        self.LR = Lag(u=self.LL_y, T=self.TA, K=self.KA, info='Regulator')

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

        # the following uses `XadIfd` for `IIFD` in the PSS/E manual
        self.vfmax = Algeb(info='Upper bound of output limiter',
                           tex_name='V_{fmax}',
                           v_str='VRMAX - KC * XadIfd',
                           e_str='VRMAX - KC * XadIfd - vfmax',
                           )
        self.vfmin = Algeb(info='Lower bound of output limiter',
                           tex_name='V_{fmin}',
                           v_str='VRMIN - KC * XadIfd',
                           e_str='VRMIN - KC * XadIfd - vfmin',
                           )

        self.HLR = HardLimiter(u=self.WF_y, lower=self.vfmin, upper=self.vfmax,
                               info='Hard limiter on regulator output')

        self.vout.e_str = 'LR_y*HLR_zi + vfmin*HLR_zl + vfmax*HLR_zu - vout'
Beispiel #3
0
    def __init__(self,
                 u,
                 K,
                 upper,
                 lower,
                 no_upper=False,
                 no_lower=False,
                 name=None,
                 tex_name=None,
                 info=None):
        Block.__init__(self, name=name, tex_name=tex_name, info=info)
        self.u = dummify(u)
        self.K = dummify(K)
        self.upper = upper
        self.lower = lower

        if (no_upper and no_lower) is True:
            raise ValueError("no_upper or no_lower cannot both be True")

        self.no_lower = no_lower
        self.no_upper = no_upper

        self.x = Algeb(info='Gain output before limiter', tex_name='x')
        self.y = Algeb(info='Gain output after limiter', tex_name='y')

        self.lim = HardLimiter(u=self.x,
                               lower=self.lower,
                               upper=self.upper,
                               no_upper=no_upper,
                               no_lower=no_lower,
                               tex_name='lim')

        self.vars = {'lim': self.lim, 'x': self.x, 'y': self.y}
Beispiel #4
0
    def __init__(self,
                 u,
                 T1,
                 T2,
                 lower,
                 upper,
                 name=None,
                 info='Lead-lag transfer function'):
        super().__init__(name=name, info=info)
        self.T1 = T1
        self.T2 = T2
        self.u = u
        self.lower = lower
        self.upper = upper

        self.x = State(info='State in lead-lag transfer function',
                       tex_name="x'")
        self.ynl = Algeb(
            info='Output of lead-lag transfer function before limiter',
            tex_name=r'y_{nl}')
        self.y = Algeb(
            info='Output of lead-lag transfer function after limiter',
            tex_name=r'y')
        self.lim = HardLimiter(u=self.ynl, lower=self.lower, upper=self.upper)

        self.vars = {
            'x': self.x,
            'ynl': self.ynl,
            'y': self.y,
            'lim': self.lim
        }
Beispiel #5
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']
Beispiel #6
0
    def __init__(self, system, config):
        TG2Data.__init__(self)
        TGBase.__init__(self, system, config)
        self.config.add({'deadband': 0,
                         'hardlimit': 1})
        self.config.add_extra("_help",
                              deadband="enable input dead band",
                              hardlimit="enable output hard limit"
                              )
        self.config.add_extra("_alt",
                              deadband=(0, 1),
                              hardlimit=(0, 1),
                              )
        self.config.add_extra("_tex",
                              deadband="z_{deadband}",
                              hardlimit="z_{hardlimit}",
                              )

        self.w_d = Algeb(info='Generator speed deviation before dead band (positive for under speed)',
                         tex_name=r'\omega_{dev}',
                         v_str='0',
                         e_str='u * (wref - omega) - w_d',
                         )
        self.w_db = DeadBand(u=self.w_d,
                             center=self.dbc,
                             lower=self.dbl,
                             upper=self.dbu,
                             enable=self.config.deadband,
                             )
        self.w_dm = Algeb(info='Measured speed deviation after dead band',
                          tex_name=r'\omega_{dm}',
                          v_str='0',
                          e_str='(1 - w_db_zi) * w_d + '
                                'w_db_zlr * dbl + '
                                'w_db_zur * dbu - '
                                'w_dm')

        self.w_dmg = Algeb(info='Speed deviation after dead band after gain',
                           tex_name=r'\omega_{dmG}',
                           v_str='0',
                           e_str='gain * w_dm - w_dmg',
                           )
        self.ll = LeadLag(u=self.w_dmg,
                          T1=self.T1,
                          T2=self.T2,
                          )

        self.pnl = Algeb(info='Power output before hard limiter',
                         tex_name='P_{nl}',
                         v_str='tm0',
                         e_str='tm0 + ll_y - pnl',
                         )
        self.plim = HardLimiter(u=self.pnl,
                                lower=self.pmin,
                                upper=self.pmax,
                                enable=self.config.hardlimit,
                                )

        self.pout.e_str = 'pnl * plim_zi + pmax * plim_zu + pmin * plim_zl - pout'
Beispiel #7
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.group = 'Experimental'
        self.flags.update({'tds': True})
        self.uin = State(
            v_str=0,
            e_str=
            'Piecewise((0, dae_t<= 0), (1, dae_t <= 2), (-1, dae_t <6), (1, True))',
        )
        self.x = State(
            e_str='uin * Ki * HL_zi',
            v_str=0.05,
        )
        self.y = Algeb(e_str='uin * Kp + x - y', v_str=0.05)

        self.HL = HardLimiter(u=self.y, lower=self.Wmin, upper=self.Wmax)
        self.w = Algeb(e_str='HL_zi * y + HL_zl * Wmin + HL_zu * Wmax - w',
                       v_str=0.05)
Beispiel #8
0
    def __init__(self, u, kp, ki, ks, lower, upper, no_lower=False, no_upper=False,
                 ref=0.0, x0=0.0, name=None, tex_name=None, info=None):
        Block.__init__(self, name=name, tex_name=tex_name, info=info)

        self.u = dummify(u)
        self.kp = dummify(kp)
        self.ki = dummify(ki)
        self.ks = dummify(ks)
        self.lower = dummify(lower)
        self.upper = dummify(upper)
        self.ref = dummify(ref)
        self.x0 = dummify(x0)

        self.xi = State(info="Integrator output", tex_name='xi')
        self.ys = Algeb(info="PI summation before limit", tex_name='ys')
        self.lim = HardLimiter(u=self.ys, lower=self.lower, upper=self.upper,
                               no_lower=no_lower, no_upper=no_upper, tex_name='lim')
        self.y = Algeb(info="PI output", discrete=self.lim, tex_name='y')
        self.vars = {'xi': self.xi, 'ys': self.ys, 'lim': self.lim, 'y': self.y}
Beispiel #9
0
    def __init__(self, system, config):
        PVD1Model.__init__(self, system, config)
        self.pgen = Algeb(info='Real power output',
                          v_str='v * Ipout_y',
                          e_str='v*Ipout_y - pgen',
                          tex_name='P_{gen}'
                          )
        # --- Add integrator. Assume that state-of-charge is the initial condition ---
        self.pIG = Integrator(u=self.pgen, T=self.Tf, K=1.0, y0=self.SOCinit)

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

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

        self.Ipcmd.lim.sign_lower = dummify(-1)
        self.Ipcmd.lim.lower = self.Ipmax
Beispiel #10
0
    def __init__(self, system, config):
        PVD1Model.__init__(self, system, config)

        # --- Add integrator. Assume that state-of-charge is the initial condition ---
        self.pIG = Integrator(
            u='v * Ipout_y',
            T=self.Tf,
            K=1.0,
            y0=self.SOCinit,
            check_init=False,
        )

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

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

        self.Ipcmd.lim.sign_lower = dummify(-1)
        self.Ipcmd.lim.lower = self.Ipmax
Beispiel #11
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        self.KPC = ConstService(v_str='KP * exp(1j * radians(THETAP))',
                                tex_name='K_{PC}',
                                info='KP polar THETAP',
                                vtype=np.complex)

        # vd, vq, Id, Iq from SynGen
        self.vd = ExtAlgeb(
            src='vd',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'V_d',
            info='d-axis machine voltage',
        )
        self.vq = ExtAlgeb(
            src='vq',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'V_q',
            info='q-axis machine voltage',
        )
        self.Id = ExtAlgeb(
            src='Id',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'I_d',
            info='d-axis machine current',
        )

        self.Iq = ExtAlgeb(
            src='Iq',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'I_q',
            info='q-axis machine current',
        )

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

        self.UEL = Algeb(info='Interface var for under exc. limiter',
                         tex_name='U_{EL}',
                         v_str='0',
                         e_str='0 - UEL')

        self.VE = VarService(
            tex_name='V_E',
            info='VE',
            v_str='Abs(KPC*(vd + 1j*vq) + 1j*(KI + KPC*XL)*(Id + 1j*Iq))',
        )

        self.IN = Algeb(
            tex_name='I_N',
            info='Input to FEX',
            v_str='KC * XadIfd / VE',
            e_str='KC * XadIfd / VE - 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.VBMIN = dummify(-9999)
        self.VGMIN = dummify(-9999)

        self.VB = GainLimiter(
            u='VE*FEX_y',
            K=1,
            upper=self.VBMAX,
            lower=self.VBMIN,
            no_lower=True,
            info='VB with limiter',
        )

        self.VG = GainLimiter(
            u=self.vout,
            K=self.KG,
            upper=self.VGMAX,
            lower=self.VGMIN,
            no_lower=True,
            info='Feedback gain with HL',
        )

        self.vrs = Algeb(
            tex_name='V_{RS}',
            info='VR subtract feedback VG',
            v_str='vf0 / VB_y / KM',
            e_str='LAW1_y - VG_y - vrs',
        )

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

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

        # input excitation voltages; PSS outputs summed at vi
        self.vi = Algeb(
            info='Total input voltages',
            tex_name='V_i',
            unit='p.u.',
            e_str='-LG_y + vref - vi',
            v_str='-v + vref',
        )

        self.vil = Algeb(info='Input voltage after limit',
                         tex_name='V_{il}',
                         v_str='HLI_zi*vi + HLI_zl*VIMIN + HLI_zu*VIMAX',
                         e_str='HLI_zi*vi + HLI_zl*VIMIN + HLI_zu*VIMAX - vil')

        self.HG = HVGate(
            u1=self.UEL,
            u2=self.vil,
            info='HVGate for under excitation',
        )

        self.LL = LeadLag(
            u=self.HG_y,
            T1=self.TC,
            T2=self.TB,
            info='Regulator',
            zero_out=True,
        )  # LL_y == VA

        self.LAW1 = LagAntiWindup(
            u=self.LL_y,
            T=self.TA,
            K=self.KA,
            lower=self.VRMIN,
            upper=self.VRMAX,
            info='Lag AW on VR',
        )  # LAW1_y == VR

        self.HLI = HardLimiter(
            u=self.vi,
            lower=self.VIMIN,
            upper=self.VIMAX,
            info='Input limiter',
        )

        self.LAW2 = LagAntiWindup(
            u=self.vrs,
            T=self.TM,
            K=self.KM,
            lower=self.VMMIN,
            upper=self.VMMAX,
            info='Lag AW on VM',
        )  # LAW2_y == VM

        self.vout.e_str = 'VB_y * LAW2_y - vout'
Beispiel #12
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        # vd, vq, Id, Iq from SynGen
        self.vd = ExtAlgeb(
            src='vd',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'V_d',
            info='d-axis machine voltage',
        )
        self.vq = ExtAlgeb(
            src='vq',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'V_q',
            info='q-axis machine voltage',
        )
        self.Id = ExtAlgeb(
            src='Id',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'I_d',
            info='d-axis machine current',
        )
        self.Iq = ExtAlgeb(
            src='Iq',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'I_q',
            info='q-axis machine current',
        )
        self.VE = VarService(
            tex_name=r'V_{E}',
            info=r'V_{E}',
            v_str='Abs(KP * (vd + 1j*vq) + 1j*KI*(Id + 1j*Iq))',
        )

        self.V40 = ConstService('sqrt(VE ** 2 - (0.78 * XadIfd) ** 2)')
        self.VR0 = ConstService(info='Initial VR',
                                tex_name='V_{R0}',
                                v_str='vf0 * KE - V40')

        self.vb0 = ConstService(info='Initial vb',
                                tex_name='V_{b0}',
                                v_str='VR0 / KA')

        # Set VRMAX to 999 when VRMAX = 0
        self._zVRM = FlagValue(
            self.VRMAX,
            value=0,
            tex_name='z_{VRMAX}',
        )
        self.VRMAXc = ConstService(
            v_str='VRMAX + 999*(1-_zVRM)',
            info='Set VRMAX=999 when zero',
        )

        self.LG = Lag(u=self.v, T=self.TR, K=1, info='Sensing delay')

        ExcVsum.__init__(self)

        self.vref.v_str = 'v + vb0'

        self.vref0 = PostInitService(info='Constant vref',
                                     tex_name='V_{ref0}',
                                     v_str='vref')

        # NOTE: for offline exciters, `vi` equation ignores ext. voltage changes
        self.vi = Algeb(
            info='Total input voltages',
            tex_name='V_i',
            unit='p.u.',
            e_str='ue * (-LG_y + vref + UEL + OEL + Vs - vi)',
            v_str='vref - v',
            diag_eps=True,
        )

        self.LA3 = LagAntiWindup(
            u='ue * (vi - WF_y)',
            T=self.TA,
            K=self.KA,
            upper=self.VRMAXc,
            lower=self.VRMIN,
            info=r'V_{R}, Lag Anti-Windup',
        )  # LA3_y is V_R

        # FIXME: antiwindup out of limit is not warned of in initialization

        self.zeros = ConstService(v_str='0.0')

        self.LA1 = Lag(
            'ue * (VB_y * HL_zi + VBMAX * HL_zu)',
            T=self.TE,
            K=1,
            D=self.KE,
        )

        self.WF = Washout(u=self.LA1_y,
                          T=self.TF,
                          K=self.KF,
                          info='V_F, stablizing circuit feedback, washout')

        self.SQE = Algeb(
            tex_name=r'SQE',
            info=r'Square of error after mul',
            v_str='VE ** 2 - (0.78 * XadIfd) ** 2',
            e_str='VE ** 2 - (0.78 * XadIfd) ** 2 - SQE',
        )

        self.SL = LessThan(u=self.zeros,
                           bound=self.SQE,
                           equal=False,
                           enable=True,
                           cache=False)

        self.VB = Piecewise(self.SQE,
                            points=(0, ),
                            funs=('ue * LA3_y', 'ue * (sqrt(SQE) + LA3_y)'))

        self.HL = HardLimiter(
            u=self.VB_y,
            lower=self.zeros,
            upper=self.VBMAX,
            info='Hard limiter for VB',
        )

        self.vout.e_str = 'ue * (LA1_y - vout)'
Beispiel #13
0
    def __init__(self, system, config):
        TGBase.__init__(self, system, config, add_sn=False)

        # check if K1-K8 sums up to 1
        self._sumK18 = ConstService(v_str='K1+K2+K3+K4+K5+K6+K7+K8',
                                    info='summation of K1-K8',
                                    tex_name=r"\sum_{i=1}^8 K_i")
        self._K18c1 = InitChecker(
            u=self._sumK18,
            info='summation of K1-K8 and 1.0',
            equal=1,
        )

        # check if  `tm0 * (K2 + k4 + K6 + K8) = tm02 *(K1 + K3 + K5 + K7)
        self._tm0K2 = PostInitService(
            info='mul of tm0 and (K2+K4+K6+K8)',
            v_str='zsyn2*tm0*(K2+K4+K6+K8)',
        )
        self._tm02K1 = PostInitService(
            info='mul of tm02 and (K1+K3+K5+K6)',
            v_str='tm02*(K1+K3+K5+K7)',
        )
        self._Pc = InitChecker(
            u=self._tm0K2,
            info='proportionality of tm0 and tm02',
            equal=self._tm02K1,
        )

        self.Sg2 = ExtParam(
            src='Sn',
            model='SynGen',
            indexer=self.syn2,
            allow_none=True,
            default=0.0,
            tex_name='S_{n2}',
            info='Rated power of Syn2',
            unit='MVA',
            export=False,
        )
        self.Sg12 = ParamCalc(
            self.Sg,
            self.Sg2,
            func=np.add,
            tex_name="S_{g12}",
            info='Sum of generator power ratings',
        )
        self.Sn = NumSelect(
            self.Tn,
            fallback=self.Sg12,
            tex_name='S_n',
            info='Turbine or Gen rating',
        )

        self.zsyn2 = FlagValue(
            self.syn2,
            value=None,
            tex_name='z_{syn2}',
            info='Exist flags for syn2',
        )

        self.tm02 = ExtService(
            src='tm',
            model='SynGen',
            indexer=self.syn2,
            tex_name=r'\tau_{m02}',
            info='Initial mechanical input of syn2',
            allow_none=True,
            default=0.0,
        )
        self.tm012 = ConstService(
            info='total turbine power',
            v_str='tm0 + tm02',
        )

        self.tm2 = ExtAlgeb(
            src='tm',
            model='SynGen',
            indexer=self.syn2,
            allow_none=True,
            tex_name=r'\tau_{m2}',
            e_str='zsyn2 * u * (PLP - tm02)',
            info='Mechanical power to syn2',
        )

        self.wd = Algeb(
            info='Generator under speed',
            unit='p.u.',
            tex_name=r'\omega_{dev}',
            v_str='0',
            e_str='(wref - omega) - wd',
        )

        self.LL = LeadLag(
            u=self.wd,
            T1=self.T2,
            T2=self.T1,
            K=self.K,
            info='Signal conditioning for wd',
        )

        # `P0` == `tm0`
        self.vs = Algeb(
            info='Valve speed',
            tex_name='V_s',
            v_str='0',
            e_str='(LL_y + tm012 + paux - IAW_y) / T3 - vs',
        )

        self.HL = HardLimiter(
            u=self.vs,
            lower=self.UC,
            upper=self.UO,
            info='Limiter on valve acceleration',
        )

        self.vsl = Algeb(
            info='Valve move speed after limiter',
            tex_name='V_{sl}',
            v_str='vs * HL_zi + UC * HL_zl + UO * HL_zu',
            e_str='vs * HL_zi + UC * HL_zl + UO * HL_zu - vsl',
        )

        self.IAW = IntegratorAntiWindup(
            u=self.vsl,
            T=1,
            K=1,
            y0=self.tm012,
            lower=self.PMIN,
            upper=self.PMAX,
            info='Valve position integrator',
        )

        self.L4 = Lag(
            u=self.IAW_y,
            T=self.T4,
            K=1,
            info='first process',
        )

        self.L5 = Lag(
            u=self.L4_y,
            T=self.T5,
            K=1,
            info='second (reheat) process',
        )

        self.L6 = Lag(
            u=self.L5_y,
            T=self.T6,
            K=1,
            info='third process',
        )

        self.L7 = Lag(
            u=self.L6_y,
            T=self.T7,
            K=1,
            info='fourth (second reheat) process',
        )

        self.PHP = Algeb(
            info='HP output',
            tex_name='P_{HP}',
            v_str='K1*L4_y + K3*L5_y + K5*L6_y + K7*L7_y',
            e_str='K1*L4_y + K3*L5_y + K5*L6_y + K7*L7_y - PHP',
        )

        self.PLP = Algeb(
            info='LP output',
            tex_name='P_{LP}',
            v_str='K2*L4_y + K4*L5_y + K6*L6_y + K8*L7_y',
            e_str='K2*L4_y + K4*L5_y + K6*L6_y + K8*L7_y - PLP',
        )

        self.pout.e_str = 'PHP - pout'