Exemple #1
0
    def __init__(self, system, config):
        AreaData.__init__(self)
        Model.__init__(self, system, config)
        self.group = 'Collection'
        self.flags.pflow = True
        self.flags.tds = True

        self.Bus = BackRef()
        self.ACTopology = BackRef()

        # --------------------Experiment Zone--------------------
        self.Vn = ExtParam(model='Bus',
                           src='Vn',
                           indexer=self.ACTopology,
                           export=False)
        self.Vn_sum = NumReduce(u=self.Vn, fun=np.sum, ref=self.Bus)
        self.Vn_sum_rep = NumRepeat(u=self.Vn_sum, ref=self.Bus)

        self.a = ExtAlgeb(model='ACTopology',
                          src='a',
                          indexer=self.ACTopology,
                          info='Bus voltage angle')
        self.v = ExtAlgeb(model='ACTopology',
                          src='v',
                          indexer=self.ACTopology,
                          info='Bus voltage magnitude')
Exemple #2
0
    def __init__(self, system, config):
        REECA1Model.__init__(self, system, config)
        self.busrocof = DeviceFinder(
            self.busroc,
            link=self.bus,
            idx_name='bus',
        )

        self.df = ExtAlgeb(
            model='FreqMeasurement',
            src='WO_y',
            indexer=self.busrocof,
            export=False,
            info='Bus frequency deviation',
        )

        self.dfdt = ExtAlgeb(
            model='FreqMeasurement',
            src='Wf_y',
            indexer=self.busrocof,
            export=False,
            info='Bus ROCOF',
            unit='p.u.',
        )

        self.Pref.e_str += '- Kdf * dfdt - Kf * df'
Exemple #3
0
    def __init__(self, system, config):
        AreaData.__init__(self)
        Model.__init__(self, system, config)
        self.group = 'Collection'
        self.flags.update({'pflow': True, 'tds': True})

        self.Bus = RefParam(export=False)
        self.ACTopology = RefParam(export=False)

        # --------------------Experiment Zone--------------------
        self.Vn = ExtParam(model='Bus',
                           src='Vn',
                           indexer=self.ACTopology,
                           export=False)
        self.Vn_sum = ReducerService(u=self.Vn, fun=np.sum, ref=self.Bus)
        self.Vn_sum_rep = RepeaterService(u=self.Vn_sum, ref=self.Bus)

        self.a = ExtAlgeb(model='ACTopology',
                          src='a',
                          indexer=self.ACTopology,
                          info='Bus voltage angle')
        self.v = ExtAlgeb(model='ACTopology',
                          src='v',
                          indexer=self.ACTopology,
                          info='Bus voltage magnitude')
Exemple #4
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)',
        )
Exemple #5
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([])
Exemple #6
0
    def __init__(self, system=None, config=None):
        super().__init__(system, config)
        self.group = 'StaticGen'
        self.flags.update({'pflow': True, 'collate': True})

        self.config.add(OrderedDict((('pv2pq', 0), ('npv2pq', 1))))
        self.config.add_extra(
            "_help",
            pv2pq="convert PV to PQ in PFlow at Q limits",
            npv2pq="max. # of pv2pq conversion in each iteration",
        )
        self.config.add_extra("_alt", pv2pq=(0, 1), npv2pq=">=0")
        self.config.add_extra(
            "_tex",
            pv2pq="z_{pv2pq}",
        )

        self.a = ExtAlgeb(model='Bus',
                          src='a',
                          indexer=self.bus,
                          tex_name=r'\theta')
        self.v = ExtAlgeb(model='Bus',
                          src='v',
                          indexer=self.bus,
                          v_setter=True,
                          tex_name=r'V')

        self.p = Algeb(info='actual active power generation',
                       unit='p.u.',
                       tex_name=r'p',
                       diag_eps=1e-6)
        self.q = Algeb(info='actual reactive power generation',
                       unit='p.u.',
                       tex_name='q',
                       diag_eps=1e-6)

        # TODO: implement switching starting from the second iteration
        self.qlim = SortedLimiter(u=self.q,
                                  lower=self.qmin,
                                  upper=self.qmax,
                                  enable=self.config.pv2pq,
                                  n_select=self.config.npv2pq)

        # variable initialization equations
        self.v.v_str = 'v0'
        self.p.v_str = 'p0'
        self.q.v_str = 'q0'

        # injections into buses have negative values
        self.a.e_str = "-u * p"
        self.v.e_str = "-u * q"

        # power injection equations g(y) = 0
        self.p.e_str = "u * (p0 - p)"
        self.q.e_str = "u*(qlim_zi * (v0-v) + "\
                       "qlim_zl * (qmin-q) + "\
                       "qlim_zu * (qmax-q))"
Exemple #7
0
    def __init__(self, system=None, config=None):
        ShuntData.__init__(self)
        Model.__init__(self, system, config)
        self.group = 'StaticShunt'
        self.flags['pflow'] = True

        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.a.e_str = 'u * v**2 * g'
        self.v.e_str = '-u * v**2 * b'
Exemple #8
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) + \
Exemple #9
0
    def __init__(self, system, config):
        ModelData.__init__(self)
        self.node1 = IdxParam(
            default=None,
            tex_name='node_1',
            info='Node 1 index',
            mandatory=True,
            model='Node',
        )
        self.node2 = IdxParam(
            default=None,
            tex_name='node_2',
            info='Node 2 index',
            mandatory=True,
            model='Node',
        )
        self.Vdcn1 = NumParam(
            default=100,
            info='DC voltage rating on node 1',
            unit='kV',
            non_zero=True,
            tex_name='V_{dcn1}',
        )
        self.Vdcn2 = NumParam(
            default=100,
            info='DC voltage rating on node 2',
            unit='kV',
            non_zero=True,
            tex_name='V_{dcn2}',
        )
        self.Idcn = NumParam(
            default=1,
            info='DC current rating',
            unit='kA',
            non_zero=True,
            tex_name='I_{dcn}',
        )

        Model.__init__(self, system, config)
        self.v1 = ExtAlgeb(
            model='Node',
            src='v',
            indexer=self.node1,
            info='DC voltage on node 1',
        )
        self.v2 = ExtAlgeb(
            model='Node',
            src='v',
            indexer=self.node2,
            info='DC voltage on node 2',
        )
Exemple #10
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',
                       )
Exemple #11
0
 def __init__(self, system, config):
     ModelData.__init__(self)
     self.node = IdxParam(
         default=None,
         tex_name='node',
         info='Node index',
         mandatory=True,
         model='Node',
     )
     self.voltage = NumParam(
         default=0.0,
         tex_name='V_0',
         info='Ground voltage (typically 0)',
         unit='p.u.',
     )
     Model.__init__(self, system, config)
     self.flags.update({'pflow': True})
     self.group = 'DCLink'
     self.v = ExtAlgeb(
         model='Node',
         src='v',
         indexer=self.node,
         e_str='-Idc',
     )
     self.Idc = Algeb(
         tex_name='I_{dc}',
         info='Ficticious current injection from ground',
         e_str='u * (v - voltage)',
         v_str='0',
         diag_eps=1e-6,
     )
     self.v.e_str = '-Idc'
Exemple #12
0
    def __init__(self, system, config):
        ACEData.__init__(self)
        Model.__init__(self, system, config)

        self.flags.tds = True

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

        self.f = ExtAlgeb(
            model='FreqMeasurement',
            src='f',
            indexer=self.busfreq,
            export=False,
            info='Bus frequency',
        )

        self.ace = Algeb(
            info='area control error',
            unit='MW (p.u.)',
            tex_name='ace',
            e_str='10 * bias * (f - 1) - ace',
        )
Exemple #13
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.flags.pflow = True
        self.flags.tds = True
        self.group = 'ACShort'

        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.p = Algeb(
            info='active power (1 to 2)',
            e_str='u * (a1 - a2)',
            tex_name='P',
            diag_eps=True,
        )

        self.q = Algeb(
            info='active power (1 to 2)',
            e_str='u * (v1 - v2)',
            tex_name='Q',
            diag_eps=True,
        )

        self.a1.e_str = 'p'
        self.a2.e_str = '-p'

        self.v1.e_str = 'q'
        self.v2.e_str = '-q'
Exemple #14
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',
        )
Exemple #15
0
 def __init__(self, system, config):
     DGPRCTBaseModel.__init__(self, system, config)
     self.v = ExtAlgeb(model='Bus', src='v',
                       indexer=self.bus,
                       export=False,
                       info='Bus voltage',
                       unit='p.u.',
                       )
     fProtect.__init__(self)
     VProtect.__init__(self)
Exemple #16
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)

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

        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            tex_name=r'\theta',
            info='Bus voltage angle',
            e_str='-p0',
            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='-q0',
            ename='P',
            tex_ename='P',
        )

        self.p0 = ExtService(
            model='StaticGen',
            src='p',
            indexer=self.gen,
            tex_name='P_0',
        )
        self.q0 = ExtService(
            model='StaticGen',
            src='q',
            indexer=self.gen,
            tex_name='Q_0',
        )
Exemple #17
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'),
                ('interval', 4.0),
                ('offset', 0.0),
            ]))
        self.config.add_extra(
            '_help', {
                'freq_model': 'default freq. measurement model',
                'interval': 'sampling time interval',
                'offset': 'sampling time offset'
            })

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

        self.f = ExtAlgeb(
            model='FreqMeasurement',
            src='f',
            indexer=self.busfreq,
            export=False,
            info='Bus frequency',
        )

        self.fs = Sampling(
            self.f,
            interval=self.config.interval,
            offset=self.config.offset,
            tex_name='f_s',
            info='Sampled freq.',
        )

        self.ace = Algeb(
            info='area control error',
            unit='MW (p.u.)',
            tex_name='ace',
            e_str='10 * bias * (fs_v - 1) - ace',
        )
Exemple #18
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',
        )
Exemple #19
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',
        )
Exemple #20
0
    def __init__(self, system, config):
        super().__init__(system, config)

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

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

        self.af = Lag(
            u=self.a,
            T=self.Tf,
            K=1,
            D=1,
            info='input angle signal filter',
        )

        self.PI = PIController(
            u='u * (af_y - am)',
            kp=self.Kp,
            ki=self.Ki,
            tex_name='PI',
            info='PI controller',
        )

        self.ae = State(info='PLL angle output before filter',
                        e_str='2 * pi *fn * PI_y',
                        v_str='a',
                        tex_name=r'\theta_{est}')

        self.am = State(info='PLL output angle after filtering',
                        e_str='ae - am',
                        t_const=self.Tp,
                        v_str='a',
                        tex_name=r'\theta_{PLL}')
Exemple #21
0
    def __init__(self, system, config):
        ExcBase.__init__(self, system, config)

        self.KPC = ConstService(v_str='KP * exp(1j * radians(THETAP))',
                                tex_name='K_{PC}',
                                info='KP polar THETAP',
                                vtype=np.complex)

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

        self.Iq = ExtAlgeb(
            src='Iq',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'I_q',
            info='q-axis machine current',
        )

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

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

        self.VE = VarService(
            tex_name='V_E',
            info='VE',
            v_str='Abs(KPC*(vd + 1j*vq) + 1j*(KI + KPC*XL)*(Id + 1j*Iq))',
        )

        self.IN = Algeb(
            tex_name='I_N',
            info='Input to FEX',
            v_str='KC * XadIfd / VE',
            e_str='KC * XadIfd / VE - IN',
        )

        self.FEX = Piecewise(
            u=self.IN,
            points=(0, 0.433, 0.75, 1),
            funs=('1', '1 - 0.577*IN', 'sqrt(0.75 - IN ** 2)',
                  '1.732*(1 - IN)', 0),
            info='Piecewise function FEX',
        )

        self.VBMIN = dummify(-9999)
        self.VGMIN = dummify(-9999)

        self.VB = GainLimiter(
            u='VE*FEX_y',
            K=1,
            upper=self.VBMAX,
            lower=self.VBMIN,
            no_lower=True,
            info='VB with limiter',
        )

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

        self.vrs = Algeb(
            tex_name='V_{RS}',
            info='VR subtract feedback VG',
            v_str='vf0 / VB_y / KM',
            e_str='LAW1_y - VG_y - vrs',
        )

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

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

        # input excitation voltages; PSS outputs summed at vi
        self.vi = Algeb(
            info='Total input voltages',
            tex_name='V_i',
            unit='p.u.',
            e_str='-LG_y + vref - vi',
            v_str='-v + vref',
        )

        self.vil = Algeb(info='Input voltage after limit',
                         tex_name='V_{il}',
                         v_str='HLI_zi*vi + HLI_zl*VIMIN + HLI_zu*VIMAX',
                         e_str='HLI_zi*vi + HLI_zl*VIMIN + HLI_zu*VIMAX - vil')

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

        self.LL = LeadLag(
            u=self.HG_y,
            T1=self.TC,
            T2=self.TB,
            info='Regulator',
            zero_out=True,
        )  # LL_y == VA

        self.LAW1 = LagAntiWindup(
            u=self.LL_y,
            T=self.TA,
            K=self.KA,
            lower=self.VRMIN,
            upper=self.VRMAX,
            info='Lag AW on VR',
        )  # LAW1_y == VR

        self.HLI = HardLimiter(
            u=self.vi,
            lower=self.VIMIN,
            upper=self.VIMAX,
            info='Input limiter',
        )

        self.LAW2 = LagAntiWindup(
            u=self.vrs,
            T=self.TM,
            K=self.KM,
            lower=self.VMMIN,
            upper=self.VMMAX,
            info='Lag AW on VM',
        )  # LAW2_y == VM

        self.vout.e_str = 'VB_y * LAW2_y - vout'
Exemple #22
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',
                         )
Exemple #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([])
Exemple #24
0
    def __init__(self, system, config):
        super().__init__(system, config)
        self.group = 'PSS'
        self.flags.update({'tds': True})

        self.VCUr = Replace(self.VCU, lambda x: np.equal(x, 0.0), 999)
        self.VCLr = Replace(self.VCL, lambda x: np.equal(x, 0.0), -999)

        # retrieve indices of connected generator, bus, and bus freq
        self.syn = ExtParam(model='Exciter',
                            src='syn',
                            indexer=self.avr,
                            export=False,
                            info='Retrieved generator idx',
                            dtype=str)

        self.bus = ExtParam(
            model='SynGen',
            src='bus',
            indexer=self.syn,
            export=False,
            info='Retrieved bus idx',
            dtype=str,
            default=None,
        )

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

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

        # from SynGen
        self.Sn = ExtParam(model='SynGen',
                           src='Sn',
                           indexer=self.syn,
                           tex_name='S_n',
                           info='Generator power base',
                           export=False)

        self.omega = ExtState(
            model='SynGen',
            src='omega',
            indexer=self.syn,
            tex_name=r'\omega',
            info='Generator speed',
            unit='p.u.',
        )

        self.tm0 = ExtService(
            model='SynGen',
            src='tm',
            indexer=self.syn,
            tex_name=r'\tau_{m0}',
            info='Initial mechanical input',
        )
        self.tm = ExtAlgeb(
            model='SynGen',
            src='tm',
            indexer=self.syn,
            tex_name=r'\tau_m',
            info='Generator mechanical input',
        )
        self.te = ExtAlgeb(
            model='SynGen',
            src='te',
            indexer=self.syn,
            tex_name=r'\tau_e',
            info='Generator electrical output',
        )
        # from Bus
        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.buss,
            tex_name=r'V',
            info='Bus (or busr, if given) terminal voltage',
        )
        self.v0 = ExtService(
            model='Bus',
            src='v',
            indexer=self.buss,
            tex_name="V_0",
            info='Initial bus voltage',
        )

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

        # from Exciter
        self.vi = ExtAlgeb(model='Exciter',
                           src='vi',
                           indexer=self.avr,
                           tex_name='v_i',
                           info='Exciter input voltage',
                           e_str='u * vsout')

        self.vsout = Algeb(
            info='PSS output voltage to exciter',
            tex_name='v_{sout}',
        )  # `self.vsout.e_str` to be provided by specific models
Exemple #25
0
    def __init__(self, system, config):
        ModelData.__init__(self)
        self.bus = IdxParam(
            model='Bus',
            info="idx of connected bus",
            mandatory=True,
        )
        self.node1 = IdxParam(
            default=None,
            tex_name='node_1',
            info='Node 1 index',
            mandatory=True,
            model='Node',
        )
        self.node2 = IdxParam(
            default=None,
            tex_name='node_2',
            info='Node 2 index',
            mandatory=True,
            model='Node',
        )
        self.Vn = NumParam(
            default=110.0,
            info="AC voltage rating",
            non_zero=True,
            tex_name=r'V_n',
        )
        self.Vdcn1 = NumParam(
            default=100,
            info='DC voltage rating on node 1',
            unit='kV',
            non_zero=True,
            tex_name='V_{dcn1}',
        )
        self.Vdcn2 = NumParam(
            default=100,
            info='DC voltage rating on node 2',
            unit='kV',
            non_zero=True,
            tex_name='V_{dcn2}',
        )
        self.Idcn = NumParam(
            default=1,
            info='DC current rating',
            unit='kA',
            non_zero=True,
            tex_name='I_{dcn}',
        )

        Model.__init__(self, system, config)
        self.a = ExtAlgeb(
            model='Bus',
            src='a',
            indexer=self.bus,
            info='AC bus voltage phase',
        )
        self.v = ExtAlgeb(
            model='Bus',
            src='v',
            indexer=self.bus,
            info='AC bus voltage magnitude',
        )
        self.v1 = ExtAlgeb(
            model='Node',
            src='v',
            indexer=self.node1,
            info='DC node 1 voltage',
        )
        self.v2 = ExtAlgeb(
            model='Node',
            src='v',
            indexer=self.node2,
            info='DC node 2 voltage',
        )
Exemple #26
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'
Exemple #27
0
    def __init__(self, system, config):
        Model.__init__(self, system, config)
        self.group = 'Exciter'
        self.flags.tds = True

        # from synchronous generators, get Sn, Vn, bus; tm0; omega
        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.vf0 = ExtService(src='vf',
                              model='SynGen',
                              indexer=self.syn,
                              tex_name='v_{f0}',
                              info='Steady state excitation voltage')
        self.bus = ExtParam(
            src='bus',
            model='SynGen',
            indexer=self.syn,
            tex_name='bus',
            info='Bus idx of the generators',
            export=False,
            vtype=str,
        )
        self.omega = ExtState(
            src='omega',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'\omega',
            info='Generator speed',
        )
        self.vf = ExtAlgeb(
            src='vf',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'v_f',
            e_str='u * (vout - vf0)',
            info='Excitation field voltage to generator',
        )
        self.XadIfd = ExtAlgeb(
            src='XadIfd',
            model='SynGen',
            indexer=self.syn,
            tex_name=r'X_{ad}I_{fd}',
            info='Armature excitation current',
        )
        # from bus, get a and v
        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',
        )

        # output excitation voltage
        self.vout = Algeb(
            info='Exciter final output voltage',
            tex_name='v_{out}',
            v_str='vf0',
        )
Exemple #28
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',
        )
Exemple #29
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')
Exemple #30
0
    def __init__(self, system, config):
        super().__init__(system, config)
        self.group = 'SynGen'
        self.flags.update({
            'tds': True,
            'nr_iter': False,
        })

        # 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='Id0',
                        tex_name=r'I_d',
                        e_str='')  # to be completed by subclasses
        self.Iq = Algeb(info='q-axis current',
                        v_str='Iq0',
                        tex_name=r'I_q',
                        e_str='')  # to be completed

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

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

        self.subidx = ExtParam(
            model='StaticGen',
            src='subidx',
            indexer=self.gen,
            tex_name='idx_{sub}',
            export=False,
        )
        # ----------service consts for initialization----------
        self.p0 = ExtService(
            model='StaticGen',
            src='p',
            indexer=self.gen,
            tex_name='P_0',
        )
        self.q0 = ExtService(
            model='StaticGen',
            src='q',
            indexer=self.gen,
            tex_name='Q_0',
        )