Esempio n. 1
0
    def __init__(self, u, s10, s12, name=None, tex_name=None, info=None):
        self.s10 = s10
        self.s12 = s12

        points = [0, 0.8]
        c0 = [15, -24, 10]
        c1 = [-27.5, 50, -22.5]
        c2 = [12.5, -25, 12.5]

        self.c0 = ConstService(
            v_str=
            f'0.8*{c0[0]} + {c0[1]} * (1 - {s10.name}) + 1.2 * {c0[2]} * (1-{s12.name})',
            tex_name='c_0',
            info='Constant coefficient in quadratic saturation')
        self.c1 = ConstService(
            v_str=
            f'0.8*{c1[0]} + {c1[1]} * (1 - {s10.name}) + 1.2 * {c1[2]} * (1-{s12.name})',
            tex_name='c_1')
        self.c2 = ConstService(
            v_str=
            f'0.8*{c2[0]} + {c2[1]} * (1 - {s10.name}) + 1.2 * {c2[2]} * (1-{s12.name})',
            tex_name='c_2')

        super().__init__(u=u,
                         points=points,
                         funs=None,
                         name=name,
                         tex_name=tex_name,
                         info=info)

        self.vars.update({'c0': self.c0, 'c1': self.c1, 'c2': self.c2})
Esempio n. 2
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.group = 'DynLoad'
        self.flags.tds = True

        self.bus = ExtParam(model='PQ', src='bus', indexer=self.pq)

        self.p0 = ExtService(
            model='PQ',
            src='Ppf',
            indexer=self.pq,
            tex_name='P_0',
        )
        self.q0 = ExtService(
            model='PQ',
            src='Qpf',
            indexer=self.pq,
            tex_name='Q_0',
        )
        self.v0 = ExtService(
            model='Bus',
            src='v',
            indexer=self.bus,
            tex_name='V_0',
        )

        self.busfreq = DeviceFinder(
            u=self.busf,
            link=self.bus,
            idx_name='bus',
            info='found idx of BusFreq',
        )

        self.f = ExtAlgeb(
            model='FreqMeasurement',
            src='f',
            indexer=self.busfreq,
            tex_name='f',
        )

        self.pv0 = ConstService(v_str='u * kp/100 * p0 / (v0) ** ap ')
        self.qv0 = ConstService(v_str='u * kq/100 * q0 / (v0) ** aq ')

        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            tex_name=r'\theta',
            e_str='pv0 * (v ** ap) * (f ** bp)',
        )

        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.bus,
            tex_name='V',
            e_str='qv0 * (v ** aq) * (f ** bq)',
        )
Esempio n. 3
0
    def __init__(self, system, config):
        ModelData.__init__(self)
        self.bus = IdxParam(
            model='Bus',
            info="linked bus idx",
            mandatory=True,
        )
        self.tf = TimerParam(
            info='Fault start time for the bus',
            mandatory=True,
            callback=self.apply_fault,
        )
        self.tc = TimerParam(
            info='Fault end time for the bus',
            callback=self.clear_fault,
        )
        self.xf = NumParam(
            info='Fault to ground impedance',
            default=1e-4,
            tex_name='x_f',
        )
        self.rf = NumParam(
            info='Fault to ground resistance',
            default=0,
            tex_name='x_f',
        )

        Model.__init__(self, system, config)
        self.flags.update({'tds': True})
        self.group = 'TimedEvent'
        self.gf = ConstService(
            tex_name='g_{f}',
            v_str='re(1/(rf + 1j * xf))',
        )
        self.bf = ConstService(
            tex_name='b_{f}',
            v_str='im(1/(rf + 1j * xf))',
        )
        self.uf = ConstService(
            tex_name='u_f',
            v_str='0',
        )

        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            tex_name=r'\theta',
            e_str='u * uf * (v ** 2 * gf)',
        )
        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.bus,
            tex_name=r'V',
            e_str='u * uf * (v ** 2 * bf)',
        )
        self._vstore = np.array([])
Esempio n. 4
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. 5
0
    def __init__(self, system=None, config=None):
        LineData.__init__(self)
        Model.__init__(self, system, config)
        self.group = 'ACLine'
        self.flags.pflow = True
        self.flags.tds = True

        self.a1 = ExtAlgeb(model='Bus', src='a', indexer=self.bus1, tex_name='a_1',
                           info='phase angle of the from bus')
        self.a2 = ExtAlgeb(model='Bus', src='a', indexer=self.bus2, tex_name='a_2',
                           info='phase angle of the to bus')
        self.v1 = ExtAlgeb(model='Bus', src='v', indexer=self.bus1, tex_name='v_1',
                           info='voltage magnitude of the from bus')
        self.v2 = ExtAlgeb(model='Bus', src='v', indexer=self.bus2, tex_name='v_2',
                           info='voltage magnitude of the to bus')

        self.gh = ConstService(tex_name='g_h')
        self.bh = ConstService(tex_name='b_h')
        self.gk = ConstService(tex_name='g_k')
        self.bk = ConstService(tex_name='b_k')

        self.yh = ConstService(tex_name='y_h', vtype=np.complex)
        self.yk = ConstService(tex_name='y_k', vtype=np.complex)
        self.yhk = ConstService(tex_name='y_{hk}', vtype=np.complex)

        self.ghk = ConstService(tex_name='g_{hk}')
        self.bhk = ConstService(tex_name='b_{hk}')

        self.gh.v_str = 'g1 + 0.5 * g'
        self.bh.v_str = 'b1 + 0.5 * b'
        self.gk.v_str = 'g2 + 0.5 * g'
        self.bk.v_str = 'b2 + 0.5 * b'

        self.yh.v_str = 'u * (gh + 1j * bh)'
        self.yk.v_str = 'u * (gk + 1j * bk)'
        self.yhk.v_str = 'u/((r+1e-8) + 1j*(x+1e-8))'

        self.ghk.v_str = 're(yhk)'
        self.bhk.v_str = 'im(yhk)'

        self.a1.e_str = 'u * (v1 ** 2 * (gh + ghk) / tap ** 2  - \
                              v1 * v2 * (ghk * cos(a1 - a2 - phi) + \
                                         bhk * sin(a1 - a2 - phi)) / tap)'

        self.v1.e_str = 'u * (-v1 ** 2 * (bh + bhk) / tap ** 2 - \
                              v1 * v2 * (ghk * sin(a1 - a2 - phi) - \
                                         bhk * cos(a1 - a2 - phi)) / tap)'

        self.a2.e_str = 'u * (v2 ** 2 * (gh + ghk) - \
                              v1 * v2 * (ghk * cos(a1 - a2 - phi) - \
                                         bhk * sin(a1 - a2 - phi)) / tap)'

        self.v2.e_str = 'u * (-v2 ** 2 * (bh + bhk) + \
Esempio n. 6
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

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

        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.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 = 'LR_y*HLR_zi + vfmin*HLR_zl + vfmax*HLR_zu - vout'
Esempio n. 7
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.group = 'TurbineGov'
        self.flags.update({'tds': True})
        self.Sn = ExtParam(
            src='Sn',
            model='SynGen',
            indexer=self.syn,
            tex_name='S_m',
            info='Rated power from generator',
            unit='MVA',
            export=False,
        )
        self.Vn = ExtParam(
            src='Vn',
            model='SynGen',
            indexer=self.syn,
            tex_name='V_m',
            info='Rated voltage from generator',
            unit='kV',
            export=False,
        )
        self.tm0 = ExtService(src='tm',
                              model='SynGen',
                              indexer=self.syn,
                              tex_name=r'\tau_{m0}',
                              info='Initial mechanical input')
        self.omega = ExtState(src='omega',
                              model='SynGen',
                              indexer=self.syn,
                              tex_name=r'\omega',
                              info='Generator speed',
                              unit='p.u.')

        self.gain = ConstService(
            v_str='u / R',
            tex_name='G',
        )

        self.tm = ExtAlgeb(
            src='tm',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'\tau_m',
            e_str='u * (pout - tm0)',
            info='Mechanical power to generator',
        )
        self.pout = Algeb(
            info='Turbine final output power',
            tex_name='P_{out}',
            v_str='tm0',
        )
        self.wref = Algeb(
            info='Speed reference variable',
            tex_name=r'\omega_{ref}',
            v_str='wref0',
            e_str='wref0 - wref',
        )
Esempio n. 8
0
    def __init__(self, system, config):
        MotorBaseModel.__init__(self, system, config)

        self.x2 = ConstService(
            v_str='xs + xr1*xr2*xm / (xr1*xr2 + xr1*xm + xr2*xm)',
            tex_name="x''",
        )
        self.T20 = ConstService(
            v_str='(xr2 + xr1*xm / (xr1 + xm) ) / (wb * rr2)',
            tex_name="T''_0",
        )

        self.e2d = State(
            info='real part of 2nd cage voltage',
            e_str='u * '
            '(-wb*slip*(e1q - e2q) + '
            '(wb*slip*e1q - (e1d + (x0 - x1) * Iq)/T10) + '
            '(e1d - e2d - (x1 - x2) * Iq)/T20)',
            v_str='0.05 * u',
            tex_name="e''_d",
            diag_eps=True,
        )

        self.e2q = State(
            info='imag part of 2nd cage voltage',
            e_str='u * '
            '(wb*slip*(e1d - e2d) + '
            '(-wb*slip*e1d - (e1q - (x0 - x1) * Id)/T10) + '
            '(e1q - e2q + (x1 - x2) * Id) / T20)',
            v_str='0.9 * u',
            tex_name="e''_q",
            diag_eps=True,
        )

        self.Id.e_str = 'u * (vd - e2d - rs * Id + x2 * Iq)'

        self.Id.v_str = '0.9 * u'

        self.Iq.e_str = 'u * (vq - e2q - rs * Iq - x2 * Id)'

        self.Iq.v_str = '0.1 * u'

        self.te.v_str = 'u * (e2d * Id + e2q * Iq)'

        self.te.e_str = f'{self.te.v_str} - te'
Esempio n. 9
0
    def __init__(self, system, config):
        ShuntModel.__init__(self, system, config)

        self.config.add(OrderedDict((
            ('min_iter', 2),
            ('err_tol', 0.01),
        )))
        self.config.add_extra(
            "_help",
            min_iter="iteration number starting from which to enable switching",
            err_tol="iteration error below which to enable switching",
        )
        self.config.add_extra(
            "_alt",
            min_iter='int',
            err_tol='float',
        )
        self.config.add_extra(
            "_tex",
            min_iter="sw_{iter}",
            err_tol=r"\epsilon_{tol}",
        )

        self.beff = SwBlock(init=self.b, ns=self.ns, blocks=self.bs)
        self.geff = SwBlock(init=self.g,
                            ns=self.ns,
                            blocks=self.gs,
                            ext_sel=self.beff)

        self.vlo = ConstService(v_str='vref - dv', tex_name='v_{lo}')
        self.vup = ConstService(v_str='vref + dv', tex_name='v_{up}')

        self.adj = ShuntAdjust(v=self.v,
                               lower=self.vlo,
                               upper=self.vup,
                               bsw=self.beff,
                               gsw=self.geff,
                               dt=self.dt,
                               u=self.u,
                               min_iter=self.config.min_iter,
                               err_tol=self.config.err_tol,
                               info='shunt adjuster')

        self.a.e_str = 'u * v**2 * geff'
        self.v.e_str = '-u * v**2 * beff'
Esempio n. 10
0
    def __init__(self, system, config):
        ToggleData.__init__(self)
        Model.__init__(self, system, config)
        self.flags.update({'tds': True})
        self.group = 'TimedEvent'

        self.t.callback = self._u_switch
        self._init = False  # very first initialization that stores `u`
        self._u = ConstService('1')
Esempio n. 11
0
    def __init__(self, u, s10, s12, name=None, tex_name=None, info=None):
        self.s10 = s10
        self.s12 = s12

        points = [0, 1.0, 1.2]
        self.c = ConstService(v_str=f'log({s12.name} / {s10.name}) / log(1.2)')

        super().__init__(u=u, points=points, funs=None, name=name, tex_name=tex_name, info=info)
        self.vars.update({'c': self.c})
Esempio n. 12
0
    def __init__(self, system, config):
        super(IEEESTModel, self).__init__(system, config)

        self.KST5 = ConstService(v_str='KS * T5', tex_name='KS*T5')
        self.SW = Switcher(
            u=self.MODE,
            options=[1, 2, 3, 4, 5, 6],
        )

        self.signal = Algeb(
            tex_name='S_{in}',
            info='Input signal',
        )
        # input signals:
        # 1 (s0) - Rotor speed deviation (p.u.)
        # 2 (s1) - Bus frequency deviation (p.u.)                    # TODO: calculate freq without reimpl.
        # 3 (s2) - Generator electrical power in Gen MVABase (p.u.)  # TODO: allow using system.config.mva
        # 4 (s3) - Generator accelerating power (p.u.)
        # 5 (s4) - Bus voltage (p.u.)
        # 6 (s5) - Derivative of p.u. bus voltage                    # TODO: memory block for calc. of derivative

        self.signal.e_str = 'SW_s0 * (1-omega) + SW_s1 * 0 + SW_s2 * te + ' \
                            'SW_s3 * (tm-tm0) + SW_s4 *v + SW_s5 * 0 - signal'

        self.F1 = Lag2ndOrd(u=self.signal, K=1, T1=self.A1, T2=self.A2)

        self.F2 = LeadLag2ndOrd(u=self.F1_y,
                                T1=self.A3,
                                T2=self.A4,
                                T3=self.A5,
                                T4=self.A6)

        self.LL1 = LeadLag(u=self.F2_y, T1=self.T1, T2=self.T2)

        self.LL2 = LeadLag(u=self.LL1_y, T1=self.T3, T2=self.T4)

        self.WO = Washout(u=self.LL2_y, T=self.T6, K=self.KST5)  # WO_y == Vss

        self.VLIM = Limiter(u=self.WO_y,
                            lower=self.LSMIN,
                            upper=self.LSMAX,
                            info='Vss limiter')

        self.Vss = Algeb(
            tex_name='V_{ss}',
            info='Voltage output before output limiter',
            e_str='VLIM_zi * WO_y + VLIM_zu * LSMAX + VLIM_zl * LSMIN - Vss')

        self.OLIM = Limiter(u=self.v,
                            lower=self.VCL,
                            upper=self.VCU,
                            info='output limiter')

        # TODO: allow ignoring VCU or VCL when zero

        self.vsout.e_str = 'OLIM_zi * Vss - vsout'
Esempio n. 13
0
 def __init__(self):
     self.UEL0 = ConstService('0')
     self.UEL = Algeb(info='Interface var for under exc. limiter',
                      tex_name='U_{EL}',
                      v_str='UEL0',
                      e_str='UEL0 - UEL')
     self.OEL0 = ConstService('0')
     self.OEL = Algeb(info='Interface var for over exc. limiter',
                      tex_name='O_{EL}',
                      v_str='OEL0',
                      e_str='OEL0 - OEL')
     self.Vs = Algeb(info='Voltage compensation from PSS',
                     tex_name='V_{s}',
                     v_str='0',
                     e_str='0 - Vs')
     self.vref = Algeb(info='Reference voltage input',
                       tex_name='V_{ref}',
                       unit='p.u.',
                       e_str='vref0 - vref'
                       # TODO: subclass to provide `vi.v_str`
                       )
Esempio n. 14
0
    def __init__(self, E1, SE1, E2, SE2, name=None, tex_name=None, info=None):
        Block.__init__(self, name=name, tex_name=tex_name, info=info)

        self._E1 = dummify(E1)
        self._E2 = dummify(E2)
        self._SE1 = SE1
        self._SE2 = SE2

        self.zSE2 = FlagValue(self._SE2,
                              value=0.,
                              info='Flag non-zeros in SE2',
                              tex_name='z^{SE2}')

        # data correction for E1, E2, SE1 (TODO)
        self.E1 = ConstService(
            tex_name='E^{1c}',
            info='Corrected E1 data',
        )
        self.E2 = ConstService(
            tex_name='E^{2c}',
            info='Corrected E2 data',
        )
        self.SE1 = ConstService(
            tex_name='SE^{1c}',
            info='Corrected SE1 data',
        )
        self.SE2 = ConstService(
            tex_name='SE^{2c}',
            info='Corrected SE2 data',
        )
        self.a = ConstService(
            info='Intermediate Sat coeff',
            tex_name='a',
        )
        self.A = ConstService(
            info='Saturation start',
            tex_name='A^q',
        )
        self.B = ConstService(
            info='Saturation gain',
            tex_name='B^q',
        )
        self.vars = {
            'E1': self.E1,
            'E2': self.E2,
            'SE1': self.SE1,
            'SE2': self.SE2,
            'zSE2': self.zSE2,
            'a': self.a,
            'A': self.A,
            'B': self.B,
        }
Esempio n. 15
0
    def __init__(self, system, config):
        ModelData.__init__(self)
        Model.__init__(self, system, config)
        self.flags.tds = True
        self.group = 'FreqMeasurement'

        # Parameters
        self.bus = IdxParam(info="bus idx", mandatory=True)
        self.Tf = NumParam(default=0.02, info="input digital filter time const", unit="sec",
                           tex_name='T_f')
        self.Tw = NumParam(default=0.02, info="washout time const", unit="sec",
                           tex_name='T_w')
        self.fn = NumParam(default=60.0, info="nominal frequency", unit='Hz',
                           tex_name='f_n')

        # Variables
        self.iwn = ConstService(v_str='u / (2 * pi * fn)', tex_name=r'1/\omega_n')
        self.a0 = ExtService(src='a',
                             model='Bus',
                             indexer=self.bus,
                             tex_name=r'\theta_0',
                             info='initial phase angle',
                             )
        self.a = ExtAlgeb(model='Bus',
                          src='a',
                          indexer=self.bus,
                          tex_name=r'\theta',
                          )
        self.v = ExtAlgeb(model='Bus',
                          src='v',
                          indexer=self.bus,
                          tex_name=r'V',
                          )
        self.L = Lag(u='(a-a0)',
                     T=self.Tf,
                     K=1,
                     info='digital filter',
                     )
        self.WO = Washout(u=self.L_y,
                          K=self.iwn,
                          T=self.Tw,
                          info='angle washout',
                          )
        self.f = Algeb(info='frequency output',
                       unit='p.u. (Hz)',
                       tex_name='f',
                       v_str='1',
                       e_str='1 + WO_y - f',
                       )
Esempio n. 16
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

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

        self.vref0 = ConstService(
            info='Initial reference voltage input',
            tex_name='V_{ref0}',
            v_str='vf0/K + v',
        )

        self.vref = Algeb(info='Reference voltage input',
                          tex_name='V_{ref}',
                          unit='p.u.',
                          v_str='vref0',
                          e_str='vref0 - 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. 17
0
    def __init__(self, u, T, K, info=None, name=None):
        super().__init__(name=name, info=info)
        self.T = dummify(T)
        self.K = dummify(K)
        self.enforce_tex_name((self.K, self.T))

        self.KT = ConstService(
            info='Constant K/T',
            tex_name=f'({self.K.tex_name}/{self.T.tex_name})',
            v_str=f'{self.K.name} / {self.T.name}')

        self.u = u
        self.x = State(info='State in washout filter',
                       tex_name="x'",
                       t_const=self.T)
        self.y = Algeb(info='Output of washout filter',
                       tex_name=r'y',
                       diag_eps=1e-6)
        self.vars = {'KT': self.KT, 'x': self.x, 'y': self.y}
Esempio n. 18
0
    def __init__(self, system, config):
        ACEData.__init__(self)
        Model.__init__(self, system, config)

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

        self.config.add(OrderedDict([
            ('freq_model', 'BusFreq'),
        ]))
        self.config.add_extra('_help', {
            'freq_model': 'default freq. measurement model',
        })
        self.config.add_extra('_alt', {'freq_model': ('BusFreq', )})

        self.area = ExtParam(model='Bus',
                             src='area',
                             indexer=self.bus,
                             export=False)

        self.busf.model = self.config.freq_model
        self.busfreq = DeviceFinder(self.busf,
                                    link=self.bus,
                                    idx_name='bus',
                                    default_model='BusFreq')

        self.imva = ConstService(v_str='1/sys_mva',
                                 info='reciprocal of system mva',
                                 tex_name='1/S_{b, sys}')

        self.f = ExtAlgeb(model='FreqMeasurement',
                          src='f',
                          indexer=self.busfreq,
                          export=False,
                          info='Bus frequency',
                          unit='p.u. (Hz)')
        self.ace = Algeb(
            info='area control error',
            unit='p.u. (MW)',
            tex_name='ace',
            e_str='10 * (bias * imva) * sys_f * (f - 1) - ace',
        )
Esempio n. 19
0
    def __init__(self, system, config):
        TGBase.__init__(self, system, config)

        self.gain = ConstService(
            v_str='u/R',
            tex_name='G',
        )

        self.pref = Algeb(
            info='Reference power input',
            tex_name='P_{ref}',
            v_str='tm0 * R',
            e_str='tm0 * R - pref',
        )

        self.wd = Algeb(
            info='Generator under speed',
            unit='p.u.',
            tex_name=r'\omega_{dev}',
            v_str='0',
            e_str='(wref - omega) - wd',
        )
        self.pd = Algeb(info='Pref plus under speed times gain',
                        unit='p.u.',
                        tex_name="P_d",
                        v_str='u * tm0',
                        e_str='u*(wd + pref + paux) * gain - pd')

        self.LAG = LagAntiWindup(
            u=self.pd,
            K=1,
            T=self.T1,
            lower=self.VMIN,
            upper=self.VMAX,
        )
        self.LL = LeadLag(
            u=self.LAG_y,
            T1=self.T2,
            T2=self.T3,
        )
        self.pout.e_str = '(LL_y + Dt * wd) - pout'
Esempio n. 20
0
    def __init__(self, u, T, K, info=None, name=None):
        super().__init__(name=name, info=info)
        if isinstance(T, (int, float)):
            self.T = DummyValues(T)
        else:
            self.T = T

        if isinstance(K, (int, float)):
            self.K = DummyValues(K)
        else:
            self.K = K

        self.KT = ConstService(
            info='Constant K/T',
            tex_name=f'({self.K.tex_name}/{self.T.tex_name})',
            v_str=f'{self.K.name} / {self.T.name}')

        self.u = u
        self.x = State(info='State in washout filter', tex_name="x'")
        self.y = Algeb(info='Output of washout filter', tex_name=r'y')
        self.vars = {'KT': self.KT, 'x': self.x, 'y': self.y}
Esempio n. 21
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.flags.tds = True
        self.group = 'DG'

        self.config.add(OrderedDict((('plim', 0),
                                     )))

        self.config.add_extra('_help',
                              plim='enable input power limit check bound by [0, pmx]',
                              )
        self.config.add_extra('_tex',
                              plim='P_{lim}',
                              )
        self.config.add_extra('_alt',
                              plim=(0, 1),
                              )

        self.SWPQ = Switcher(u=self.pqflag, options=(0, 1), tex_name='SW_{PQ}', cache=True)

        self.buss = DataSelect(self.igreg, self.bus,
                               info='selected bus (bus or igreg)',
                               )

        self.busfreq = DeviceFinder(self.busf, link=self.buss, idx_name='bus')

        # --- initial values from power flow ---
        # a : bus voltage angle
        # v : bus voltage magnitude
        # p0s : active power from connected static PV generator
        # q0s : reactive power from connected static PV generator
        # pref0 : initial active power set point for the PVD1 device
        # qref0 : initial reactive power set point for the PVD1 device

        self.a = ExtAlgeb(model='Bus', src='a', indexer=self.buss, tex_name=r'\theta',
                          info='bus (or igreg) phase angle',
                          unit='rad.',
                          e_str='-Ipout_y * v * u',
                          ename='P',
                          tex_ename='P',
                          )

        self.v = ExtAlgeb(model='Bus', src='v', indexer=self.buss, tex_name='V',
                          info='bus (or igreg) terminal voltage',
                          unit='p.u.',
                          e_str='-Iqout_y * v * u',
                          ename='Q',
                          tex_ename='Q',
                          )

        self.p0s = ExtService(model='StaticGen',
                              src='p',
                              indexer=self.gen,
                              tex_name='P_{0s}',
                              info='Initial P from static gen',
                              )
        self.q0s = ExtService(model='StaticGen',
                              src='q',
                              indexer=self.gen,
                              tex_name='Q_{0s}',
                              info='Initial Q from static gen',
                              )
        # --- calculate the initial P and Q for this distributed device ---
        self.pref0 = ConstService(v_str='gammap * p0s', tex_name='P_{ref0}',
                                  info='Initial P for the PVD1 device',
                                  )
        self.qref0 = ConstService(v_str='gammaq * q0s', tex_name='Q_{ref0}',
                                  info='Initial Q for the PVD1 device',
                                  )

        # frequency measurement variable `f`
        self.f = ExtAlgeb(model='FreqMeasurement', src='f', indexer=self.busfreq, export=False,
                          info='Bus frequency', unit='p.u.',
                          )

        self.fHz = Algeb(info='frequency in Hz',
                         v_str='fn * f', e_str='fn * f - fHz',
                         unit='Hz',
                         tex_name='f_{Hz}',
                         )

        # --- frequency branch ---
        self.FL1 = Limiter(u=self.fHz, lower=self.ft0, upper=self.ft1,
                           info='Under frequency comparer', no_warn=True,
                           )
        self.FL2 = Limiter(u=self.fHz, lower=self.ft2, upper=self.ft3,
                           info='Over frequency comparer', no_warn=True,
                           )

        self.Kft01 = ConstService(v_str='1/(ft1 - ft0)', tex_name='K_{ft01}')

        self.Ffl = Algeb(info='Coeff. for under frequency',
                         v_str='FL1_zi * Kft01 * (fHz - ft0) + FL1_zu',
                         e_str='FL1_zi * Kft01 * (fHz - ft0) + FL1_zu - Ffl',
                         tex_name='F_{fl}',
                         discrete=self.FL1,
                         )

        self.Kft23 = ConstService(v_str='1/(ft3 - ft2)', tex_name='K_{ft23}')

        self.Ffh = Algeb(info='Coeff. for over frequency',
                         v_str='FL2_zl + FL2_zi * (1 + Kft23 * (ft2 - fHz))',
                         e_str='FL2_zl + FL2_zi * (1 + Kft23 * (ft2 - fHz)) - Ffh',
                         tex_name='F_{fh}',
                         discrete=self.FL2,
                         )

        self.Fdev = Algeb(info='Frequency deviation',
                          v_str='fn - fHz', e_str='fn - fHz - Fdev',
                          unit='Hz', tex_name='f_{dev}',
                          )

        self.DB = DeadBand1(u=self.Fdev, center=0.0, lower=self.fdbd, upper=0.0, gain=self.ddn,
                            info='frequency deviation deadband with gain',
                            )  # outputs   `Pdrp`
        self.DB.db.no_warn = True

        # --- Voltage flags ---
        self.VL1 = Limiter(u=self.v, lower=self.vt0, upper=self.vt1,
                           info='Under voltage comparer', no_warn=True,
                           )
        self.VL2 = Limiter(u=self.v, lower=self.vt2, upper=self.vt3,
                           info='Over voltage comparer', no_warn=True,
                           )

        self.Kvt01 = ConstService(v_str='1/(vt1 - vt0)', tex_name='K_{vt01}')

        self.Fvl = Algeb(info='Coeff. for under voltage',
                         v_str='VL1_zi * Kvt01 * (v - vt0) + VL1_zu',
                         e_str='VL1_zi * Kvt01 * (v - vt0) + VL1_zu - Fvl',
                         tex_name='F_{vl}',
                         discrete=self.VL1,
                         )

        self.Kvt23 = ConstService(v_str='1/(vt3 - vt2)', tex_name='K_{vt23}')

        self.Fvh = Algeb(info='Coeff. for over voltage',
                         v_str='VL2_zl + VL2_zi * (1 + Kvt23 * (vt2 - v))',
                         e_str='VL2_zl + VL2_zi * (1 + Kvt23 * (vt2 - v)) - Fvh',
                         tex_name='F_{vh}',
                         discrete=self.VL2,
                         )
        # --- sensed voltage with lower limit of 0.01 ---
        self.VLo = Limiter(u=self.v, lower=0.01, upper=999, no_upper=True,
                           info='Voltage lower limit (0.01) flag',
                           )

        self.vp = Algeb(tex_name='V_p',
                        info='Sensed positive voltage',
                        v_str='v * VLo_zi + 0.01 * VLo_zl',
                        e_str='v * VLo_zi + 0.01 * VLo_zl - vp',
                        )

        self.Pext0 = ConstService(info='External additional signal added to Pext',
                                  tex_name='P_{ext0}',
                                  v_str='0',
                                  )

        self.Pext = Algeb(tex_name='P_{ext}',
                          info='External power signal (for AGC)',
                          v_str='u * Pext0',
                          e_str='u * Pext0 - Pext'
                          )

        self.Pref = Algeb(tex_name='P_{ref}',
                          info='Reference power signal (for scheduling setpoint)',
                          v_str='u * pref0',
                          e_str='u * pref0 - Pref'
                          )

        self.Psum = Algeb(tex_name='P_{tot}',
                          info='Sum of P signals',
                          v_str='u * (Pext + Pref + DB_y)',
                          e_str='u * (Pext + Pref + DB_y) - Psum',
                          )  # `DB_y` is `Pdrp` (f droop)

        self.PHL = Limiter(u=self.Psum, lower=0.0, upper=self.pmx,
                           enable=self.config.plim,
                           info='limiter for Psum in [0, pmx]',
                           )

        self.Vcomp = VarService(v_str='abs(v*exp(1j*a) + (1j * xc) * (Ipout_y + 1j * Iqout_y))',
                                info='Voltage before Xc compensation',
                                tex_name='V_{comp}'
                                )

        self.Vqu = ConstService(v_str='v1 - (qref0 - qmn) / dqdv',
                                info='Upper voltage bound => qmx',
                                tex_name='V_{qu}',
                                )

        self.Vql = ConstService(v_str='v0 + (qmx - qref0) / dqdv',
                                info='Lower voltage bound => qmn',
                                tex_name='V_{ql}',
                                )

        self.VQ1 = Limiter(u=self.Vcomp, lower=self.Vql, upper=self.v0,
                           info='Under voltage comparer for Q droop',
                           no_warn=True,
                           )

        self.VQ2 = Limiter(u=self.Vcomp, lower=self.v1, upper=self.Vqu,
                           info='Over voltage comparer for Q droop',
                           no_warn=True,
                           )

        Qdrp = 'u * VQ1_zl * qmx + VQ2_zu * qmn + ' \
               'u * VQ1_zi * (qmx + dqdv *(Vqu - Vcomp)) + ' \
               'u * VQ2_zi * (dqdv * (v1 - Vcomp)) '

        self.Qdrp = Algeb(tex_name='Q_{drp}',
                          info='External power signal (for AGC)',
                          v_str=Qdrp,
                          e_str=f'{Qdrp} - Qdrp',
                          discrete=(self.VQ1, self.VQ2),
                          )

        self.Qref = Algeb(tex_name=r'Q_{ref}',
                          info='Reference power signal (for scheduling setpoint)',
                          v_str='u * qref0',
                          e_str='u * qref0 - Qref'
                          )

        self.Qsum = Algeb(tex_name=r'Q_{tot}',
                          info='Sum of Q signals',
                          v_str=f'u * (qref0 + {Qdrp})',
                          e_str='u * (Qref + Qdrp) - Qsum',
                          discrete=(self.VQ1, self.VQ2),
                          )

        self.Ipul = Algeb(info='Ipcmd before Ip hard limit',
                          v_str='(Psum * PHL_zi + pmx * PHL_zu) / vp',
                          e_str='(Psum * PHL_zi + pmx * PHL_zu) / vp - Ipul',
                          tex_name='I_{p,ul}',
                          )

        self.Iqul = Algeb(info='Iqcmd before Iq hard limit',
                          v_str='Qsum / vp',
                          e_str='Qsum / vp - Iqul',
                          tex_name='I_{q,ul}',
                          )

        # --- Ipmax, Iqmax and Iqmin ---
        Ipmaxsq = "(Piecewise((0, Le(ialim**2 - Iqcmd_y**2, 0)), ((ialim**2 - Iqcmd_y ** 2), True)))"
        Ipmaxsq0 = "(Piecewise((0, Le(ialim**2 - (u*qref0/v)**2, 0)), ((ialim**2 - (u*qref0/v) ** 2), True)))"
        self.Ipmaxsq = VarService(v_str=Ipmaxsq, tex_name='I_{pmax}^2')
        self.Ipmaxsq0 = ConstService(v_str=Ipmaxsq0, tex_name='I_{pmax0}^2')

        self.Ipmax = Algeb(v_str='(SWPQ_s1 * ialim + SWPQ_s0 * sqrt(Ipmaxsq0))',
                           e_str='(SWPQ_s1 * ialim + SWPQ_s0 * sqrt(Ipmaxsq)) - Ipmax',
                           tex_name='I_{pmax}',
                           )

        Iqmaxsq = "(Piecewise((0, Le(ialim**2 - Ipcmd_y**2, 0)), ((ialim**2 - Ipcmd_y ** 2), True)))"
        Iqmaxsq0 = "(Piecewise((0, Le(ialim**2 - (u*pref0/v)**2, 0)), ((ialim**2 - (u*pref0/v) ** 2), True)))"
        self.Iqmaxsq = VarService(v_str=Iqmaxsq, tex_name='I_{qmax}^2')
        self.Iqmaxsq0 = ConstService(v_str=Iqmaxsq0, tex_name='I_{qmax0}^2')

        self.Iqmax = Algeb(v_str='SWPQ_s0 * ialim + SWPQ_s1 * sqrt(Iqmaxsq0)',
                           e_str='SWPQ_s0 * ialim + SWPQ_s1 * sqrt(Iqmaxsq) - Iqmax',
                           tex_name='I_{qmax}',
                           )

        # TODO: set option whether to use degrading gain
        # --- `Ipcmd` and `Iqcmd` ---
        self.Ipcmd = GainLimiter(u=self.Ipul,
                                 K=1, R='Fvl * Fvh * Ffl * Ffh * recflag + 1 * (1 - recflag)',
                                 lower=0, upper=self.Ipmax,
                                 info='Ip with limiter and coeff.',
                                 tex_name='I^{pcmd}',
                                 )

        self.Iqcmd = GainLimiter(u=self.Iqul,
                                 K=1, R='Fvl * Fvh * Ffl * Ffh * recflag + 1 * (1 - recflag)',
                                 lower=self.Iqmax, sign_lower=-1,
                                 upper=self.Iqmax,
                                 info='Iq with limiter and coeff.',
                                 tex_name='I^{qcmd}',
                                 )

        self.Ipout = Lag(u=self.Ipcmd_y, T=self.tip, K=1.0,
                         info='Output Ip filter',
                         )

        self.Iqout = Lag(u=self.Iqcmd_y, T=self.tiq, K=1.0,
                         info='Output Iq filter',
                         )
Esempio n. 22
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 / 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'
Esempio n. 23
0
    def __init__(self, system, config):
        ModelData.__init__(self)
        self.bus = IdxParam(
            model='Bus',
            info="linked bus idx",
            mandatory=True,
        )
        self.tf = TimerParam(
            info='Bus fault start time',
            unit='second',
            mandatory=True,
            callback=self.apply_fault,
        )
        self.tc = TimerParam(
            info='Bus fault end time',
            unit='second',
            callback=self.clear_fault,
        )
        self.xf = NumParam(
            info='Fault to ground impedance (positive)',
            unit='p.u.(sys)',
            default=1e-4,
            tex_name='x_f',
        )
        self.rf = NumParam(
            info='Fault to ground resistance (positive)',
            unit='p.u.(sys)',
            default=0,
            tex_name='x_f',
        )

        Model.__init__(self, system, config)
        self.flags.update({'tds': True})
        self.group = 'TimedEvent'
        self.gf = ConstService(
            tex_name='g_{f}',
            v_str='re(1/(rf + 1j * xf))',
        )
        self.bf = ConstService(
            tex_name='b_{f}',
            v_str='im(1/(rf + 1j * xf))',
        )

        # uf: an internal flag of whether the fault is in action (1) or not (0)
        self.uf = ConstService(tex_name='u_f', v_str='0')

        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            tex_name=r'\theta',
            info='Bus voltage angle',
            unit='p.u.(kV)',
            e_str='u * uf * (v ** 2 * gf)',
        )
        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.bus,
            tex_name=r'V',
            unit='p.u.(kV)',
            info='Bus voltage magnitude',
            e_str='-u * uf * (v ** 2 * bf)',
        )
        self._vstore = np.array([])
Esempio n. 24
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. 25
0
    def __init__(self):
        # parameter checking for `xl`
        self._xlc = InitChecker(u=self.xl, info='(xl <= xd2)', upper=self.xd2)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.Id.e_str += '+ xd2*Id - psi2d'
Esempio n. 26
0
    def __init__(self):
        # internal voltage and rotor angle calculation
        self.xq = ExtService(
            model='GENCLS',
            src='xd1',
            indexer=self.idx,
        )
        self._V = ConstService(
            v_str='v * exp(1j * a)',
            tex_name='V_c',
            vtype=np.complex,
        )
        self._S = ConstService(
            v_str='p0 - 1j * q0',
            tex_name='S',
            vtype=np.complex,
        )
        self._I = ConstService(
            v_str='_S / conj(_V)',
            tex_name='I_c',
            vtype=np.complex,
        )
        self._E = ConstService(tex_name='E', vtype=np.complex)
        self._deltac = ConstService(tex_name=r'\delta_c', vtype=np.complex)
        self.delta0 = ConstService(tex_name=r'\delta_0')

        self.vdq = ConstService(
            v_str='u * (_V * exp(1j * 0.5 * pi - _deltac))',
            tex_name='V_{dq}',
            vtype=np.complex)
        self.Idq = ConstService(
            v_str='u * (_I * exp(1j * 0.5 * pi - _deltac))',
            tex_name='I_{dq}',
            vtype=np.complex)

        self.Id0 = ConstService(v_str='re(Idq)', tex_name=r'I_{d0}')
        self.Iq0 = ConstService(v_str='im(Idq)', tex_name=r'I_{q0}')
        self.vd0 = ConstService(v_str='re(vdq)', tex_name=r'V_{d0}')
        self.vq0 = ConstService(v_str='im(vdq)', tex_name=r'V_{q0}')

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

        # initialization of internal voltage and delta
        self._E.v_str = '_V + _I * (ra + 1j * xq)'
        self._deltac.v_str = 'log(_E / abs(_E))'
        self.delta0.v_str = 'u * im(_deltac)'

        self.Id.e_str += '+ xq * Id - vf'
        self.Iq.e_str += '+ xq * Iq'
        self.vf0.v_str = '(vq0 + ra * Iq0) + xq * Id0'
Esempio n. 27
0
    def __init__(self, system, config):
        super().__init__(system, config)
        self.group = 'SynGen'
        self.flags.update({
            'tds': True,
            'nr_iter': False,
        })
        self.config.add(
            vf_lower=1.0,
            vf_upper=5.0,
        )

        self.config.add_extra(
            "_help",
            vf_lower="lower limit for vf warning",
            vf_upper="upper limit for vf warning",
        )

        # state variables
        self.delta = State(info='rotor angle',
                           unit='rad',
                           v_str='delta0',
                           tex_name=r'\delta',
                           e_str='u * (2 * pi * fn) * (omega - 1)')
        self.omega = State(info='rotor speed',
                           unit='pu (Hz)',
                           v_str='u',
                           tex_name=r'\omega',
                           e_str='(u / M) * (tm - te - D * (omega - 1))')

        # network algebraic variables
        self.a = ExtAlgeb(model='Bus',
                          src='a',
                          indexer=self.bus,
                          tex_name=r'\theta',
                          info='Bus voltage phase angle',
                          e_str='-u * (vd * Id + vq * Iq)')
        self.v = ExtAlgeb(model='Bus',
                          src='v',
                          indexer=self.bus,
                          tex_name=r'V',
                          info='Bus voltage magnitude',
                          e_str='-u * (vq * Id - vd * Iq)')

        # algebraic variables
        # Need to be provided by specific generator models
        self.Id = Algeb(info='d-axis current',
                        v_str='u * Id0',
                        tex_name=r'I_d',
                        e_str='')  # to be completed by subclasses
        self.Iq = Algeb(info='q-axis current',
                        v_str='u * Iq0',
                        tex_name=r'I_q',
                        e_str='')  # to be completed

        self.vd = Algeb(
            info='d-axis voltage',
            v_str='u * vd0',
            e_str='u * v * sin(delta - a) - vd',
            tex_name=r'V_d',
        )
        self.vq = Algeb(
            info='q-axis voltage',
            v_str='u * vq0',
            e_str='u * v * cos(delta - a) - vq',
            tex_name=r'V_q',
        )

        self.tm = Algeb(info='mechanical torque',
                        tex_name=r'\tau_m',
                        v_str='tm0',
                        e_str='tm0 - tm')
        self.te = Algeb(
            info='electric torque',
            tex_name=r'\tau_e',
            v_str='u * tm0',
            e_str='u * (psid * Iq - psiq * Id) - te',
        )
        self.vf = Algeb(info='excitation voltage',
                        unit='pu',
                        v_str='u * vf0',
                        e_str='u * vf0 - vf',
                        tex_name=r'v_f')

        self._vfc = InitChecker(
            u=self.vf,
            info='(vf range)',
            lower=self.config.vf_lower,
            upper=self.config.vf_upper,
        )

        self.XadIfd = Algeb(tex_name='X_{ad}I_{fd}',
                            info='d-axis armature excitation current',
                            unit='p.u (kV)',
                            v_str='u * vf0',
                            e_str='u * vf0 - XadIfd'
                            )  # e_str to be provided. Not available in GENCLS

        self.subidx = ExtParam(
            model='StaticGen',
            src='subidx',
            indexer=self.gen,
            export=False,
            info='Generator idx in plant; only used by PSS/E data')

        # declaring `Vn_bus` as ExtParam will fail for PSS/E parser
        self.Vn_bus = ExtService(
            model='Bus',
            src='Vn',
            indexer=self.bus,
        )
        self._vnc = InitChecker(
            u=self.Vn,
            info='Vn and Bus Vn',
            equal=self.Vn_bus,
        )

        # ----------service consts for initialization----------
        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',
        )
Esempio n. 28
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.group = 'Calculation'
        self.flags.update({'tds': True})

        self.SynGen = BackRef(info='Back reference to SynGen idx')

        self.SynGenIdx = RefFlatten(ref=self.SynGen)

        self.M = ExtParam(
            model='SynGen',
            src='M',
            indexer=self.SynGenIdx,
            export=False,
            info='Linearly stored SynGen.M',
        )

        self.wgen = ExtState(
            model='SynGen',
            src='omega',
            indexer=self.SynGenIdx,
            tex_name=r'\omega_{gen}',
            info='Linearly stored SynGen.omega',
        )
        self.agen = ExtState(
            model='SynGen',
            src='delta',
            indexer=self.SynGenIdx,
            tex_name=r'\delta_{gen}',
            info='Linearly stored SynGen.delta',
        )
        self.d0 = ExtService(
            model='SynGen',
            src='delta',
            indexer=self.SynGenIdx,
            tex_name=r'\delta_{gen,0}',
            info='Linearly stored initial delta',
        )

        self.a0 = ExtService(
            model='SynGen',
            src='omega',
            indexer=self.SynGenIdx,
            tex_name=r'\omega_{gen,0}',
            info='Linearly stored initial omega',
        )

        self.Mt = NumReduce(
            u=self.M,
            tex_name='M_t',
            fun=np.sum,
            ref=self.SynGen,
            info='Summation of M by COI index',
        )

        self.Mr = NumRepeat(
            u=self.Mt,
            tex_name='M_{tr}',
            ref=self.SynGen,
            info='Repeated summation of M',
        )

        self.Mw = ConstService(tex_name='M_w',
                               info='Inertia weights',
                               v_str='M/Mr')

        self.d0w = ConstService(tex_name=r'\delta_{gen,0,w}',
                                v_str='d0 * Mw',
                                info='Linearly stored weighted delta')

        self.a0w = ConstService(tex_name=r'\omega_{gen,0,w}',
                                v_str='a0 * Mw',
                                info='Linearly stored weighted omega')

        self.d0a = NumReduce(
            u=self.d0w,
            tex_name=r'\delta_{gen,0,avg}',
            fun=np.sum,
            ref=self.SynGen,
            info='Average initial delta',
            cache=False,
        )

        self.a0a = NumReduce(
            u=self.a0w,
            tex_name=r'\omega_{gen,0,avg}',
            fun=np.sum,
            ref=self.SynGen,
            info='Average initial omega',
            cache=False,
        )

        self.pidx = IdxRepeat(u=self.idx,
                              ref=self.SynGen,
                              info='Repeated COI.idx')

        # Note:
        # Even if d(omega) /d (omega) = 1, it is still stored as a lambda function.
        # When no SynGen is referencing any COI, j_update will not be called,
        # and Jacobian will become singular. `diag_eps = True` needs to be used.

        # Note:
        # Do not assign `v_str=1` for `omega`. Otherwise, COIs with no connected generators will
        # fail to initialize.
        self.omega = Algeb(
            tex_name=r'\omega_{coi}',
            info='COI speed',
            v_str='a0a',
            v_setter=True,
            e_str='-omega',
            diag_eps=True,
        )
        self.delta = Algeb(
            tex_name=r'\delta_{coi}',
            info='COI rotor angle',
            v_str='d0a',
            v_setter=True,
            e_str='-delta',
            diag_eps=True,
        )

        # Note:
        # `omega_sub` or `delta_sub` must not provide `v_str`.
        # Otherwise, values will be incorrectly summed for `omega` and `delta`.
        self.omega_sub = ExtAlgeb(
            model='COI',
            src='omega',
            e_str='Mw * wgen',
            indexer=self.pidx,
            info='COI frequency contribution of each generator')
        self.delta_sub = ExtAlgeb(
            model='COI',
            src='delta',
            e_str='Mw * agen',
            indexer=self.pidx,
            info='COI angle contribution of each generator')
Esempio n. 29
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. 30
0
    def __init__(self):
        self.gd1 = ConstService(v_str='(xd2 - xl) / (xd1 - xl)',
                                tex_name=r"\gamma_{d1}")
        self.gq1 = ConstService(v_str='(xq2 - xl) / (xq1 - xl)',
                                tex_name=r"\gamma_{q1}")
        self.gd2 = ConstService(v_str='(xd1 - xd2) / (xd1 - xl) ** 2',
                                tex_name=r"\gamma_{d2}")
        self.gq2 = ConstService(v_str='(xq1 - xq2) / (xq1 - xl) ** 2',
                                tex_name=r"\gamma_{q2}")
        self.gqd = ConstService(v_str='(xq - xl) / (xd - xl)',
                                tex_name=r"\gamma_{qd}")

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

        # internal voltage and rotor angle calculation

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.Id.e_str += '+ xd2 * Id - gd1 * e1q - (1 - gd1) * e2d'
        self.Iq.e_str += '+ xq2 * Iq + gq1 * e1d - (1 - gq1) * e2q'