Example #1
0
    def steady_state_model(self, t):
        """Grid voltage change."""

        Vagrid_new, wgrid_new = self.events.grid_events(t)
        Vagrid_new = Vagrid_new * (self.Vgridrated / self.Vbase)

        if abs(self.Vagrid -
               Vagrid_new) > 0.0 and t >= self._t_voltage_previous:
            utility_functions.print_to_terminal(
                "{}:Grid voltage changed from {:.3f} V to {:.3f} V at {:.3f} s"
                .format(self.name, self.Vagrid, Vagrid_new, t))

            self.Vagrid = Vagrid_new
            self.Vbgrid = utility_functions.Ub_calc(self.Vagrid *
                                                    self.unbalance_ratio_b)
            self.Vcgrid = utility_functions.Uc_calc(self.Vagrid *
                                                    self.unbalance_ratio_c)

            self._t_voltage_previous = t

        if abs(self.wgrid -
               wgrid_new) > 0.0 and t >= self._t_frequency_previous:
            utility_functions.print_to_terminal(
                "{}:Grid frequency changed from {:.3f} Hz to {:.3f} Hz at {:.3f} s"
                .format(self.name, self.wgrid / (2.0 * math.pi),
                        wgrid_new / (2.0 * math.pi), t))

            self.wgrid = wgrid_new
            self._t_frequency_previous = t

        self.vag = self.Vagrid
        self.vbg = self.Vbgrid
        self.vcg = self.Vcgrid
    def print_event(self,text_string,print_inline):
        """Print information about ride through events."""
        
        if text_string != '':
            if print_inline:  #Print in notebook window
                logging.info(text_string)

            else: #Print in console window
                utility_functions.print_to_terminal(text_string)
        else:
            pass
    def update_Zload1(self, t):
        """Update load impedance at PCC-LV side."""

        if self.standAlone:  #Update load at PCC LV side only in stand alone mode
            Zload1_actual_new = self.events.load_events(t)
            Zload1_new = Zload1_actual_new / BaseValues.Zbase

            if abs(self.Zload1 - Zload1_new) > 0.0:
                self.Zload1 = Zload1_new
                utility_functions.print_to_terminal(
                    "Load at PCC LV side changed from {:.3f} VA to {:.3f} VA at {:.3f}"
                    .format(self.S_load1, self.S_load1_calc(), t))
    def update_Ppv(self, t):
        """Update PV module power output based on solar events and DC link voltage."""

        Sinsol_new, Tactual_new = self.events.solar_events(t)
        if abs(self.Sinsol - Sinsol_new
               ) or abs(self.Tactual - Tactual_new
                        ) > 0.0:  #Update Iph only if solar insolation changes

            self.Sinsol = Sinsol_new
            self.Tactual = Tactual_new
            utility_functions.print_to_terminal(
                "{}:PV module current output changed from {:.3f} A to {:.3f} A at {:.3f} s"
                .format(self.name, self.Iph, self.Iph_calc(), t))
            self.Iph = self.Iph_calc()

        self.Ppv = self.Ppv_calc(self.Vdc_actual)
    def Volt_VAR_logic(self, t):
        """ Volt-VAR."""

        #Select RMS voltage source
        Vrms_measured = self.Vrms
        self.Qlimit = self.Qlimit_calc()

        deadband_V = 0.01

        if t > self.Volt_VAR_logic_t:  #Update volt-var logic only if solver time is greater that current time
            self.Volt_VAR_logic_t = t

            if self.VOLT_VAR_ACTIVE:

                if self.Volt_VAR_inject_range(Vrms_measured, deadband_V):
                    Qref = self.Q_Volt_VAR_inject(Vrms_measured)
                elif self.Volt_VAR_absorb_range(Vrms_measured, deadband_V):
                    Qref = self.Q_Volt_VAR_absorb(Vrms_measured)
                else:
                    utility_functions.print_to_terminal(
                        "Volt-VAR control with reference voltage {:.3f} is deactivated at {:.3f} s for {:.3f} V"
                        .format(self.Vrms_ref * self.Vbase, t,
                                Vrms_measured * self.Vbase))
                    Qref = 0.0
                    self.VOLT_VAR_ACTIVE = False
            else:
                if self.Volt_VAR_inject_range(Vrms_measured, deadband_V):
                    Qref = self.Q_Volt_VAR_inject(Vrms_measured)
                    utility_functions.print_to_terminal(
                        "Volt-VAR control (injection) with reference voltage {:.3f} is activated at {:.3f} s for {:.3f} V"
                        .format(self.Vrms_ref * self.Vbase, t,
                                Vrms_measured * self.Vbase))
                    self.VOLT_VAR_ACTIVE = True
                elif self.Volt_VAR_absorb_range(Vrms_measured, deadband_V):
                    Qref = self.Q_Volt_VAR_absorb(Vrms_measured)
                    utility_functions.print_to_terminal(
                        "Volt-VAR control (absorbption) with reference voltage {:.3f} is activated at {:.3f} s for {:.3f} V"
                        .format(self.Vrms_ref * self.Vbase, t,
                                Vrms_measured * self.Vbase))
                    self.VOLT_VAR_ACTIVE = True

                else:  #Don't supply/absorb reactive power outside operating range
                    Qref = 0.0
        else:
            self.Volt_VAR_logic_t = self.Volt_VAR_logic_t
            Qref = self.Q_ref

        return Qref
 def Volt_VAR_logic(self,t):
     """Function for volt_var control."""
     
     assert not (self.VOLT_VAR_ENABLE and self.VOLT_WATT_ENABLE), "Volt-VAR and Volt-Watt cannot be active at the same time"
     
     #Volt-VAR logic
     V1_Volt_VAR = self.Vrms_ref - 0.04*self.Vrms_ref #From IEEE 1547-2018 Catergy B (Table 8 - page 39)
     V2_Volt_VAR = self.Vrms_ref - 0.01*self.Vrms_ref #From IEEE 1547-2018 Catergy B (Table 8 - page 39)
     V3_Volt_VAR = self.Vrms_ref + 0.01*self.Vrms_ref #From IEEE 1547-2018 Catergy B (Table 8 - page 39)
     V4_Volt_VAR = self.Vrms_ref + 0.04*self.Vrms_ref #From IEEE 1547-2018 Catergy B (Table 8 - page 39)       
     
     #Select RMS voltage source
     _Vrms_measured = self.Vrms
     
     _del_V = 0.02
     if self.VOLT_VAR_ENABLE and (_Vrms_measured < V2_Volt_VAR or _Vrms_measured > V3_Volt_VAR) and t>self.t_stable:
         if self.VOLT_VAR_FLAG:
             if (_Vrms_measured > V1_Volt_VAR - _del_V and _Vrms_measured < V4_Volt_VAR + _del_V):
                 
                 Qref = self.Qsetpoint_calc(t)                    
                 
             else:
                 utility_functions.print_to_terminal("Volt-VAR control with reference voltage {:.3f} is deactivated at {:.3f} s for {:.3f} V".format(self.Vrms_ref*self.Vbase,t,_Vrms_measured*self.Vbase))
                 Qref = 0.0
                 self.VOLT_VAR_FLAG = False
         else:
             if ( _Vrms_measured >= V1_Volt_VAR and  _Vrms_measured < V4_Volt_VAR):
                 utility_functions.print_to_terminal("Volt-VAR control with reference voltage {:.3f} is activated at {:.3f} s for {:.3f} V".format(self.Vrms_ref*self.Vbase,t,_Vrms_measured*self.Vbase))
                 self.VOLT_VAR_FLAG = True
                 Qref = self.Qsetpoint_calc(t)
             else:
                 utility_functions.print_to_terminal("Volt-VAR control not activated at {:.3f} s since {:.3f} V is outside range!".format(t,_Vrms_measured*self.Vbase))
                 Qref = 0.0
     else: 
         Qref = 0.0
     
     return Qref
    def FRT(self,t):
        """Frequency ride through and trip logic. """
        
        t_reconnect_limit = 3.0   #Time lag before reconnecting

        #IEEE 1547-2018 standards
        F_LF1 = 57.0  #From IEEE 1557-2018 Category III    
        F_LF2 = 58.8  #From IEEE 1557-2018 Category III    
        t_LF1_limit = 0.16      #Time limit for LF1 zone From IEEE 1557-2018 Category III (Table 19 and figure H10)   
        t_LF2_limit = 299.0      #Time limit for LF2 zone From IEEE 1557-2018 Category III (Table 19 and figure H10)
        
        #Dummy variables to preserve logic
        F_LF3 = 0.0
        t_LF3_limit = 0.0
               
        del_f =0.02
        assert (F_LF1 < F_LF2) and (t_LF1_limit < t_LF2_limit), "Frequency level 2 should be greater than frequency level 1"

        #Use grid frequency as estimated by PLL
        fgrid = self.we/(2.0*math.pi)
        
        if self.LFRT_ENABLE and t >  self.t_stable and not self.LFRT_TRIP:
            
            if self.LFRT_DEBUG:
                text_string = '{time_stamp:.4f} -- fgrid:{f1:.3f} Hz, t_LF1start:{t1:.3f} s, t_LF2start:{t2:.3f} s, t_LF3start:{t3:.3f} s'\
                               .format(time_stamp=t,f1 = fgrid,t1=self.t_LF1start,t2=self.t_LF2start,t3=self.t_LF3start)
                utility_functions.print_to_terminal(text_string)
            
            if self.t_LF1start == 0.0 or self.t_LF2start == 0.0 or self.t_LF3start == 0.0:
            
                if self.t_LF1start == 0.0 and fgrid < F_LF1:
                    self.t_LF1start = t
                    utility_functions.print_LFRT_events(t,fgrid,self.t_LF1start,event_name='LF1_start')
                
                if self.t_LF2start == 0.0 and fgrid < F_LF2:
                    self.t_LF2start = t
                    utility_functions.print_LFRT_events(t,fgrid,self.t_LF2start,event_name='LF2_start')
                
                if self.t_LF3start == 0.0 and fgrid < F_LF3:
                    self.t_LF3start = t
                    utility_functions.print_LFRT_events(t,fgrid,self.t_LF3start,event_name='LF3_start')
                
            if self.t_LF1start > 0.0 or self.t_LF2start > 0.0 or self.t_LF3start > 0.0:
                
                if fgrid >= F_LF1+del_f  or fgrid >= F_LF2+del_f or fgrid >= F_LF3+del_f:
                    if fgrid >= F_LF1+del_f and self.t_LF1start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF1start,event_name='LF1_reset')
                        self.t_LF1start = 0.0
                    if fgrid >= F_LF2+del_f and self.t_LF2start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF2start,event_name='LF2_reset')   
                        self.t_LF2start = 0.0
                    if fgrid >= F_LF3+del_f and self.t_LF3start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF3start,event_name='LF3_reset')   
                        self.t_LF3start = 0.0
                
                if t-self.t_LF1start >= t_LF1_limit and self.t_LF1start > 0.0:   #Trip inverter if any limit breached
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF1start,event_name='inverter_trip_LF1')
                        #six.print_(t-self.t_LF1start)
                        self.LFRT_trip_signals()
                        
                elif t-self.t_LF2start >= t_LF2_limit and self.t_LF2start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF2start,event_name='inverter_trip_LF2')
                        self.LFRT_trip_signals()
                        
                elif t-self.t_LF3start >= t_LF3_limit and self.t_LF3start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF3start,event_name='inverter_trip_LF3')
                        self.LFRT_trip_signals()
                        
                if fgrid < F_LF1 and self.t_LF1start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF1start,event_name='LF1_zone') #,verbose = False
                if fgrid < F_LF2 and self.t_LF2start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF2start,event_name='LF2_zone')
                if fgrid < F_LF3 and self.t_LF3start > 0.0:
                        utility_functions.print_LFRT_events(t,fgrid,self.t_LF3start,event_name='LF3_zone')
                        #six.print_(self.t_LF2start)

        elif self.LFRT_ENABLE and t > self.t_stable and self.LFRT_TRIP:

            if self.t_LF_reconnect > 0.0:
                if fgrid < F_LF3:
                    utility_functions.print_LFRT_events(t,fgrid,self.t_LF_reconnect,event_name='reconnect_reset')
                    self.t_LF_reconnect = 0.0
                elif fgrid >= F_LF3 and t-self.t_LF_reconnect >= t_reconnect_limit:
                    utility_functions.print_LFRT_events(t,fgrid,self.t_LF_reconnect,event_name='inverter_reconnection')
                    self.LFRT_TRIP = False             #Reset trip flag
                    self.LFRT_RECONNECT = True        #Set reconnect flag
                    self.t_LF_reconnect = 0.0    #Reset timer
                elif fgrid >= F_LF3 and t-self.t_LF_reconnect < t_reconnect_limit:
                     utility_functions.print_LFRT_events(t,fgrid,self.t_LF_reconnect,event_name='reconnect_zone')
            elif self.t_LF_reconnect == 0.0:
                if fgrid >= F_LF3:
                    self.t_LF_reconnect = t
                    utility_functions.print_LFRT_events(t,fgrid,self.t_LF_reconnect,event_name='reconnect_start')
                else:
                    utility_functions.print_LFRT_events(t,fgrid,event_name='inverter_tripped')

        else:
            self.t_LF1start = 0.0
            self.t_LF2start = 0.0
            self.t_LF3start = 0.0
            self.LFRT_TRIP = False
 def debug_simulation(self,t):
     """ Print to terminal for debugging."""
   
     utility_functions.print_to_terminal('t:{:.4f}'.format(t))
    
     if self.DEBUG_VOLTAGES:
         utility_functions.print_to_terminal('Vdc_ref:{:.3f},Vdc:{:.3f},Vat:{:.3f},Va:{:.3f},Vag:{:.3f},Vagrid:{:.3f},Vagrid_setpoint:{:.3f}'. format(self.PV_model.Vdc_ref,self.PV_model.Vdc,self.PV_model.Vtrms,self.PV_model.Vrms,self.grid_model.Vgrms,abs(self.grid_model.Vagrid_no_conversion)/math.sqrt(2),abs(self.grid_model.Vagrid)/math.sqrt(2)))
         
     if self.DEBUG_CURRENTS:
         utility_functions.print_to_terminal('ia_ref:{:.3f},ia:{:.3f},iload1:{:.3f}'. format(self.PV_model.ia_ref,self.PV_model.ia,self.PV_model.iaload1))
             
     if self.DEBUG_POWER:
         utility_functions.print_to_terminal('Sinsol:{:.3f},Q_ref:{:.3f},Ppv:{:.3f},S:{:.3f},S_PCC:{:.3f},S_load1:{:.3f},S_G:{:.3f}'.format(self.PV_model.Sinsol,self.PV_model.Q_ref,self.PV_model.Ppv,self.PV_model.S,self.PV_model.S_PCC,self.PV_model.S_load1,self.PV_model.S_G))
     
     if self.DEBUG_CONTROLLERS:
         utility_functions.print_to_terminal('xDC:{:.3f},xQ:{:.3f},ua:{:.3f},xa:{:.3f},ma:{:.3f}'. format(self.PV_model.xdc,self.PV_model.xQ,self.PV_model.ua,self.PV_model.xa,self.PV_model.ma))
         
     if self.DEBUG_PLL:
         utility_functions.print_to_terminal("we:{:.3f}, wte:{:.3f} rad, vd: {:.3f} V, vq {:.3f} V".format(self.PV_model.we,self.PV_model.wte,self.PV_model.vd,self.PV_model.vq))