Beispiel #1
0
    def __init__(self, system, config):
        DC2Term.__init__(self, system, config)
        self.flags.pflow = True
        self.group = 'DCLink'

        self.R = NumParam(
            unit='p.u.',
            tex_name='R',
            info='DC line resistance',
            non_zero=True,
            default=0.01,
            r=True,
        )
        self.L = NumParam(
            unit='p.u.',
            tex_name='L',
            info='DC line inductance',
            non_zero=True,
            default=0.001,
            r=True,
        )
        self.C = NumParam(
            unit='p.u.',
            tex_name='C',
            info='DC capacitance',
            non_zero=True,
            default=0.001,
            g=True,
        )
        self.IL = State(
            tex_name='I_L',
            info='Inductance current',
            unit='p.u.',
            v_str='0',
            e_str='u * vC',
            t_const=self.L,
        )
        self.vC = State(
            tex_name='v_C',
            info='Capacitor current',
            unit='p.u.',
            e_str='-u * (Idc - vC/R - IL)',
            v_str='v1 - v2',
            t_const=self.C,
        )
        self.Idc = Algeb(
            tex_name='I_{dc}',
            info='Current from node 2 to 1',
            unit='p.u.',
            e_str='u * (vC - (v1 - v2)) + '
            '(1 - u) * Idc',
            v_str='-(v1 - v2) / R',
            diag_eps=True,
        )
        self.v1.e_str = '-Idc'
        self.v2.e_str = '+Idc'
Beispiel #2
0
    def __init__(self, system, config):
        TGBase.__init__(self, system, config)

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

        self.LAG_y = State(
            info='State in lag transfer function',
            tex_name=r"x'_{LAG}",
            e_str='LAG_lim_zi * (1 * pd - LAG_y)',
            t_const=self.T1,
            v_str='pd',
        )
        self.LAG_lim = AntiWindup(
            u=self.LAG_y,
            lower=self.VMIN,
            upper=self.VMAX,
            tex_name='lim_{lag}',
        )
        self.LL_x = State(info='State in lead-lag transfer function',
                          tex_name="x'_{LL}",
                          v_str='LAG_y',
                          e_str='(LAG_y - LL_x)',
                          t_const=self.T3)
        self.LL_y = Algeb(
            info='Lead-lag Output',
            tex_name='y_{LL}',
            v_str='LAG_y',
            e_str='T2 / T3 * (LAG_y - LL_x) + LL_x - LL_y',
        )

        self.pout.e_str = 'ue * (LL_y - Dt * wd) - pout'
Beispiel #3
0
    def __init__(self):
        self.psid = State(
            info='d-axis flux',
            tex_name=r'\psi_d',
            v_str='u * psid0',
            e_str='u * 2 * pi * fn * (ra * Id + vd + omega * psiq)',
        )
        self.psiq = State(
            info='q-axis flux',
            tex_name=r'\psi_q',
            v_str='u * psiq0',
            e_str='u * 2 * pi * fn * (ra * Iq + vq - omega * psid)',
        )

        self.Id.e_str += '+ psid'
        self.Iq.e_str += '+ psiq'
Beispiel #4
0
    def __init__(self, system, config):
        DC2Term.__init__(self, system, config)
        self.flags.pflow = True
        self.group = 'DCLink'

        self.C = NumParam(
            unit='p.u.',
            info='DC capacitance',
            non_zero=True,
            default=0.001,
            g=True,
        )
        self.vC = State(tex_name='v_C',
                        info='Capacitor current',
                        unit='p.u.',
                        v_str='0',
                        e_str='-u * Idc',
                        t_const=self.C)
        self.Idc = Algeb(
            tex_name='I_{dc}',
            info='Current from node 2 to 1',
            unit='p.u.',
            v_str='0',
            e_str='u * (vC - (v1 - v2)) + '
            '(1 - u) * Idc',
            diag_eps=True,
        )
        self.v1.e_str = '-Idc'
        self.v2.e_str = '+Idc'
Beispiel #5
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.flags.tds = True
        self.group = 'RenGovernor'

        self.reg = ExtParam(model='RenExciter', src='reg', indexer=self.ree,
                            export=False,
                            )

        self.Sn = ExtParam(model='RenGen', src='Sn', indexer=self.reg,
                           tex_name='S_n', export=False,
                           )

        self.wge = ExtAlgeb(model='RenExciter', src='wg', indexer=self.ree,
                            export=False,
                            e_str='-1.0 + s1_y',
                            ename='wg',
                            tex_ename=r'\omega_g',
                            )

        self.Pe = ExtAlgeb(model='RenGen', src='Pe', indexer=self.reg, export=False,
                           info='Retrieved Pe of RenGen')

        self.Pe0 = ExtService(model='RenGen', src='Pe', indexer=self.reg, tex_name='P_{e0}',
                              )

        self.H2 = ConstService(v_str='2 * H', tex_name='2H')

        self.Pm = Algeb(tex_name='P_m',
                        info='Mechanical power',
                        e_str='Pe0 - Pm',
                        v_str='Pe0',
                        )

        self.wr0 = Algeb(tex_name=r'\omega_{r0}',
                         unit='p.u.',
                         v_str='w0',
                         e_str='w0 - wr0',
                         info='speed set point',
                         )

        # `s1_y` is `w_m`
        self.s1 = Integrator(u='(Pm - Pe) / wge - D * (s1_y - wr0)',
                             T=self.H2,
                             K=1.0,
                             y0='wr0',
                             )

        # make two alias states, `wt` and `wg`, pointing to `s1_y`
        self.wt = AliasState(self.s1_y, tex_name=r'\omega_t')

        self.wg = AliasState(self.s1_y, tex_name=r'\omega_g')

        self.s3_y = State(info='Unused state variable',
                          tex_name='y_{s3}',
                          )

        self.Kshaft = ConstService(v_str='1.0', tex_name='K_{shaft}',
                                   info='Dummy Kshaft',
                                   )
Beispiel #6
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'
Beispiel #7
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.group = 'Experimental'
        self.flags.update({'tds': True})
        self.uin = State(
            v_str=0,
            e_str=
            'Piecewise((0, dae_t<= 0), (1, dae_t <= 2), (-1, dae_t <6), (1, True))',
            tex_name='u_{in}',
        )
        self.x = State(
            e_str='uin * Ki * HL_zi',
            v_str=0.05,
        )
        self.y = Algeb(e_str='uin * Kp + x - y', v_str=0.05)

        self.HL = HardLimiter(u=self.y, lower=self.Wmin, upper=self.Wmax)
        self.w = Algeb(e_str='HL_zi * y + HL_zl * Wmin + HL_zu * Wmax - w',
                       v_str=0.05)
Beispiel #8
0
    def __init__(self, system, config):
        PMUData.__init__(self)
        Model.__init__(self, system, config)

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

        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            tex_name=r'\theta',
            info='Bus voltage phase angle',
        )
        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.bus,
            tex_name=r'V',
            info='Bus voltage magnitude',
        )

        self.am = State(
            tex_name=r'\theta_m',
            info='phase angle measurement',
            unit='rad.',
            e_str='a - am',
            t_const=self.Ta,
            v_str='a',
        )

        self.vm = State(
            tex_name='V_m',
            info='voltage magnitude measurement',
            unit='p.u.(kV)',
            e_str='v - vm',
            t_const=self.Tv,
            v_str='v',
        )
Beispiel #9
0
    def __init__(self, system, config):
        DC2Term.__init__(self, system, config)
        self.flags.pflow = True
        self.group = 'DCLink'

        self.L = NumParam(
            unit='p.u.',
            info='DC line inductance',
            non_zero=True,
            default=0.001,
            r=True,
        )
        self.IL = State(
            tex_name='I_L',
            info='Inductance current',
            unit='p.u.',
            v_str='0',
            e_str='-u * (v1 - v2)',
            t_const=self.L,
        )
        self.v1.e_str = '-IL'
        self.v2.e_str = '+IL'
Beispiel #10
0
    def __init__(self, system, config):
        DC2Term.__init__(self, system, config)
        self.flags.pflow = True
        self.group = 'DCLink'

        self.R = NumParam(
            unit='p.u.',
            tex_name='R',
            info='DC line resistance',
            non_zero=True,
            default=0.01,
            r=True,
        )
        self.L = NumParam(
            unit='p.u.',
            tex_name='L',
            info='DC line inductance',
            non_zero=True,
            default=0.001,
            r=True,
        )
        self.IL = State(
            tex_name='I_L',
            info='Inductance current',
            unit='p.u.',
            e_str='u * (v1 - v2 - R * IL)',
            v_str='(v1 - v2) / R',
            t_const=self.L,
        )
        self.Idc = Algeb(
            tex_name='I_{dc}',
            info='Current from node 2 to 1',
            unit='p.u.',
            e_str='-u * IL - Idc',
            v_str='-u * (v1 - v2) / R',
        )
        self.v1.e_str = '-Idc'
        self.v2.e_str = '+Idc'
Beispiel #11
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.flags.tds = True
        self.group = 'RenGen'

        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            tex_name=r'\theta',
            info='Bus voltage angle',
            e_str='-u * Pe',
        )
        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.bus,
            tex_name='V',
            info='Bus voltage magnitude',
            e_str='-u * Qe',
        )

        self.p0s = ExtService(
            model='StaticGen',
            src='p',
            indexer=self.gen,
            tex_name=r'P_{0s}',
            info='total P of the static gen',
        )
        self.q0s = ExtService(
            model='StaticGen',
            src='q',
            indexer=self.gen,
            tex_name=r'Q_{0s}',
            info='total Q of the static gen',
        )
        self.Pref = ConstService(
            v_str='gammap * p0s',
            tex_name='P_{ref}',
            info='Initial P for the REGCV1 device',
        )
        self.Qref = ConstService(
            v_str='gammaq * q0s',
            tex_name='Q_{ref}',
            info='Initial Q for the REGCV1 device',
        )

        self.vref = ExtService(
            model='StaticGen',
            src='v',
            indexer=self.gen,
            tex_name=r'V_{ref}',
            info='initial v of the static gen',
        )

        # --- INITIALIZATION ---
        self.ixs = ConstService(
            v_str='1/xs',
            tex_name=r'1/xs',
        )
        self.Id0 = ConstService(
            tex_name=r'I_{d0}',
            v_str='u * Pref / v',
        )
        self.Iq0 = ConstService(
            tex_name=r'I_{q0}',
            v_str='- u * Qref / v',
        )

        self.vd0 = ConstService(
            tex_name=r'v_{d0}',
            v_str='u * v',
        )
        self.vq0 = ConstService(
            tex_name=r'v_{q0}',
            v_str='0',
        )

        self.Pref2 = Algeb(
            tex_name=r'P_{ref2}',
            info='active power reference after adjusting by frequency',
            e_str='u * Pref - dw * kw - Pref2',
            v_str='u * Pref')

        self.vref2 = Algeb(
            tex_name=r'v_{ref2}',
            info='voltage reference after adjusted by reactive power',
            e_str='(u * Qref - Qe) * kv + vref - vref2',
            v_str='u * vref')

        self.dw = State(info='delta virtual rotor speed',
                        unit='pu (Hz)',
                        v_str='0',
                        tex_name=r'\Delta\omega',
                        e_str='Pref2 - Pe - D * dw',
                        t_const=self.M)

        self.omega = Algeb(info='virtual rotor speed',
                           unit='pu (Hz)',
                           v_str='u',
                           tex_name=r'\omega',
                           e_str='1 + dw - omega')

        self.delta = State(info='virtual delta',
                           unit='rad',
                           v_str='a',
                           tex_name=r'\delta',
                           e_str='2 * pi * fn * dw')

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

        self.Pe = Algeb(tex_name='P_e',
                        info='active power injection from VSC',
                        e_str='vd * Id + vq * Iq - Pe',
                        v_str='Pref')
        self.Qe = Algeb(tex_name='Q_e',
                        info='reactive power injection from VSC',
                        e_str='- vd * Iq + vq * Id - Qe',
                        v_str='Qref')

        self.Id = Algeb(
            tex_name='I_d',
            info='d-axis current',
            v_str='Id0',
            diag_eps=True,
        )
        self.Iq = Algeb(
            tex_name='I_q',
            info='q-axis current',
            v_str='Iq0',
            diag_eps=True,
        )
Beispiel #12
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=complex)
        self._S = ConstService(v_str='p0 - 1j * q0',
                               tex_name='S',
                               info='complex terminal power',
                               vtype=complex)
        self._Zs = ConstService(v_str='ra + 1j * xd2',
                                tex_name='Z_s',
                                info='equivalent impedance',
                                vtype=complex)
        self._It = ConstService(v_str='_S / conj(_V)',
                                tex_name='I_t',
                                info='complex terminal current',
                                vtype=complex)
        self._Is = ConstService(tex_name='I_s',
                                v_str='_It + _V / _Zs',
                                info='equivalent current source',
                                vtype=complex)

        self.psi20 = ConstService(
            tex_name=r"\psi''_0",
            v_str='_Is * _Zs',
            info='sub-transient flux linkage in stator reference',
            vtype=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=complex)
        self.psi20_dq = ConstService(tex_name=r"\psi''_{0,dq}",
                                     v_str='psi20 * _Tdq',
                                     vtype=complex)
        self.It_dq = ConstService(tex_name=r"I_{t,dq}",
                                  v_str='conj(_It * _Tdq)',
                                  vtype=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='u * 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='u * 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='u * 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'
Beispiel #13
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)

        self.flags.pflow = True
        self.flags.tds = True
        self.flags.tds_init = False
        self.group = 'Motor'

        # services
        self.wb = ConstService(v_str='2 * pi * fn',
                               tex_name=r'\omega_b',
                               )

        self.x0 = ConstService(v_str='xs + xm',
                               tex_name='x_0',
                               )

        self.x1 = ConstService(v_str='xs + xr1 * xm / (xr1 + xm)',
                               tex_name="x'",
                               )

        self.T10 = ConstService(v_str='(xr1 + xm) / (wb * rr1)',
                                tex_name="T'_0",
                                )

        self.M = ConstService(v_str='2 * Hm',
                              tex_name='M',
                              )

        self.aa = ConstService(v_str='c1 + c2 + c3',
                               tex_name=r'\alpha',
                               )

        self.bb = ConstService(v_str='-c2 - 2 * c3',
                               tex_name=r'\beta',
                               )

        # network algebraic variables
        self.a = ExtAlgeb(model='Bus',
                          src='a',
                          indexer=self.bus,
                          tex_name=r'\theta',
                          info='Bus voltage phase angle',
                          e_str='+p',
                          ename='P',
                          tex_ename='P',
                          )

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

        self.vd = Algeb(info='d-axis voltage',
                        e_str='-u * v * sin(a) - vd',
                        tex_name=r'V_d',
                        )

        self.vq = Algeb(info='q-axis voltage',
                        e_str='u * v * cos(a) - vq',
                        tex_name=r'V_q',
                        )

        self.slip = State(tex_name=r"\sigma",
                          e_str='u * (tm - te)',
                          t_const=self.M,
                          diag_eps=True,
                          v_str='1.0 * u',
                          )

        self.p = Algeb(tex_name='P',
                       e_str='u * (vd * Id + vq * Iq) - p',
                       v_str='u * (vd * Id + vq * Iq)',
                       )

        self.q = Algeb(tex_name='Q',
                       e_str='u * (vq * Id - vd * Iq) - q',
                       v_str='u * (vq * Id - vd * Iq)',
                       )

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

        self.e1q = State(info='imaginary part of 1st cage voltage',
                         tex_name="e'_q",
                         v_str='0.9 * u',
                         e_str='u * (-wb*slip*e1d - (e1q - (x0 - x1) * Id)/T10)',
                         diag_eps=True,
                         )

        self.Id = Algeb(tex_name='I_d',
                        diag_eps=True,
                        )

        self.Iq = Algeb(tex_name='I_q',
                        diag_eps=True,
                        )

        self.te = Algeb(tex_name=r'\tau_e',
                        )

        self.tm = Algeb(tex_name=r'\tau_m',
                        )

        self.tm.v_str = 'u * (aa + bb * slip + c2 * slip * slip)'
        self.tm.e_str = f'{self.tm.v_str} - tm'
Beispiel #14
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)

        self.group = 'SynGen'

        self.group_param_exception = ['Sn', 'M', 'D']
        self.group_var_exception = ['vd', 'vq', 'Id', 'Iq', 'tm', 'te', 'vf', 'XadIfd']
        self.flags.tds = True

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

        self.zs = ConstService('ra + 1j * xs', vtype=complex,
                               info='impedance',
                               )
        self.zs2n = ConstService('ra * ra - xs * xs',
                                 info='ra^2 - xs^2',
                                 )

        # get power flow solutions

        self.p = ExtService(model='StaticGen', src='p',
                            indexer=self.gen,
                            )
        self.q = ExtService(model='StaticGen', src='q',
                            indexer=self.gen,
                            )
        self.Ec = ConstService('v * exp(1j * a) +'
                               'conj((p + 1j * q) / (v * exp(1j * a))) * (ra + 1j * xs)',
                               vtype=complex,
                               tex_name='E_c',
                               )

        self.E0 = ConstService('abs(Ec)', tex_name='E_0')
        self.delta0 = ConstService('arg(Ec)', tex_name=r'\delta_0')

        # Note: `Vts` and `fts` are assigned by TimeSeries before initializing this model.
        self.Vts = ConstService()
        self.fts = ConstService()

        self.ifscale = ConstService('1/fscale', tex_name='1/f_{scale}')
        self.iVscale = ConstService('1/Vscale', tex_name='1/V_{scale}')

        self.foffs = ConstService('fts * ifscale - 1', tex_name='f_{offs}')
        self.Voffs = ConstService('Vts * iVscale - E0', tex_name='V_{offs}')

        self.Vflt = State(info='filtered voltage',
                          t_const=self.Tv,
                          v_str='(iVscale * Vts - Voffs)',
                          e_str='(iVscale * Vts - Voffs) - Vflt',
                          unit='pu',
                          tex_name='V_{flt}',
                          )

        self.omega = State(info='filtered frequency',
                           t_const=self.Tf,
                           v_str='fts * ifscale - foffs',
                           e_str='(ifscale * fts - foffs) - omega',
                           unit='pu',
                           tex_name=r'\omega',
                           )

        self.delta = State(info='rotor angle',
                           unit='rad',
                           v_str='delta0',
                           tex_name=r'\delta',
                           e_str='u * (2 * pi * fn) * (omega - 1)',
                           )

        # --- Power injections are obtained by sympy ---

        # >>> from sympy import symbols, sin, cos, conjugate
        # >>> Vflt, delta, v, a, ra, xs = symbols('Vflt delta v a ra xs', real=True)

        # >>> S = -v * (cos(a) + 1j*sin(a)) * \
        #         conjugate((Vflt * (cos(delta)+1j*sin(delta)) - v*(cos(a)+1j*sin(a))) / (ra+1j*xs))
        # >>> S.simplify().as_real_imag()

        self.a = ExtAlgeb(model='Bus',
                          src='a',
                          indexer=self.bus,
                          tex_name=r'\theta',
                          info='Bus voltage phase angle',
                          e_str='Vflt*v*xs*sin(a - delta)/(ra*ra + xs*xs) + '
                                'ra*v*(-Vflt*cos(a - delta) + v)/(ra*ra + xs*xs)',
                          ename='P',
                          tex_ename='P',
                          )
        self.v = ExtAlgeb(model='Bus',
                          src='v',
                          indexer=self.bus,
                          tex_name=r'V',
                          info='Bus voltage magnitude',
                          ename='Q',
                          e_str='-Vflt*ra*v*sin(a - delta)/(ra*ra + xs*xs) + '
                                'v*xs*(-Vflt*cos(a - delta) + v)/(ra*ra + xs*xs)',
                          tex_ename='Q',
                          )
Beispiel #15
0
    def __init__(self, system, config):
        TGBase.__init__(self, system, config)

        self.VELMn = ConstService(
            v_str='-VELM',
            tex_name='-VELM',
        )
        self.tr = ConstService(
            v_str='r * Tr',
            tex_name='r*Tr',
        )
        self.gr = ConstService(
            v_str='1/r',
            tex_name='1/r',
        )
        self.ratel = ConstService(
            v_str='- VELM - gr',
            tex_name='rate_l',
        )
        self.rateu = ConstService(
            v_str='VELM - gr',
            tex_name='rate_u',
        )
        self.q0 = ConstService(
            v_str='tm0 / At + qNL',
            tex_name='q_0',
        )
        self.pref = Algeb(
            info='Reference power input',
            tex_name='P_{ref}',
            v_str='R * q0',
            e_str='R * q0 - pref',
        )

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

        self.LG = Lag(
            u=self.pd,
            K=1,
            T=self.Tf,
            info='filter after speed deviation (e)',
        )

        self.gtpos = State(info='State in gate position (c)',
                           unit='rad',
                           v_str='q0',
                           tex_name=r'\delta',
                           e_str='LG_y')

        self.dgl = VarService(
            tex_name='dg_{lower}',
            info='dg lower limit',
            v_str='- VELM - gr * LG_y',
        )
        self.dgu = VarService(
            tex_name='dg_{upper}',
            info='dg upper limit',
            v_str='VELM - gr * LG_y',
        )
        self.dg_lim = AntiWindupRate(
            u=self.gtpos,
            lower=self.GMIN,
            upper=self.GMAX,
            rate_lower=self.dgl,
            rate_upper=self.dgu,
            tex_name='lim_{dg}',
            info='gate velocity and position limiter',
        )

        self.dg = Algeb(
            info='desired gate (c)',
            unit='p.u.',
            tex_name="dg",
            v_str='q0',
            e_str='gtpos + gr * LG_y - dg',
        )

        self.LAG = Lag(
            u=self.dg,
            K=1,
            T=self.Tg,
            info='gate opening (g)',
        )
        self.h = Algeb(
            info='turbine head',
            unit='p.u.',
            tex_name="h",
            e_str='q_y**2 / LAG_y**2 - h',
            v_str='1',
        )
        self.q = Integrator(u="1 - q_y**2 / LAG_y**2",
                            T=self.Tw,
                            K=1,
                            y0='q0',
                            check_init=False,
                            info="turbine flow (q)")

        self.pout.e_str = 'ue * (At * h * (q_y - qNL) - Dt * wd * LAG_y) - pout'
Beispiel #16
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 * (tm - te - D * (omega - 1))',
            t_const=self.M,
        )

        # 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)',
            ename='P',
            tex_ename='P',
            is_input=True,
        )
        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)',
            ename='Q',
            tex_ename='Q',
            is_input=True,
        )

        # 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',
            vtype=str,
        )

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

        self.Pe = Algeb(tex_name='P_e',
                        info='active power injection',
                        e_str='u * (vd * Id + vq * Iq) - Pe',
                        v_str='u * (vd0 * Id0 + vq0 * Iq0)')
        self.Qe = Algeb(tex_name='Q_e',
                        info='reactive power injection',
                        e_str='u * (vq * Id - vd * Iq) - Qe',
                        v_str='u * (vq0 * Id0 - vd0 * Iq0)')