Esempio n. 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'
Esempio n. 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'
Esempio n. 3
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)
        ExcVsum.__init__(self)

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

        self.vi = Algeb(
            info='Total voltage input',
            unit='pu',
            e_str='ue * (-LP_y + vref + Vs - WF_y ) -vi ',
            v_str='ue*(-v +vref)',
        )

        self.VRMAXu = ConstService('VRMAX * ue + (1-ue) * 999')
        self.VRMINu = ConstService('VRMIN * ue + (1-ue) * -999')

        self.VR = LagAntiWindup(
            u=self.vi,
            T=self.TA,
            K=self.KA,
            upper=self.VRMAXu,
            lower=self.VRMINu,
        )

        self.LL = LeadLag(
            u=self.VR_y,
            T1=self.TF3,
            T2=self.TF2,
        )

        self.WF = Washout(u=self.LL_y, T=self.TF1, K=self.KF)

        self.INTin = 'ue * (VR_y - VFE)'

        ExcACSat.__init__(self)

        self.vref.v_str = 'v + VFE / KA'

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

        self.VFE.v_str = "INT_y * KE + Se "
        self.VFE.e_str = "ue * (INT_y * KE + Se - VFE) "

        # disable iterative initialization of the integrator output
        self.INT.y.v_str = 'vf0'
        self.INT.y.v_iter = None

        self.vout.e_str = 'ue * INT_y - vout'
Esempio n. 4
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        self.TA = ConstService(v_str='TATB * TB')

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

        self.vref0 = PostInitService(
            info='Constant vref',
            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.',
        )
        self.vi.e_str = '(vref - v) - vi'
        self.vi.v_str = 'vref0 - v'

        self.LL = LeadLag(u=self.vi, T1=self.TA, T2=self.TB, zero_out=True)

        self.LAW = LagAntiWindup(
            u=self.LL_y,
            T=self.TE,
            K=self.K,
            lower=self.EMIN,
            upper=self.EMAX,
        )

        self.vout.e_str = 'LAW_y - vout'
Esempio n. 5
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        # 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',
                                   )
        # Saturation
        self.SAT = ExcQuadSat(self.E1, self.SE1, self.E2, self.SE2,
                              info='Field voltage saturation',
                              )

        self.Se0 = ConstService(info='Initial saturation output',
                                tex_name='S_{e0}',
                                v_str='Indicator(vf0>SAT_A) * SAT_B * (SAT_A - vf0) ** 2',
                                )
        self.vr0 = ConstService(info='Initial vr',
                                tex_name='V_{r0}',
                                v_str='KE * vf0 + Se0')
        self.vb0 = ConstService(info='Initial vb',
                                tex_name='V_{b0}',
                                v_str='vr0 / KA')
        self.vfe0 = ConstService(v_str='vf0 * KE + Se0',
                                 tex_name='V_{FE0}',
                                 )

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

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

        self.LG = Lag(u=self.v, T=self.TR, K=1,
                      info='Sensing delay',
                      )
        # 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 - vi)',
                        v_str='-v + vref',
                        diag_eps=True,
                        )
        self.LA = LagAntiWindup(u='ue * (vi - WF_y)',
                                T=self.TA,
                                K=self.KA,
                                upper=self.VRMAXc,
                                lower=self.VRMIN,
                                info='Anti-windup lag',
                                )
        self.VFE = Algeb(info='Combined saturation feedback',
                         tex_name='V_{FE}',
                         unit='p.u.',
                         v_str='vfe0',
                         e_str='ue * (INT_y * KE + Se - VFE)',
                         diag_eps=True,
                         )

        self.INT = Integrator(u='ue * (LA_y - VFE)',
                              T=self.TE,
                              K=1,
                              y0=self.vf0,
                              info='Integrator',
                              )

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

        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 - Se',
                        )

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

        self.vout.e_str = 'ue * (INT_y - vout)'
Esempio n. 6
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)
        ExcVsum.__init__(self)

        self.UEL0.v_str = '-999'
        self.OEL0.v_str = '999'

        self.flags.nr_iter = True

        # NOTE: e_str `KC*XadIfd / INT_y - IN` causes numerical inaccuracies
        self.IN = Algeb(tex_name='I_N',
                        info='Input to FEX',
                        v_str='1',
                        v_iter='KC * XadIfd - INT_y * IN',
                        e_str='ue * (KC * XadIfd - INT_y * IN)',
                        diag_eps=True,
                        )

        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_str = '1'
        self.FEX.y.v_iter = self.FEX.y.e_str

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

        # input excitation voltages;
        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='-v + vref',
                        diag_eps=True,
                        )

        self.LL = LeadLag(u=self.vi, T1=self.TC, T2=self.TB,
                          info='V_A, Lead-lag compensator',
                          zero_out=True,
                          )  # LL_y == VA

        self.VAMAXu = ConstService('VAMAX * ue + (1-ue) * 999')
        self.VAMINu = ConstService('VAMIN * ue + (1-ue) * -999')

        self.LA = LagAntiWindup(u=self.LL_y,
                                T=self.TA,
                                K=self.KA,
                                upper=self.VAMAXu,
                                lower=self.VAMINu,
                                info='V_A, Anti-windup lag',
                                )  # LA_y == VA

        self.HVG = HVGate(u1=self.UEL,
                          u2=self.LA_y,
                          info='HVGate for under excitation',
                          )

        self.LVG = LVGate(u1=self.HVG_y,
                          u2=self.OEL,
                          info='HVGate for under excitation',
                          )

        self.INTin = 'ue * (LVG_y - VFE)'

        ExcACSat.__init__(self)

        self.vref.v_str = 'v + VFE / KA'

        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 = 'ue * FEX_y * INT_y - vout'
Esempio n. 7
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'
Esempio n. 8
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)'
Esempio n. 9
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        self.config.add(OrderedDict((
            ('ksr', 2),
            ('ksm', 2),
        )))

        self.config.add_extra(
            '_help',
            ksr='Tracking gain for outer PI controller',
            ksm='Tracking gain for inner PI controller',
        )
        self.config.add_extra(
            '_tex',
            ksr='K_{sr}',
            ksm='K_{sm}',
        )

        self.KPC = ConstService(v_str='KP * exp(1j * radians(THETAP))',
                                tex_name='K_{PC}',
                                info='KP polar THETAP',
                                vtype=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')

        # lower part: VB signal
        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='safe_div(KC * XadIfd, VE)',
            e_str='ue * (KC * XadIfd - VE * IN)',
            diag_eps=True,
        )

        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,
            R=1,
            upper=self.VBMAX,
            lower=self.VBMIN,
            no_lower=True,
            info='VB with limiter',
        )

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

        self.vref = Algeb(info='Reference voltage input',
                          tex_name='V_{ref}',
                          unit='p.u.',
                          v_str='v',
                          e_str='vref0 - vref')
        self.vref0 = PostInitService(
            info='Const reference voltage',
            tex_name='V_{ref0}',
            v_str='vref',
        )

        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.PI1 = PITrackAW(u=self.vi,
                             kp=self.KPR,
                             ki=self.KIR,
                             ks=self.config.ksr,
                             lower=self.VRMIN,
                             upper=self.VRMAX,
                             x0='VG_y')

        self.LA = Lag(
            u=self.PI1_y,
            T=self.TA,
            K=1.0,
            info='Regulation delay',
        )
        self.PI2 = PITrackAW(
            u='LA_y - VG_y',
            kp=self.KPM,
            ki=self.KIM,
            ks=self.config.ksm,
            lower=self.VMMIN,
            upper=self.VMMAX,
            x0='safe_div(vf0, VB_y)',
        )

        # TODO: add back LV Gate

        self.vout.e_str = 'VB_y * PI2_y - vout'
Esempio n. 10
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)
        self.flags.nr_iter = True
        self.config.add(OrderedDict((('ks', 2),
                                     )))
        self.config.add_extra('_help',
                              ks='Tracking gain for PID controller',
                              )

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

        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_str = '0.5'
        self.FEX.y.v_iter = self.FEX.y.e_str

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

        ExcVsum.__init__(self)

        self.vref.v_str = 'v'

        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='-v + vref',
                        diag_eps=True,
                        )

        # chekck y0
        self.PID = PIDTrackAW(u=self.vi, kp=self.kP, ki=self.kI,
                              ks=self.config.ks,
                              kd=self.kD, Td=self.Td, x0='VFE / KA',
                              lower=self.VPMIN, upper=self.VPMAX,
                              tex_name='PID', info='PID', name='PID',
                              )

        self.LA = LagAntiWindup(u=self.PID_y,
                                T=self.TA,
                                K=self.KA,
                                upper=self.VRMAX,
                                lower=self.VRMIN,
                                info=r'V_{R}, Anti-windup lag',
                                )

        self.INTin = 'ue * (LA_y - VFE)'

        ExcACSat.__init__(self)

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

        self.vout.e_str = 'ue * (FEX_y * INT_y - vout)'
Esempio n. 11
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'
Esempio n. 12
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)
        self.flags.nr_iter = True

        ExcVsum.__init__(self)
        self.UEL0.v_str = '-999'
        self.OEL0.v_str = '999'

        self.ulim = ConstService('9999')
        self.llim = ConstService('-9999')

        self.SWUEL = Switcher(u=self.UELc,
                              options=[0, 1, 2, 3],
                              tex_name='SW_{UEL}',
                              cache=True)
        self.SWVOS = Switcher(u=self.VOSc,
                              options=[0, 1, 2],
                              tex_name='SW_{VOS}',
                              cache=True)

        # control block begin
        self.LG = Lag(
            self.v,
            T=self.TR,
            K=1,
            info='Voltage transducer',
        )
        self.SG0 = ConstService(v_str='0', info='SG initial value.')
        self.SG = Algeb(
            tex_name='SG',
            info='SG',
            v_str='SG0',
            e_str='SG0 - SG',
        )

        self.zero = ConstService('0')
        self.LR = GainLimiter(
            u='XadIfd - ILR',
            K=self.KLR,
            R=1,
            upper=self.ulim,
            lower=self.zero,
            no_upper=True,
            info='Exciter output current gain limiter',
        )

        self.VA0 = PostInitService(tex_name='V_{A0}',
                                   v_str='vf0 - SWVOS_s2 * SG + LR_y',
                                   info='VA (LA_y) initial value')

        self.vref.v_str = 'ue * (v + (vf0 - SWVOS_s2 * SG + LR_y) / KA - SWVOS_s1 * SG - SWUEL_s1 * UEL)'
        self.vref.v_iter = 'ue * (v + (vf0 - SWVOS_s2 * SG + LR_y) / KA - SWVOS_s1 * SG - SWUEL_s1 * UEL)'

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

        self.vi = Algeb(
            info='Total input voltages',
            tex_name='V_i',
            unit='p.u.',
            e_str=
            'ue * (-LG_y + vref - WF_y + SWUEL_s1 * UEL + SWVOS_s1 * SG + Vs) - vi',
            v_iter=
            'ue * (-LG_y + vref - WF_y + SWUEL_s1 * UEL + SWVOS_s1 * SG + Vs)',
            v_str=
            'ue * (-LG_y + vref - WF_y + SWUEL_s1 * UEL + SWVOS_s1 * SG + Vs)',
        )

        self.vil = GainLimiter(
            u=self.vi,
            K=1,
            R=1,
            upper=self.VIMAX,
            lower=self.VIMIN,
            info='Exciter voltage input limiter',
        )

        self.UEL2 = Algeb(
            tex_name='UEL_2',
            info='UEL_2 as HVG1 u1',
            v_str='ue * (SWUEL_s2 * UEL + (1 - SWUEL_s2) * llim)',
            e_str='ue * (SWUEL_s2 * UEL + (1 - SWUEL_s2) * llim) - UEL2',
        )
        self.HVG1 = HVGate(
            u1=self.UEL2,
            u2=self.vil_y,
            info='HVGate after V_I',
        )

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

        self.LL1 = LeadLag(
            u=self.LL_y,
            T1=self.TC1,
            T2=self.TB1,
            info='Lead-lag compensator 1',
            zero_out=True,
        )

        self.LA = LagAntiWindup(
            u=self.LL1_y,
            T=self.TA,
            K=self.KA,
            upper=self.VAMAX,
            lower=self.VAMIN,
            info='V_A, Anti-windup lag',
        )  # LA_y is VA

        self.vas = Algeb(
            tex_name=r'V_{As}',
            info='V_A after subtraction, as HVG u2',
            v_str='ue * (SWVOS_s2 * SG + LA_y - LR_y)',
            v_iter='ue * (SWVOS_s2 * SG + LA_y - LR_y)',
            e_str='ue * (SWVOS_s2 * SG + LA_y - LR_y) - vas',
        )

        self.UEL3 = Algeb(
            tex_name='UEL_3',
            info='UEL_3 as HVG u1',
            v_str='ue * (SWUEL_s3 * UEL + (1 - SWUEL_s3) * llim)',
            e_str='ue * (SWUEL_s3 * UEL + (1 - SWUEL_s3) * llim) - UEL3',
        )
        self.HVG = HVGate(
            u1=self.UEL3,
            u2=self.vas,
            info='HVGate for under excitation',
        )

        self.LVG = LVGate(
            u1=self.HVG_y,
            u2=self.OEL,
            info='HVGate for over excitation',
        )

        # 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.efdu = VarService(
            info='Output exciter voltage upper bound',
            tex_name=r'efd_{u}',
            v_str='Abs(vd + 1j*vq) * VRMAX - KC * XadIfd',
        )
        self.efdl = VarService(info='Output exciter voltage lower bound',
                               tex_name=r'efd_{l}',
                               v_str='Abs(vd + 1j*vq) * VRMIN')

        self.vol = GainLimiter(
            u=self.LVG_y,
            K=1,
            R=1,
            upper=self.efdu,
            lower=self.efdl,
            info='Exciter output limiter',
        )

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

        self.vout.e_str = 'ue * vol_y  - vout'
Esempio n. 13
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.flags.tds = True
        self.group = 'RenGen'

        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            tex_name=r'\theta',
            info='Bus voltage angle',
            e_str='-Pe',
            ename='P',
            tex_ename='P',
        )

        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.bus,
            tex_name=r'V',
            info='Bus voltage magnitude',
            e_str='-Qe',
            ename='Q',
            tex_ename='Q',
        )

        self.p0s = ExtService(
            model='StaticGen',
            src='p',
            indexer=self.gen,
            tex_name='P_{0s}',
            info='initial P of the static gen',
        )
        self.q0s = ExtService(
            model='StaticGen',
            src='q',
            indexer=self.gen,
            tex_name='Q_{0s}',
            info='initial Q of the static gen',
        )
        self.p0 = ConstService(
            v_str='p0s * gammap',
            tex_name='P_0',
            info='initial P of this gen',
        )
        self.q0 = ConstService(
            v_str='q0s * gammaq',
            tex_name='Q_0',
            info='initial Q of this gen',
        )
        self.ra = ExtParam(
            model='StaticGen',
            src='ra',
            indexer=self.gen,
            tex_name='r_a',
            export=False,
        )
        self.xs = ExtParam(
            model='StaticGen',
            src='xs',
            indexer=self.gen,
            tex_name='x_s',
            export=False,
        )

        # --- INITIALIZATION ---
        self.q0gt0 = ConstService(
            'Indicator(q0> 0)',
            tex_name='z_{q0>0}',
            info='flags for q0 below zero',
        )
        self.q0lt0 = ConstService(
            'Indicator(q0< 0)',
            tex_name='z_{q0<0}',
            info='flags for q0 below zero',
        )

        self.Ipcmd0 = ConstService(
            'p0 / v',
            info='initial Ipcmd',
            tex_name='I_{pcmd0}',
        )

        self.Iqcmd0 = ConstService(
            '-q0 / v',
            info='initial Iqcmd',
            tex_name='I_{qcmd0}',
        )

        self.LVG = Piecewise(
            u=self.v,
            points=('Lvpnt0', 'Lvpnt1'),
            funs=('0', '(v - Lvpnt0) * kLVG', '1'),
            info='Ip gain during low voltage',
            tex_name='L_{VG}',
        )

        # `Ipcmd` is not defined when the initial `LVG_y` is zero
        self.Ipcmd = Algeb(
            tex_name='I_{pcmd}',
            info='current component for active power',
            e_str='Ipcmd0_LVG - Ipcmd',
            v_str=
            'Indicator(LVG_y>0) * Ipcmd0 / LVG_y + Indicator(LVG_y<=0) * 1',
            diag_eps=True,
        )

        self.Ipcmd0_LVG = PostInitService(
            v_str='Ipcmd', info='initial Ipcmd considering initial LVG output')

        self.Iqcmd = Algeb(tex_name='I_{qcmd}',
                           info='current component for reactive power',
                           e_str='Iqcmd0 - Iqcmd',
                           v_str='Iqcmd0')

        # reactive power management

        # rate limiting logic (for fault recovery, although it does not detect any recovery)
        #   - activate upper limit when q0 > 0 (self.q0gt0)
        #   - activate lower limit when q0 < 0 (self.q0lt0)

        self.S1 = LagAntiWindupRate(
            u=self.Iqcmd,
            T=self.Tg,
            K=-1,
            lower=-9999,
            upper=9999,
            no_lower=True,
            no_upper=True,
            rate_lower=self.Iqrmin,
            rate_upper=self.Iqrmax,
            rate_lower_cond=self.q0lt0,
            rate_upper_cond=self.q0gt0,
            tex_name='S_1',
            info='Iqcmd delay',
        )  # output `S1_y` == `Iq`

        # piece-wise gain for low voltage active current mgnt.
        self.kLVG = ConstService(
            v_str='1 / (Lvpnt1 - Lvpnt0)',
            tex_name='k_{LVG}',
        )

        # piece-wise gain for LVPL
        self.kLVPL = ConstService(
            v_str='Lvplsw * Lvpl1 / (Brkpt - Zerox)',
            tex_name='k_{LVPL}',
        )

        self.S2 = Lag(
            u=self.v,
            T=self.Tfltr,
            K=1.0,
            info='Voltage filter with no anti-windup',
            tex_name='S_2',
        )
        self.LVPL = Piecewise(
            u=self.S2_y,
            points=('Zerox', 'Brkpt'),
            funs=('0 + 9999*(1-Lvplsw)',
                  '(S2_y - Zerox) * kLVPL + 9999 * (1-Lvplsw)', '9999'),
            info='Low voltage Ipcmd upper limit',
            tex_name='L_{VPL}',
        )

        self.S0 = LagAntiWindupRate(
            u=self.Ipcmd,
            T=self.Tg,
            K=1,
            upper=self.LVPL_y,
            rate_upper=self.Rrpwr,
            lower=-9999,
            rate_lower=-9999,
            no_lower=True,
            rate_no_lower=True,
            tex_name='S_0',
        )  # `S0_y` is the output `Ip` in the block diagram

        self.Ipout = Algeb(
            e_str='S0_y * LVG_y -Ipout',
            v_str='Ipcmd * LVG_y',
            info='Output Ip current',
            tex_name='I_{pout}',
        )

        # high voltage part
        self.HVG = GainLimiter(u='v - Volim',
                               K=self.Khv,
                               R=1,
                               info='High voltage gain block',
                               lower=0,
                               upper=999,
                               no_upper=True,
                               tex_name='H_{VG}')
        self.HVG.lim.no_warn = True
        self.HVG.lim.allow_adjust = False

        self.Iqout = GainLimiter(
            u='S1_y - HVG_y',
            K=1,
            R=1,
            lower=self.Iolim,
            upper=9999,
            no_upper=True,
            info='Iq output block',
            tex_name='I^{qout}',
        )  # `Iqout_y` is the final Iq output

        self.Pe = Algeb(tex_name='P_e',
                        info='Active power output',
                        v_str='p0',
                        e_str='Ipout * v - Pe')
        self.Qe = Algeb(tex_name='Q_e',
                        info='Reactive power output',
                        v_str='q0',
                        e_str='Iqout_y * v - Qe')
Esempio n. 14
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)

        self.flags.tds = True
        self.group = 'RenPitch'

        self.rego = ExtParam(model='RenAerodynamics', src='rego', indexer=self.rea,
                             export=False,
                             )

        self.ree = ExtParam(model='RenGovernor', src='ree', indexer=self.rego,
                            export=False,
                            )

        self.wt = ExtState(model='RenGovernor', src='wt', indexer=self.rego,
                           export=False,
                           )

        self.theta0 = ExtService(model='RenAerodynamics', src='theta0', indexer=self.rea,
                                 )

        self.theta = ExtAlgeb(model='RenAerodynamics', src='theta', indexer=self.rea,
                              export=False,
                              e_str='-theta0 + LG_y',
                              ename='theta',
                              tex_ename=r'\theta',
                              )

        self.Pord = ExtState(model='RenExciter', src='Pord', indexer=self.ree,
                             )

        self.Pref = ExtAlgeb(model='RenExciter', src='Pref', indexer=self.ree,
                             )

        self.PIc = PIAWHardLimit(u='Pord - Pref', kp=self.Kpc, ki=self.Kic,
                                 aw_lower=self.thmin, aw_upper=self.thmax,
                                 lower=self.thmin, upper=self.thmax,
                                 tex_name='PI_c',
                                 info='PI for active power diff compensation',
                                 )

        self.wref = Algeb(tex_name=r'\omega_{ref}',
                          info='optional speed reference',
                          e_str='wref0 - wref',
                          v_str='wt',
                          )
        self.wref0 = PostInitService(v_str='wref', info='initial wref')

        self.PIw = PIAWHardLimit(u='Kcc * (Pord - Pref) + wt - wref', kp=self.Kpw, ki=self.Kiw,
                                 aw_lower=self.thmin, aw_upper=self.thmax,
                                 lower=self.thmin, upper=self.thmax,
                                 tex_name='PI_w',
                                 info='PI for speed and active power deviation',
                                 )

        self.LG = LagAntiWindupRate(u='PIw_y + PIc_y', T=self.Tp, K=1.0,
                                    lower=self.thmin, upper=self.thmax,
                                    rate_lower=self.dthmin, rate_upper=self.dthmax,
                                    tex_name='LG',
                                    info='Output lag anti-windup rate limiter')

        # remove warning when pitch angle==0
        self.PIc_hl.warn_flags.pop(0)
        self.PIc_aw.warn_flags.pop(0)
        self.PIw_hl.warn_flags.pop(0)
        self.PIw_aw.warn_flags.pop(0)
        self.LG_lim.warn_flags.pop(0)
Esempio n. 15
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

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

        # calculate `Se0` ahead of time in order to calculate `vr0`
        # The term `1-ug` is to prevent division by zero when generator is off
        self.Se0 = ConstService(info='Initial saturation output',
                                tex_name='S_{e0}',
                                v_str='Indicator(vf0>SAT_A) * SAT_B * (SAT_A - vf0) ** 2 / (vf0 + 1 - ug)',
                                )
        self.vr0 = ConstService(info='Initial vr',
                                tex_name='V_{r0}',
                                v_str='(KE + Se0) * vf0')
        self.vb0 = ConstService(info='Initial vb',
                                tex_name='V_{b0}',
                                v_str='vr0 / KA')

        self.vref = Algeb(info='Reference voltage input',
                          tex_name='V_{ref}',
                          unit='p.u.',
                          v_str='v + vb0',
                          e_str='vref0 - vref'
                          )
        self.vref0 = PostInitService(info='Constant v ref',
                                     tex_name='V_{ref0}',
                                     v_str='vref',
                                     )

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

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

        self.vp = State(info='Voltage after saturation feedback, before speed term',
                        tex_name='V_p',
                        unit='p.u.',
                        v_str='vf0',
                        e_str='ue * (LA_y - KE*vp - Se*vp)',
                        t_const=self.TE,
                        )

        self.LS = Lag(u=self.v, T=self.TR, K=1.0, info='Sensing lag TF')

        # 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 = 'vb0'
        self.vi.e_str = '(vref - LS_y - W_y) - vi'

        self.LL = LeadLag(u=self.vi,
                          T1=self.TC,
                          T2=self.TB,
                          info='Lead-lag for internal delays',
                          zero_out=True,
                          )
        self.LA = LagAntiWindup(u=self.LL_y,
                                T=self.TA,
                                K=self.KA,
                                upper=self.VRMAX,
                                lower=self.VRMIN,
                                info='Anti-windup lag',
                                )
        self.W = Washout(u=self.vp,
                         T=self.TF1,
                         K=self.KF1,
                         info='Signal conditioner'
                         )
        self.vout.e_str = 'ue * omega * vp - vout'
Esempio n. 16
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='-v + vref',
            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

        self.zero = ConstService(v_str='0.0')
        self.one = ConstService(v_str='1.0')

        self.LA1 = LagAntiWindup(
            u='ue * (LA3_y + V4)',
            T=self.TE,
            K=self.one,
            D=self.KE,
            upper=self.VBMAX,
            lower=self.zero,
            info=r'E_{FD}, vout, Lag Anti-Windup',
        )  # LA1_y is final output

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

        self.SQE = VarService(
            tex_name=r'SQE',
            info=r'Square Error',
            v_str='VE ** 2 - (0.78 * XadIfd) ** 2',
        )

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

        self.V4 = VarService(
            tex_name='V_4',
            v_str='SL_z1 * sqrt(SQE)',
        )

        self.vout.e_str = 'ue * (LA1_y - vout)'
Esempio n. 17
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'
Esempio n. 18
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        # 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='Transducer delay',
        )

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

        # NOTE: Se0 below is not divided by `vf0` or `INT_y`
        # `Se0` is the variable `Vx` in Powerworld's diagram
        self.Se0 = ConstService(
            tex_name='S_{e0}',
            v_str='Indicator(vf0>SAT_A) * SAT_B*(SAT_A-vf0) ** 2',
        )

        self.vfe0 = ConstService(
            v_str='vf0*KE + Se0',
            tex_name='V_{FE0}',
        )

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

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

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

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

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

        self.VRU = VarService(
            v_str='VRMAXc * v',
            tex_name='V_T V_{RMAX}',
        )
        self.VRL = VarService(
            v_str='VRMIN * v',
            tex_name='V_T V_{RMIN}',
        )

        # TODO: WARNING: HVGate is temporarily skipped
        self.LA = LagAntiWindup(
            u=self.LL_y,
            T=self.TA,
            K=self.KA,
            upper=self.VRU,
            lower=self.VRL,
            info='Anti-windup lag',
        )  # LA_y == VR

        self.SL = LessThan(
            u=self.vout,
            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='Se0',
            e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B - Se',
        )

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

        self.INT = Integrator(
            u='ue * (LA_y - VFE)',
            T=self.TE,
            K=1,
            y0=self.vf0,
            info='Integrator',
        )

        self.WF = Washout(u=self.INT_y,
                          T=self.TF1,
                          K=self.KF,
                          info='Feedback to input')

        self.vout.e_str = 'INT_y - vout'