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'
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'
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'
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'
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 / vf0', ) 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.vref0 = ConstService( info='Initial reference voltage input', tex_name='V_{ref0}', v_str='v + vb0', ) 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='vref0', e_str='vref0 - vref') 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.', e_str='-LG_y + vref - vi', v_str='-v + vref', ) self.LA = LagAntiWindup( u='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='INT_y * (KE + Se) - VFE') self.INT = Integrator( u='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 / INT_y - Se', ) self.WF = Washout(u=self.vout, T=self.TF, K=self.KF, info='Stablizing circuit feedback') self.vout.e_str = 'INT_y - vout'
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'
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'
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=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'
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)'
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'
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', ) self.Se0 = ConstService( tex_name='S_{e0}', v_str='Indicator(vf0>SAT_A) * SAT_B*(SAT_A-vf0) ** 2 / vf0', ) self.vfe0 = ConstService( v_str='vf0 * (KE + Se0)', tex_name='V_{FE0}', ) self.vref0 = ConstService( info='Initial reference voltage input', tex_name='V_{ref0}', v_str='v + vfe0 / KA', ) self.vref = Algeb(info='Reference voltage input', tex_name='V_{ref}', unit='p.u.', v_str='vref0', e_str='vref0 - vref') self.vi = Algeb( info='Total input voltages', tex_name='V_i', unit='p.u.', v_str='vref0 - v', 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 # `LessThan` may be causing memory issue in (SL_z0 * vout) - uncertain yet 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 / INT_y - 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='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'
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)'
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)'
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'
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'