예제 #1
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        # Notes:
        # TimeSeries model is not used in power flow for now

        self.flags.tds = True

        self.config.add(OrderedDict((('silent', 1), )))

        self.config.add_extra(
            "_help",
            silent="suppress output messages if is not zero",
        )
        self.config.add_extra(
            "_alt",
            silent=(0, 1),
        )

        self.SW = Switcher(
            self.mode,
            options=(0, 1, 2),
            info='mode switcher',
        )

        self._data = OrderedDict(
        )  # keys are the idx, and values are the dataframe
예제 #2
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'
예제 #3
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.flags.tds = True
        self.group = 'TimedEvent'

        self.SW = Switcher(
            u=self.method,
            options=('+', '-', '*', '/', '='),
            info='Switcher for alteration method',
        )

        self.t.callback = self._alter_field
예제 #4
0
    def test_switcher(self):
        p = NumParam()
        p.v = np.array([0, 1, 2, 2, 1, 3, 1])
        switcher = Switcher(u=p, options=[0, 1, 2, 3, 4])
        switcher.list2array(len(p.v))

        switcher.check_var()

        self.assertSequenceEqual(switcher.s0.tolist(), [1, 0, 0, 0, 0, 0, 0])
        self.assertSequenceEqual(switcher.s1.tolist(), [0, 1, 0, 0, 1, 0, 1])
        self.assertSequenceEqual(switcher.s2.tolist(), [0, 0, 1, 1, 0, 0, 0])
        self.assertSequenceEqual(switcher.s3.tolist(), [0, 0, 0, 0, 0, 1, 0])
        self.assertSequenceEqual(switcher.s4.tolist(), [0, 0, 0, 0, 0, 0, 0])
예제 #5
0
파일: pvd1.py 프로젝트: treymingee/andes
    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',
                         )
예제 #6
0
파일: vsc.py 프로젝트: willjschmitt/andes
    def __init__(self, system, config):
        ACDC2Term.__init__(self, system, config)
        self.rsh = NumParam(default=0.0025,
                            info="AC interface resistance",
                            unit="ohm",
                            z=True,
                            tex_name='r_{sh}')
        self.xsh = NumParam(default=0.06,
                            info="AC interface reactance",
                            unit="ohm",
                            z=True,
                            tex_name='x_{sh}')

        self.control = NumParam(
            info="Control method: 0-PQ, 1-PV, 2-vQ or 3-vV", mandatory=True)
        self.v0 = NumParam(
            default=1.0,
            info="AC voltage setting (PV or vV) or initial guess (PQ or vQ)")
        self.p0 = NumParam(default=0.0,
                           info="AC active power setting",
                           unit="pu")
        self.q0 = NumParam(default=0.0,
                           info="AC reactive power setting",
                           unit="pu")
        self.vdc0 = NumParam(default=1.0,
                             info="DC voltage setting",
                             unit="pu",
                             tex_name='v_{dc0}')

        self.k0 = NumParam(default=0.0, info="Loss coefficient - constant")
        self.k1 = NumParam(default=0.0, info="Loss coefficient - linear")
        self.k2 = NumParam(default=0.0, info="Loss coefficient - quadratic")

        self.droop = NumParam(default=0.0,
                              info="Enable dc voltage droop control",
                              unit="boolean")
        self.K = NumParam(default=0.0, info="Droop coefficient")
        self.vhigh = NumParam(default=9999,
                              info="Upper voltage threshold in droop control",
                              unit="pu")
        self.vlow = NumParam(default=0.0,
                             info="Lower voltage threshold in droop control",
                             unit="pu")

        self.vshmax = NumParam(default=1.1,
                               info="Maximum ac interface voltage",
                               unit="pu")
        self.vshmin = NumParam(default=0.9,
                               info="Minimum ac interface voltage",
                               unit="pu")
        self.Ishmax = NumParam(default=2, info="Maximum ac current", unit="pu")

        # define variables and equations
        self.flags.update({'pflow': True})
        self.group = 'StaticACDC'

        self.gsh = ConstService(tex_name='g_{sh}',
                                v_str='re(1/(rsh + 1j * xsh))',
                                vtype=np.complex)
        self.bsh = ConstService(tex_name='b_{sh}',
                                v_str='im(1/(rsh + 1j * xsh))',
                                vtype=np.complex)

        self.mode = Switcher(u=self.control, options=(0, 1, 2, 3))

        self.ash = Algeb(
            info='voltage phase behind the transformer',
            unit='rad',
            tex_name=r'\theta_{sh}',
            v_str='a',
            e_str='u * (gsh * v**2 - gsh * v * vsh * cos(a - ash) - '
            'bsh * v * vsh * sin(a - ash)) - psh',
            diag_eps=True,
        )
        self.vsh = Algeb(
            info='voltage magnitude behind transformer',
            tex_name="V_{sh}",
            unit='p.u.',
            v_str='v0',
            e_str='u * (-bsh * v**2 - gsh * v * vsh * sin(a - ash) + '
            'bsh * v * vsh * cos(a - ash)) - qsh',
            diag_eps=True,
        )
        self.psh = Algeb(
            info='active power injection into VSC',
            tex_name="P_{sh}",
            unit='p.u.',
            v_str='p0 * (mode_s0 + mode_s1)',
            e_str='u * (mode_s0 + mode_s1) * (p0 - psh) + '
            'u * (mode_s2 + mode_s3) * (v1 - v2 - vdc0)',
            diag_eps=True,
        )
        self.qsh = Algeb(
            info='reactive power injection into VSC',
            tex_name="Q_{sh}",
            v_str='q0 * (mode_s0 + mode_s2)',
            e_str='u * (mode_s0 + mode_s2) * (q0 - qsh) + '
            'u * (mode_s1 + mode_s3) * (v0 - v)',
            diag_eps=True,
        )
        self.pdc = Algeb(
            info='DC power injection',
            tex_name="P_{dc}",
            v_str='0',
            e_str='u * (gsh * vsh * vsh - gsh * v * vsh * cos(a - ash) + '
            'bsh * v * vsh * sin(a - ash)) + pdc',
        )
        self.a.e_str = '-psh'
        self.v.e_str = '-qsh'
        self.v1.e_str = '-pdc / (v1 - v2)'
        self.v2.e_str = 'pdc / (v1 - v2)'
예제 #7
0
    def __init__(self, system, config):
        PSSBase.__init__(self, system, config)

        # ALL THE FOLLOWING IS FOR INPUT 2
        # retrieve indices of bus and bus freq
        self.buss2 = DataSelect(self.busr2,
                                self.bus,
                                info='selected bus (bus or busr)')

        self.busfreq2 = DeviceFinder(self.busf2,
                                     link=self.buss2,
                                     idx_name='bus')

        # from Bus
        self.v2 = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.buss2,
            tex_name=r'V',
            info='Bus (or busr2, if given) terminal voltage',
        )

        # from BusFreq 2
        self.f2 = ExtAlgeb(model='FreqMeasurement',
                           src='f',
                           indexer=self.busfreq2,
                           export=False,
                           info='Bus frequency 2')

        # Config
        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.busf.model = self.config.freq_model
        self.busf2.model = self.config.freq_model

        # input signal switch
        self.dv = Derivative(self.v)
        self.dv2 = Derivative(self.v2)

        self.SnSb = ExtService(
            model='SynGen',
            src='M',
            indexer=self.syn,
            attr='pu_coeff',
            info='Machine base to sys base factor for power',
            tex_name='(Sb/Sn)')

        self.SW = Switcher(
            u=self.MODE,
            options=[0, 1, 2, 3, 4, 5, 6, np.nan],
        )
        self.SW2 = Switcher(
            u=self.MODE2,
            options=[0, 1, 2, 3, 4, 5, 6, np.nan],
        )

        # Input signals
        self.sig = Algeb(
            tex_name='S_{ig}',
            info='Input signal',
        )
        self.sig.v_str = 'SW_s1*(omega-1) + SW_s2*0 + SW_s3*(tm0/SnSb) + ' \
                         'SW_s4*(tm-tm0) + SW_s5*v + SW_s6*0'
        self.sig.e_str = 'SW_s1*(omega-1) + SW_s2*(f-1) + SW_s3*(te/SnSb) + ' \
                         'SW_s4*(tm-tm0) + SW_s5*v + SW_s6*dv_v - sig'

        self.sig2 = Algeb(
            tex_name='S_{ig2}',
            info='Input signal 2',
        )
        self.sig2.v_str = 'SW2_s1*(omega-1) + SW2_s2*0 + SW2_s3*(tm0/SnSb) + ' \
                          'SW2_s4*(tm-tm0) + SW2_s5*v2 + SW2_s6*0'
        self.sig2.e_str = 'SW2_s1*(omega-1) + SW2_s2*(f2-1) + SW2_s3*(te/SnSb) + ' \
                          'SW2_s4*(tm-tm0) + SW2_s5*v2 + SW2_s6*dv2_v - sig2'

        self.L1 = Lag(
            u=self.sig,
            K=self.K1,
            T=self.T1,
            info='Transducer 1',
        )
        self.L2 = Lag(
            u=self.sig2,
            K=self.K2,
            T=self.T2,
            info='Transducer 2',
        )
        self.IN = Algeb(
            tex_name='I_N',
            info='Sum of inputs',
            v_str='L1_y + L2_y',
            e_str='L1_y + L2_y - IN',
        )

        self.WO = WashoutOrLag(
            u=self.IN,
            K=self.T3,
            T=self.T4,
        )

        self.LL1 = LeadLag(
            u=self.WO_y,
            T1=self.T5,
            T2=self.T6,
            zero_out=True,
        )

        self.LL2 = LeadLag(
            u=self.LL1_y,
            T1=self.T7,
            T2=self.T8,
            zero_out=True,
        )

        self.LL3 = LeadLag(
            u=self.LL2_y,
            T1=self.T9,
            T2=self.T10,
            zero_out=True,
        )

        self.VSS = GainLimiter(u=self.LL3_y,
                               K=1,
                               lower=self.LSMIN,
                               upper=self.LSMAX)

        self.VOU = ConstService(v_str='VCUr + v0')
        self.VOL = ConstService(v_str='VCLr + v0')

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

        self.vsout.e_str = 'OLIM_zi * VSS_y - vsout'
예제 #8
0
    def __init__(self, system, config):
        PSSBase.__init__(self, system, config)

        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.busf.model = self.config.freq_model

        self.dv = Derivative(self.v)

        self.SnSb = ExtService(
            model='SynGen',
            src='M',
            indexer=self.syn,
            attr='pu_coeff',
            info='Machine base to sys base factor for power',
            tex_name='(Sb/Sn)')

        self.SW = Switcher(
            u=self.MODE,
            options=[1, 2, 3, 4, 5, 6],
        )

        self.sig = Algeb(
            tex_name='S_{ig}',
            info='Input signal',
        )

        self.sig.v_str = 'SW_s0*(omega-1) + SW_s1*0 + SW_s2*(tm0/SnSb) + ' \
                         'SW_s3*(tm-tm0) + SW_s4*v + SW_s5*0'

        self.sig.e_str = 'SW_s0*(omega-1) + SW_s1*(f-1) + SW_s2*(te/SnSb) + ' \
                         'SW_s3*(tm-tm0) + SW_s4*v + SW_s5*dv_v - sig'

        self.F1 = Lag2ndOrd(u=self.sig, 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,
                                zero_out=True)

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

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

        self.Vks = Gain(u=self.LL2_y, K=self.KS)

        self.WO = WashoutOrLag(u=self.Vks_y,
                               T=self.T6,
                               K=self.T5,
                               name='WO',
                               zero_out=True)  # 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.VCLr,
                            upper=self.VCUr,
                            info='output limiter')

        self.vsout.e_str = 'OLIM_zi * Vss - vsout'
예제 #9
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)
        self.flags.nr_iter = True

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.vout.e_str = 'ue * vol_y  - vout'