def __init__(self, system=None, config=None): BusData.__init__(self) Model.__init__(self, system=system, config=config) self.config.add(OrderedDict((('flat_start', 0.0), ))) self.group = 'ACTopology' self.category = ['TransNode'] self.flags.update({'collate': False, 'pflow': True}) self.a = Algeb(name='a', tex_name=r'\theta', info='voltage angle', unit='rad', ) self.v = Algeb(name='v', tex_name='V', info='voltage magnitude', unit='p.u.', ) # initial values self.a.v_str = 'flat_start * 1e-8 + ' \ '(1 - flat_start) * a0' self.v.v_str = 'flat_start * 1 + ' \ '(1 - flat_start) * v0'
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')
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'
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
def __init__(self, system, config): TogglerData.__init__(self) Model.__init__(self, system, config) self.flags.update({'tds': True}) self.group = 'TimedEvent' self.t.callback = self._u_switch
def __init__(self, system, config): NodeData.__init__(self) Model.__init__(self, system=system, config=config) self.config.add(OrderedDict((('flat_start', 0), ))) self.config.add_extra( "_help", flat_start="flat start for voltages", ) self.config.add_extra( "_alt", flat_start=(0, 1), ) self.config.add_extra( "_tex", flat_start="z_{flat}", ) self.group = 'DCTopology' self.category = ['TransNode'] self.flags.update({'pflow': True}) self.v = Algeb( name='v', tex_name='V_{dc}', info='voltage magnitude', unit='p.u.', diag_eps=1e-6, ) self.v.v_str = 'flat_start*1 + ' \ '(1-flat_start)*v0'
def __init__(self, system, config): OutputData.__init__(self) Model.__init__(self, system, config) self.group = 'OutputSelect' self.xidx = [] self.yidx = []
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', )
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')
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', )
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([])
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)', )
def __init__(self, system, config): ToggleData.__init__(self) Model.__init__(self, system, config) self.flags.update({'tds': True}) self.group = 'TimedEvent' self.t.callback = self._u_switch self._init = False # very first initialization that stores `u` self._u = ConstService('1')
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()
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'
def __init__(self, system, config): ModelData.__init__(self, three_params=False) self.field = DataParam(info='field name') self.comment = DataParam(info='information, comment, or anything') self.comment2 = DataParam(info='comment field 2') self.comment3 = DataParam(info='comment field 3') self.comment4 = DataParam(info='comment field 4') Model.__init__(self, system, config) self.group = 'Information'
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
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) + \
def __init__(self, system=None, config=None): BusData.__init__(self) Model.__init__(self, system=system, config=config) # island information self.n_islanded_buses = 0 self.island_sets = list() self.islanded_buses = list( ) # list of lists containing bus uid of islands self.islands = list() # same as the above self.islanded_a = np.array([]) self.islanded_v = np.array([]) # config self.config.add(OrderedDict((('flat_start', 0), ))) self.config.add_extra( "_help", flat_start="flat start for voltages", ) self.config.add_extra( "_alt", flat_start=(0, 1), ) self.config.add_extra( "_tex", flat_start="z_{flat}", ) self.group = 'ACTopology' self.category = ['TransNode'] self.flags.update({'collate': False, 'pflow': True}) self.a = Algeb( name='a', tex_name=r'\theta', info='voltage angle', unit='rad', is_output=True, ) self.v = Algeb( name='v', tex_name='V', info='voltage magnitude', unit='p.u.', is_output=True, ) # initial values self.a.v_str = 'flat_start*1e-8 + ' \ '(1-flat_start)*a0' self.v.v_str = 'flat_start*1 + ' \ '(1-flat_start)*v0'
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', )
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', )
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', )
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'
def __init__(self, system, config): Model.__init__(self, system, config) self.group = 'Experimental' self.flags.update({'tds': True}) self.uin = State( v_str=0, e_str= 'Piecewise((0, dae_t<= 0), (1, dae_t <= 2), (-1, dae_t <6), (1, True))', ) self.x = State( e_str='uin * Ki * HL_zi', v_str=0.05, ) self.y = Algeb(e_str='uin * Kp + x - y', v_str=0.05) self.HL = HardLimiter(u=self.y, lower=self.Wmin, upper=self.Wmax) self.w = Algeb(e_str='HL_zi * y + HL_zl * Wmin + HL_zu * Wmax - w', v_str=0.05)
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', )
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', )
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', )
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', )
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', )
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([])