def receptacles(self): ''' Simulation of the receptacle loads. ''' dataset = ast.literal_eval( open(os.path.abspath('Data\\Appliances.py')).read()) # define number of minutes nmin = self.nday * 1440 # determine all transitions of the appliances depending on the appliance # basic properties, ie. stochastic versus cycling power profile power = np.zeros(nmin + 1) radi = np.zeros(nmin + 1) conv = np.zeros(nmin + 1) nday = self.nday dow = self.dow result_n = dict() counter = range(len(self.clusters)) for app in self.apps: # create the equipment object with data from dataset.py eq = Equipment(**dataset[app]) r_app = dict() n_app = 0 # loop for all household mmembers for i in counter: r_appi, n_appi = eq.simulate(nday, dow, self.clusters[i], self.occ[i]) r_app = stats.sum_dict(r_app, r_appi) n_app += n_appi # and sum result_n.update({app: n_app}) power += r_app['P'] radi += r_app['QRad'] conv += r_app['QCon'] # a new time axis for power output is to be created as a different # time step is used in comparison to occupancy time = 4 * 60 * 600 + np.arange(0, (nmin + 1) * 60, 60) react = np.zeros(nmin + 1) result = { 'time': time, 'occ': None, 'P': power, 'Q': react, 'QRad': radi, 'QCon': conv, 'Wknds': None, 'mDHW': None } self.r_receptacles = result self.n_receptacles = result_n # output ########################################################## # only the power load is returned load = int(np.sum(result['P']) / 60 / 1000) print ' - Receptacle load is %s kWh' % str(load) return None
def receptacles(self): ''' Simulation of the receptacle loads. ''' dataset = ast.literal_eval(open('Appliances.py').read()) # define number of minutes nmin = self.nday * 1440 # determine all transitions of the appliances depending on the appliance # basic properties, ie. stochastic versus cycling power profile power = np.zeros(nmin+1) radi = np.zeros(nmin+1) conv = np.zeros(nmin+1) nday = self.nday dow = self.dow result_n = dict() counter = range(len(self.clusters)) for app in self.apps: # create the equipment object with data from dataset.py eq = Equipment(**dataset[app]) r_app = dict() n_app = 0 # loop for all household mmembers for i in counter: r_appi, n_appi = eq.simulate(nday, dow, self.clusters[i], self.occ[i]) r_app = stats.sum_dict(r_app, r_appi) n_app += n_appi # and sum result_n.update({app:n_app}) power += r_app['P'] radi += r_app['QRad'] conv += r_app['QCon'] # a new time axis for power output is to be created as a different # time step is used in comparison to occupancy time = 4*60*600 + np.arange(0, (nmin+1)*60, 60) react = np.zeros(nmin+1) result = {'time':time, 'occ':None, 'P':power, 'Q':react, 'QRad':radi, 'QCon':conv, 'Wknds':None, 'mDHW':None} self.r_receptacles = result self.n_receptacles = result_n # output ########################################################## # only the power load is returned load = int(np.sum(result['P'])/60/1000) print ' - Receptacle load is %s kWh' % str(load) return None
def receptacles(self): ''' Simulation of the receptacle loads. ''' # define number of minutes nmin = self.nday * 1440 # determine all transitions of the appliances depending on the appliance # basic properties, ie. stochastic versus cycling power profile power = np.zeros(nmin + 1) radi = np.zeros(nmin + 1) conv = np.zeros(nmin + 1) nday = self.nday dow = self.dow result_n = dict() counter = range(len(self.clusters)) for app in self.apps: # create the equipment object with data from dataset.py eq = Equipment(**set_appliances[app]) r_app = dict() n_app = 0 # loop for all household members for i in counter: # if appliances are not shared the load of using the appliance can be summed for each householdmember if app in ( 'CordlessPhone', 'PC' ): # it is assumed that only the cordlessphone and PC are not shared. Each person in the household (>12) has its own phone or PC. r_appi, n_appi = eq.simulate(nday, dow, self.clusters[i], self.occ[i]) r_app = stats.sum_dict(r_app, r_appi) n_app += n_appi else: # if appliances are shared the load of using the appliance can be maximal the cycle load. # if the appliance is an appliance that is working continously the load is simulated for only 1 person if app in ('FridgeFreezer', 'Refrigerator', 'ChestFreezer', 'UprightFreezer', 'Clock'): if i == 0: r_appi, n_appi = eq.simulate( nday, dow, self.clusters[i], self.occ[i]) r_app = stats.sum_dict(r_app, r_appi) n_app += n_appi # if the appliance is not continously used, but sometimes shared, the cycle load is assigned when minimal one person is using it, when nobody is using it the stanby load is assigned else: r_appi, n_appi = eq.simulate( nday, dow, self.clusters[i], self.occ[i]) r_app = stats.sum_dict2(r_app, r_appi) n_app += n_appi # and sum result_n.update({app: n_app}) power += r_app['P'] radi += r_app['QRad'] conv += r_app['QCon'] # a new time axis for power output is to be created as a different # time step is used in comparison to occupancy time = 4 * 60 * 60 + np.arange(0, (nmin + 1) * 60, 60) react = np.zeros(nmin + 1) result = { 'time': time, 'occ': None, 'P': power, 'Q': react, 'QRad': radi, 'QCon': conv, 'Wknds': None, 'mDHW': None } self.r_receptacles = result self.n_receptacles = result_n # output ########################################################## # only the power load is returned load = int(np.sum(result['P']) / 60 / 1000) print(' - Receptacle load is %s kWh' % str(load)) return None
def simulate(self, nday, dow, clustersList, occ): def stochastic_flow(self, nday, dow, clusterList, occ): ''' Simulate hot water tappings based on occupancy and the Markov state-space model of Richardson et al. Tapping characteristics are taken from Jordan & Vajen (2001). "Realistic Domestic Hot-water Profiles in Different Time Scales" ''' # parameters ###################################################### # First we check the required activity and load the respective # stats.DTMC file with its data for the "main" occupant, since the merged occupancy is used. clusterDict = clusterList[ 0] # take Dictionary in first element of list (i.e. "main" occupant) len_cycle = self.cycle_length act = self.activity if self.activity not in ( 'None', 'Presence' ): # get activity probabilities from stats.DTMC file actdata = stats.DTMC(clusterDict=clusterDict) else: actdata = None # script ########################################################## # a yearly simulation is basic, also in a unittest nbin = 144 # steps in occupancy data per day (10min steps) nmin = nday * 24 * 60 # number of minutes in total number of days to = -1 # time counter for occupancy tl = -1 # time counter for flow left = -1 # time counter for tapping duration n_fl = 0 flow = np.zeros(nmin + 1) for doy, step in itertools.product(range(nday), range(nbin)): dow_i = dow[doy] to += 1 for run in range(0, 10): tl += 1 # check if this tap is already open if left <= 0: # determine possibilities if self.activity == 'None': prob = 1 elif self.activity == 'Presence': prob = 1 if occ[to] == 1 else 0 else: occs = 1 if occ[to] == 1 else 0 prob = occs * actdata.get_var(dow_i, act, step) # check if there is a statechange in the tap if random.random() < prob * self.cal: n_fl += 1 left = random.gauss(len_cycle, len_cycle / 10) flow[tl] += self.standby_flow else: left += -1 flow[tl] += self.cycle_flow r_fl = {'mDHW': flow} return r_fl, n_fl def stochastic_load(self, nday, dow, clustersList, occ): ''' Simulate non-cycling appliances based on occupancy and the Markov state-space model of Richardson et al. ''' # parameters ###################################################### len_cycle = self.cycle_length # cycle length for this appliance act = self.activity # activity linked to the use of this appliance numOcc = len( clustersList) # number of differenc active occupants >12y # script ########################################################## # a yearly simulation is basic, also in a unittest nbin = 144 # steps in occupancy data per day (10min steps) nmin = nday * 24 * 60 # number of minutes in total number of days n_eq_dur = 0 # number of minutes that the appliance is used P = np.zeros(nmin + 1) Q = np.zeros(nmin + 1) # prefill probabilities for each occupant to perform the activity linked to appliance for entire year # make occupancy vector per time step (10-min): if ANY occupant is active (state=1), make aggregate occy=1 occy = [[1 if occ[i][x] == 1 else 0 for x in range(nday * nbin)] for i in range(numOcc)] # size numOcc x timesteps in year if act == 'None': # if appliance is linked to no specific activity (e.g. fridge) prob = [[1 for x in range(nday * nbin)] for i in range(numOcc) ] # activity 'None' always probability=1 elif act == 'Presence': # if appliance linked to presence (active occupants): probability =1 when ANYONE is present prob = occy else: # appliance linked to specific activity (e.g. "food") # get activity probabilities for all occupants from stats.DTMC file actdata = [ stats.DTMC(clusterDict=clustersList[i]) for i in range(numOcc) ] prob = occy # just initiate correct size to = -1 # time counter for occupancy for doy, step in itertools.product( range(nday), range(nbin)): #loop over year dow_i = dow[doy] # day of week (Monday=0) to += 1 for i in range( numOcc ): # get probability each occupant is performing the activity related to the appliance prob[i][to] = occy[i][to] * actdata[i].get_var( dow_i, act, step) ######################### SIMULATE appliance use to = -1 # time counter for occupancy (10min) tl = -1 # time counter for load (1min) left = [ -1 for i in range(numOcc) ] # time counter for appliance duration per occupant -> start as not used: -1 for doy, step in itertools.product( range(nday), range(nbin)): # loop over 10min steps in year dow_i = dow[doy] # day of week to += 1 # occupancy in 10 min, but for each occupancy step simulate 10 individual minutes for the loads. for run in range(10): tl += 1 if any( l > 0 for l in left ): # if any occupant was using the appliance (there was time left[i]>0) P[tl] += self.cycle_power # assign power used when appliance is working n_eq_dur += 1 # add to counter for number of minutes used in year else: # if nobody was using it P[tl] += self.standby_power # assign stand-by power # per occupant, check if they will want to change the state of the appliance for i in range(numOcc): # check if this appliance is being used by occupant i: time left[i]>0 if left[i] > 0: left[ i] += -1 # count time down until cycle passed (for this occupant) else: # if it was not used by this occupant: left[i] <= 0 # check if there is a state change in the appliance for this occupant if random.random() < prob[i][ to] * self.cal: # if random number below calibration factor cal* probability of activity: start appliance left[i] = random.gauss( len_cycle, len_cycle / 10 ) # start a cycle of random duration for this occupant r_eq = { 'P': P, 'Q': Q, 'QRad': P * self.frad, 'QCon': P * self.fconv, } # n_eq is used in calibration process for value of 'cal' if len_cycle != 0: n_eq = n_eq_dur / len_cycle # approximate number of cycles/year (assuming average length: mean of gauss distribution) else: n_eq = 1e-05 # some appliances don't have number of cycles if they are continuously working (then n_eq is not used) return r_eq, n_eq def cycle_load(self, nday): ''' Simulate cycling appliances, eg. fridges and freezers based on average clycle length and delay between cycles ''' nmin = nday * 24 * 60 # number of minutes in total number of days P = np.zeros(nmin + 1) Q = np.zeros(nmin + 1) #currently no data included (remains zero) n_eq = 0 # number of cycles for calibration of `cal` parameter of appliance # define length of cycles (same for entire year, assumed to depend on appliance) len_cycle = random.gauss(self.cycle_length, self.cycle_length / 10) # define duration of break between cycles (same for entire year) delay = random.gauss(self.delay, self.delay / 10) # start as OFF (assumption) on = False #is it ON? left = random.gauss( delay / 2, delay / 4) # time left until change of state (initiate random) for tl in range(nmin + 1): # loop over every minute of the year # if there is time LEFT until change of state, remain as is # if time is up, change state: if left <= 0: on = not on # switch to opposite state ON/OFF if on: # if switched ON n_eq += 1 # add one to cycle counter left = len_cycle #start counting 1 cycle length else: # if switched OFF left = delay #start counting time until next cycle # either way, count downt the time until next change of state left += -1 # allocate correct power, depending on current state ON/OFF if on: P[tl] = self.cycle_power # instead of the average consumption, could be sampled from normal distribution as well else: P[tl] = self.standby_power r_eq = { 'P': P, 'Q': Q, 'QRad': P * self.frad, 'QCon': P * self.fconv } return r_eq, n_eq # when simulating an equipment object, choose which of following happens: if self.type == 'appliance': #check if the equipment is an appliance instead of tapping point if self.activity == 'None': #cycling loads -> don't depend on occupants r_app, n_app = cycle_load(self, nday) elif self.name in ( 'placeholder' ): # For future: if each occupant has her/his own appliance # For the moment appliances are assigned to the household such that there is one of each type # -> no way many people use their own (That's why there are 3 different TVs) r_app = dict() n_app = 0 for i in range( len(clustersList)): # loop active occupants >12y r_appi, n_appi = stochastic_load( self, nday, dow, [clustersList[i]], [occ[i]]) # we pass a list with one clusterDict r_app = stats.sum_dict(r_app, r_appi) n_app += n_appi else: # other appliances (shared) r_app, n_app = stochastic_load( self, nday, dow, clustersList, occ ) # we pass a list with all available clusterDicts, as given from plugloads else: # flow-> model is based on total presence: do only once. r_app, n_app = stochastic_flow( self, nday, dow, clustersList, occ ) # we pass a list with one clusterDict, as given from DHW model return r_app, n_app