├── README.md ├── connection_properties.xlsx ├── connection_properties_zeroed.xlsx ├── normalized_probabilities_zeroed.pickle ├── Simulating Electric Vehicles Profiles.pdf ├── ev_demand_hourly_single_connection_only.png ├── A-statistical-analysis-of-EV-charging-behavior-in-the-UK.pdf ├── pickle_dump_probabilities.py ├── ev_demand_2019_by_minute.py └── realtime_ev_demand.py /README.md: -------------------------------------------------------------------------------- 1 | # EV_DemandSimulation 2 | Monte Carlo simulation of electricity demand for electric vehicles in UK 3 | -------------------------------------------------------------------------------- /connection_properties.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msunij/EV_DemandSimulation/HEAD/connection_properties.xlsx -------------------------------------------------------------------------------- /connection_properties_zeroed.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msunij/EV_DemandSimulation/HEAD/connection_properties_zeroed.xlsx -------------------------------------------------------------------------------- /normalized_probabilities_zeroed.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msunij/EV_DemandSimulation/HEAD/normalized_probabilities_zeroed.pickle -------------------------------------------------------------------------------- /Simulating Electric Vehicles Profiles.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msunij/EV_DemandSimulation/HEAD/Simulating Electric Vehicles Profiles.pdf -------------------------------------------------------------------------------- /ev_demand_hourly_single_connection_only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msunij/EV_DemandSimulation/HEAD/ev_demand_hourly_single_connection_only.png -------------------------------------------------------------------------------- /A-statistical-analysis-of-EV-charging-behavior-in-the-UK.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msunij/EV_DemandSimulation/HEAD/A-statistical-analysis-of-EV-charging-behavior-in-the-UK.pdf -------------------------------------------------------------------------------- /pickle_dump_probabilities.py: -------------------------------------------------------------------------------- 1 | import openpyxl 2 | import pickle 3 | 4 | wb = openpyxl.load_workbook('connection_properties_zeroed.xlsx') 5 | sheet = wb.active 6 | 7 | 8 | prop_dict = {} 9 | 10 | #Number of connection 11 | pk_weekend_count = [ sheet.cell(row=23,column=10).value, sheet.cell(row=23,column=11).value] 12 | pk_weekday_count = [ sheet.cell(row=24,column=10).value, sheet.cell(row=24,column=11).value] 13 | 14 | #Connection time 15 | 16 | pk_weekday_1 = [] 17 | pk_weekday_2 = [] 18 | pk_weekend_1 = [] 19 | pk_weekend_2 = [] 20 | 21 | for i in range(6,102): 22 | pk_weekday_1.append(sheet.cell(row=i, column=4).value) 23 | pk_weekday_2.append(sheet.cell(row=i, column=5).value) 24 | pk_weekend_1.append(sheet.cell(row=i, column=6).value) 25 | pk_weekend_2.append(sheet.cell(row=i, column=7).value) 26 | 27 | 28 | #State of charge (SOC) 29 | pk_weekend_1_initial = [] 30 | pk_weekend_2_initial = [] 31 | pk_weekday_1_initial = [] 32 | pk_weekday_2_initial = [] 33 | pk_weekend_1_final = [] 34 | pk_weekend_2_final = [] 35 | pk_weekday_1_final = [] 36 | pk_weekday_2_final = [] 37 | 38 | for i in range(5,18): 39 | pk_weekday_1_initial.append(sheet.cell(row=i, column=10).value) 40 | pk_weekday_2_initial.append(sheet.cell(row=i, column=11).value) 41 | pk_weekday_1_final.append(sheet.cell(row=i, column=12).value) 42 | pk_weekday_2_final.append(sheet.cell(row=i, column=13).value) 43 | pk_weekend_1_initial.append(sheet.cell(row=i, column=14).value) 44 | pk_weekend_2_initial.append(sheet.cell(row=i, column=15).value) 45 | pk_weekend_1_final.append(sheet.cell(row=i, column=16).value) 46 | pk_weekend_2_final.append(sheet.cell(row=i, column=17).value) 47 | 48 | # Normalizing the probabilites 49 | pk_weekend_count = [ p/sum(pk_weekend_count) for p in pk_weekend_count ] 50 | pk_weekday_count = [ p/sum(pk_weekday_count) for p in pk_weekday_count ] 51 | 52 | pk_weekday_1 = [ p/sum(pk_weekday_1) for p in pk_weekday_1 ] 53 | pk_weekday_2 = [ p/sum(pk_weekday_2) for p in pk_weekday_2 ] 54 | pk_weekend_1 = [ p/sum(pk_weekend_1) for p in pk_weekend_1 ] 55 | pk_weekend_2 = [ p/sum(pk_weekend_2) for p in pk_weekend_2 ] 56 | 57 | pk_weekend_1_initial = [ p/sum(pk_weekend_1_initial) for p in pk_weekend_1_initial] 58 | pk_weekend_2_initial = [ p/sum(pk_weekend_2_initial) for p in pk_weekend_2_initial] 59 | pk_weekday_1_initial = [ p/sum(pk_weekday_1_initial) for p in pk_weekday_1_initial] 60 | pk_weekday_2_initial = [ p/sum(pk_weekday_2_initial) for p in pk_weekday_2_initial] 61 | pk_weekend_1_final = [ p/sum(pk_weekend_1_final) for p in pk_weekend_1_final] 62 | pk_weekend_2_final = [ p/sum(pk_weekend_2_final) for p in pk_weekend_2_final] 63 | pk_weekday_1_final = [ p/sum(pk_weekday_1_final) for p in pk_weekday_1_final] 64 | pk_weekday_2_final = [ p/sum(pk_weekday_2_final) for p in pk_weekday_2_final] 65 | 66 | #time step and soc level 67 | timestep_connection = [ i for i in range(0,1440,15)] 68 | soc_unit_level = [ i for i in range(13)] 69 | 70 | #add it to the dictionaray 71 | prob_dict = {'count_prob_day':pk_weekday_count, 72 | 'count_prob_end': pk_weekend_count, 73 | 'connection_time_step':timestep_connection, 74 | 'connection_time_day_1':pk_weekday_1, 75 | 'connection_time_day_2':pk_weekday_2, 76 | 'connection_time_end_1':pk_weekend_1, 77 | 'connection_time_end_2':pk_weekend_2, 78 | 'soc_unit_level': soc_unit_level, 79 | 'soc_day_initial_1':pk_weekday_1_initial, 80 | 'soc_day_initial_2':pk_weekday_2_initial, 81 | 'soc_day_final_1':pk_weekday_1_final, 82 | 'soc_day_final_2':pk_weekday_2_final, 83 | 'soc_end_initial_1':pk_weekend_1_initial, 84 | 'soc_end_initial_2':pk_weekend_2_initial, 85 | 'soc_end_final_1':pk_weekend_1_final, 86 | 'soc_end_final_2':pk_weekend_2_final} 87 | 88 | #pickle dump process 89 | with open('normalized_probabilities_zeroed.pickle','wb') as fp: 90 | pickle.dump(prob_dict,fp) -------------------------------------------------------------------------------- /ev_demand_2019_by_minute.py: -------------------------------------------------------------------------------- 1 | import simpy 2 | import random 3 | from scipy import stats 4 | from datetime import datetime, timedelta 5 | import pickle 6 | from scipy import stats 7 | import openpyxl 8 | 9 | POWER_FACTOR = 0.98 10 | POWER_DEMAND_WHEN_CHARGING = 3.6*POWER_FACTOR 11 | CHARGE_PER_SEGMENT = 2 12 | NUM_CARS = 4 13 | DAYS = 5 14 | GAP = 0 # minimum time between successive chargings 15 | 16 | 17 | #Unpickle the pickled probability data 18 | with open('normalized_probabilities_zeroed.pickle', 'rb') as fp: 19 | connection_properties_dict = pickle.load(fp) 20 | 21 | 22 | ##probability daily connection 23 | pk_weekend_count = connection_properties_dict['count_prob_end'] 24 | pk_weekday_count = connection_properties_dict['count_prob_day'] 25 | 26 | 27 | xk_connection_time = connection_properties_dict['connection_time_step'] 28 | pk_weekend_1 = connection_properties_dict['connection_time_end_1'] 29 | pk_weekend_2 = connection_properties_dict['connection_time_end_2'] 30 | pk_weekday_1 = connection_properties_dict['connection_time_day_1'] 31 | pk_weekday_2 = connection_properties_dict['connection_time_day_2'] 32 | 33 | #SOC calculation 34 | xk_chargelevel = connection_properties_dict['soc_unit_level'] 35 | pk_weekend_1_initial = connection_properties_dict['soc_end_initial_1'] 36 | pk_weekend_2_initial = connection_properties_dict['soc_end_initial_2'] 37 | pk_weekday_1_initial = connection_properties_dict['soc_day_initial_1'] 38 | pk_weekday_2_initial = connection_properties_dict['soc_day_initial_2'] 39 | 40 | pk_weekend_1_final = connection_properties_dict['soc_end_final_1'] 41 | pk_weekend_2_final = connection_properties_dict['soc_end_final_2'] 42 | pk_weekday_1_final = connection_properties_dict['soc_day_final_1'] 43 | pk_weekday_2_final = connection_properties_dict['soc_day_final_2'] 44 | 45 | ## Random variable generators 46 | 47 | ## Number of daily connections 48 | number_of_connection_end_rv_generator = stats.rv_discrete(values =([1,2], pk_weekend_count)) 49 | number_of_connection_day_rv_generator = stats.rv_discrete(values =([1,2], pk_weekday_count)) 50 | 51 | ## charge duration 52 | initial_day_1_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekday_1_initial)) 53 | initial_day_2_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekday_2_initial)) 54 | initial_end_1_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekend_1_initial)) 55 | initial_end_2_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekend_2_initial)) 56 | 57 | final_day_1_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekday_1_final)) 58 | final_day_2_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekday_2_final)) 59 | final_end_1_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekend_1_final)) 60 | final_end_2_soc_rv_generator = stats.rv_discrete(values=(xk_chargelevel,pk_weekend_2_final)) 61 | 62 | ## Daily connection times 63 | connection_time_end_1_rv_generator = stats.rv_discrete(values=(xk_connection_time, pk_weekend_1)) 64 | connection_time_end_2_rv_generator = stats.rv_discrete(values=(xk_connection_time, pk_weekend_2)) 65 | connection_time_day_1_rv_generator = stats.rv_discrete(values=(xk_connection_time, pk_weekday_1)) 66 | connection_time_day_2_rv_generator = stats.rv_discrete(values=(xk_connection_time, pk_weekday_2)) 67 | 68 | 69 | 70 | #Simulation starts on 1st Januvary 2019(Tuesday) 71 | def is_weekend(minutes_passed): 72 | d = datetime(2019,1,1)+timedelta(minutes=minutes_passed) 73 | if d.weekday()>4: 74 | return True 75 | else: 76 | return False 77 | 78 | #format minutes to HH:MM 79 | def format_minutes(minutes_passed): 80 | return str(timedelta(minutes=minutes_passed))[:-3] 81 | 82 | #minutes left in a day 83 | def minutes_left_in_the_day(minutes_passed): 84 | minutes_left = (24*60)-(minutes_passed%(24*60)) 85 | return minutes_left 86 | 87 | def number_of_daily_connections(minutes_passed): 88 | if is_weekend(minutes_passed): 89 | rv_gen = number_of_connection_end_rv_generator 90 | else: 91 | rv_gen = number_of_connection_day_rv_generator 92 | return rv_gen.rvs(size=1)[0] 93 | 94 | 95 | def charge_duration_calculation(minutes_passed,count): 96 | #print('duration calculation ') 97 | #initial SOC calculation 98 | if count==1: 99 | if is_weekend(minutes_passed): 100 | rv_gen = initial_end_1_soc_rv_generator 101 | else: 102 | rv_gen = initial_day_1_soc_rv_generator 103 | else: 104 | if is_weekend(minutes_passed): 105 | rv_gen = initial_end_2_soc_rv_generator 106 | else: 107 | rv_gen = initial_day_2_soc_rv_generator 108 | 109 | initial_soc = rv_gen.rvs(size=1)[0] 110 | if initial_soc == 12: 111 | return 60 112 | #print('initi ',initial_soc) 113 | #Final SOC calculation 114 | if count==1: 115 | if is_weekend(minutes_passed): 116 | rv_gen = final_end_1_soc_rv_generator 117 | else: 118 | rv_gen = final_day_1_soc_rv_generator 119 | else: 120 | if is_weekend(minutes_passed): 121 | rv_gen = final_end_2_soc_rv_generator 122 | else: 123 | rv_gen = final_day_2_soc_rv_generator 124 | 125 | final_soc = 0 126 | while final_soc<=initial_soc: 127 | final_soc= rv_gen.rvs(size=1)[0] 128 | #print('final',final_soc) 129 | duration = ((final_soc-initial_soc)*CHARGE_PER_SEGMENT)/(3.6*POWER_FACTOR/60) 130 | 131 | #print(format_minutes(duration)) 132 | return duration 133 | 134 | def daily_connection_time_calculation(minutes_passed,connection_number): 135 | if connection_number==1: 136 | if is_weekend(minutes_passed): 137 | rv_gen = connection_time_end_1_rv_generator 138 | else: 139 | rv_gen = connection_time_day_1_rv_generator 140 | else: 141 | if is_weekend(minutes_passed): 142 | rv_gen = connection_time_end_2_rv_generator 143 | else: 144 | rv_gen = connection_time_day_2_rv_generator 145 | 146 | next_connection_time = int(rv_gen.rvs(size=1)[0]) 147 | return next_connection_time 148 | # time = random.randint(2*60,20*60) 149 | # return time 150 | 151 | class EVClass: 152 | def __init__(self, env, name): 153 | self.env = env 154 | self.name = name 155 | self.connection_clock_times = [0,0] 156 | self.power_demand = 0 157 | self.last_balance_charging_clock_time = 0 158 | 159 | # Start the run and monitor process everytime an instance is created. 160 | self.action = env.process(self.run()) 161 | self.monitor_process = env.process(self.monitor_demand(env)) 162 | 163 | def run(self): 164 | while True: 165 | #calculate number of connection 166 | number_of_connections = number_of_daily_connections(self.env.now) 167 | print("number_of_connections: {}".format(number_of_connections)) 168 | 169 | #left over charging from last day using self.last_balance_charging_clock_time 170 | yield self.env.timeout(self.last_balance_charging_clock_time) 171 | self.power_demand = 0 172 | 173 | yield self.env.process(self.charging_process(number_of_connections)) 174 | def charging_process(self,connection_count): 175 | 176 | if connection_count == 1: 177 | #calculate connection time 178 | connection_start_clock_time = self.connection_clock_time_calculation(connection_count) 179 | yield self.env.timeout(connection_start_clock_time-self.last_balance_charging_clock_time) 180 | else: 181 | #calculate connection time 182 | connection_start_clock_time = self.connection_clock_time_calculation(connection_count) 183 | yield self.env.process(self.additional_charging(connection_start_clock_time)) 184 | #Charging time 185 | balance_time_duration = yield self.env.process(self.charge(connection_count)) 186 | #print("in main run, with balance_time {} hours".format(balance_time/60)) 187 | 188 | #if charging end before midnight go to next day 189 | if balance_time_duration>=0: 190 | self.power_demand = 0 191 | self.last_balance_charging_clock_time = 0 192 | yield self.env.timeout(balance_time_duration) 193 | #print('day ends here') 194 | #else wait for the day to end and assign balance charging time to self.last_balance_charging_clock_time 195 | else: 196 | #print('day ends here for left over') 197 | self.last_balance_charging_clock_time = -balance_time_duration 198 | 199 | def additional_charging(self, end_clock_time): 200 | #calculate connection start time such that it is between balance time and second connection start time 201 | connection_start_clock_time = 0 202 | while not end_clock_time>connection_start_clock_time>(self.last_balance_charging_clock_time+GAP): 203 | connection_start_clock_time = self.connection_clock_time_calculation(1) 204 | 205 | duration = end_clock_time 206 | if (end_clock_time-connection_start_clock_time)>40: 207 | while connection_start_clock_time+duration>(end_clock_time-GAP): 208 | duration = charge_duration_calculation(self.env.now,1) 209 | #print("stuck here") 210 | else: 211 | duration = 0 212 | #wait till first connection start time 213 | yield self.env.timeout(connection_start_clock_time-self.last_balance_charging_clock_time) 214 | 215 | #start charging 216 | #print("start charging 1 of 2 at: {}".format(format_minutes(self.env.now))) 217 | self.power_demand = POWER_DEMAND_WHEN_CHARGING 218 | yield self.env.timeout(duration) 219 | 220 | #stop charging and wait till second connection 221 | self.power_demand = 0 222 | yield self.env.timeout(end_clock_time-(connection_start_clock_time+duration)) 223 | 224 | def charge(self,count): 225 | self.power_demand = POWER_DEMAND_WHEN_CHARGING 226 | #print("charging starts at: {}".format(format_minutes(self.env.now))) 227 | duration = charge_duration_calculation(self.env.now,count) 228 | #print("charge duration {}".format(format_minutes(duration))) 229 | balance_time_duration = (24*60)-(self.connection_clock_times[count-1]+duration) 230 | #positive balance time means charging ends before midnight 231 | if balance_time_duration>=0: 232 | #print("charging at {} ends befor midnight".format(format_minutes(self.env.now))) 233 | #print("connection time {}".format(format_minutes(self.connection_times[count-1]))) 234 | yield self.env.timeout(duration) 235 | return balance_time_duration 236 | else: 237 | #charge till midnight and return the balance time 238 | #print("charging at till midnight from {}, left on tomorrow {}".format(format_minutes(self.env.now),balance_time)) 239 | yield self.env.timeout((24*60)-self.connection_clock_times[count-1]) 240 | return balance_time_duration 241 | 242 | 243 | def connection_clock_time_calculation(self,count): 244 | if self.last_balance_charging_clock_time==0: 245 | clock_time = daily_connection_time_calculation(self.env.now,count) 246 | 247 | else: 248 | clock_time = 0 249 | while clock_time4: 73 | return True 74 | else: 75 | return False 76 | 77 | #format minutes to HH:MM 78 | def format_minutes(minutes_passed): 79 | return str(timedelta(minutes=minutes_passed))[:-3] 80 | 81 | #minutes left in a day 82 | def minutes_left_in_the_day(minutes_passed): 83 | minutes_left = (24*60)-(minutes_passed%(24*60)) 84 | return minutes_left 85 | 86 | def number_of_daily_connections(minutes_passed): 87 | if is_weekend(minutes_passed): 88 | rv_gen = number_of_connection_end_rv_generator 89 | else: 90 | rv_gen = number_of_connection_day_rv_generator 91 | return rv_gen.rvs(size=1)[0] 92 | 93 | 94 | def charge_duration_calculation(minutes_passed,count): 95 | #print('duration calculation ') 96 | #initial SOC calculation 97 | if count==1: 98 | if is_weekend(minutes_passed): 99 | rv_gen = initial_end_1_soc_rv_generator 100 | else: 101 | rv_gen = initial_day_1_soc_rv_generator 102 | else: 103 | if is_weekend(minutes_passed): 104 | rv_gen = initial_end_2_soc_rv_generator 105 | else: 106 | rv_gen = initial_day_2_soc_rv_generator 107 | 108 | initial_soc = rv_gen.rvs(size=1)[0] 109 | if initial_soc == 12: 110 | return 60 111 | #print('initi ',initial_soc) 112 | #Final SOC calculation 113 | if count==1: 114 | if is_weekend(minutes_passed): 115 | rv_gen = final_end_1_soc_rv_generator 116 | else: 117 | rv_gen = final_day_1_soc_rv_generator 118 | else: 119 | if is_weekend(minutes_passed): 120 | rv_gen = final_end_2_soc_rv_generator 121 | else: 122 | rv_gen = final_day_2_soc_rv_generator 123 | 124 | final_soc = 0 125 | while final_soc<=initial_soc: 126 | final_soc= rv_gen.rvs(size=1)[0] 127 | #print('final',final_soc) 128 | duration = ((final_soc-initial_soc)*CHARGE_PER_SEGMENT)/(3.6*POWER_FACTOR/60) 129 | 130 | #print(format_minutes(duration)) 131 | return duration 132 | 133 | def daily_connection_time_calculation(minutes_passed,connection_number): 134 | if connection_number==1: 135 | if is_weekend(minutes_passed): 136 | rv_gen = connection_time_end_1_rv_generator 137 | else: 138 | rv_gen = connection_time_day_1_rv_generator 139 | else: 140 | if is_weekend(minutes_passed): 141 | rv_gen = connection_time_end_2_rv_generator 142 | else: 143 | rv_gen = connection_time_day_2_rv_generator 144 | 145 | next_connection_time = int(rv_gen.rvs(size=1)[0]) 146 | return next_connection_time 147 | # time = random.randint(2*60,20*60) 148 | # return time 149 | 150 | class EVClass: 151 | def __init__(self, env, name): 152 | self.env = env 153 | self.name = name 154 | self.connection_clock_times = [0,0] 155 | self.power_demand = 0 156 | self.last_balance_charging_clock_time = 0 157 | 158 | # Start the run and monitor process everytime an instance is created. 159 | self.action = env.process(self.run()) 160 | self.monitor_process = env.process(self.monitor_demand(env)) 161 | 162 | def run(self): 163 | while True: 164 | #calculate number of connection 165 | number_of_connections = number_of_daily_connections(self.env.now) 166 | #print("number_of_connections: {}".format(number_of_connections)) 167 | 168 | #left over charging from last day using self.last_balance_charging_clock_time 169 | yield self.env.timeout(self.last_balance_charging_clock_time) 170 | self.power_demand = 0 171 | 172 | yield self.env.process(self.charging_process(number_of_connections)) 173 | def charging_process(self,connection_count): 174 | 175 | if connection_count == 1: 176 | #calculate connection time 177 | connection_start_clock_time = self.connection_clock_time_calculation(connection_count) 178 | yield self.env.timeout(connection_start_clock_time-self.last_balance_charging_clock_time) 179 | else: 180 | #calculate connection time 181 | connection_start_clock_time = self.connection_clock_time_calculation(connection_count) 182 | yield self.env.process(self.additional_charging(connection_start_clock_time)) 183 | #Charging time 184 | balance_time_duration = yield self.env.process(self.charge(connection_count)) 185 | #print("in main run, with balance_time {} hours".format(balance_time/60)) 186 | 187 | #if charging end before midnight go to next day 188 | if balance_time_duration>=0: 189 | self.power_demand = 0 190 | self.last_balance_charging_clock_time = 0 191 | yield self.env.timeout(balance_time_duration) 192 | #print('day ends here') 193 | #else wait for the day to end and assign balance charging time to self.last_balance_charging_clock_time 194 | else: 195 | #print('day ends here for left over') 196 | self.last_balance_charging_clock_time = -balance_time_duration 197 | 198 | def additional_charging(self, end_clock_time): 199 | #calculate connection start time such that it is between balance time and second connection start time 200 | connection_start_clock_time = 0 201 | while not end_clock_time>connection_start_clock_time>(self.last_balance_charging_clock_time+GAP): 202 | connection_start_clock_time = self.connection_clock_time_calculation(1) 203 | 204 | duration = end_clock_time 205 | if (end_clock_time-connection_start_clock_time)>40: 206 | while connection_start_clock_time+duration>(end_clock_time-GAP): 207 | duration = charge_duration_calculation(self.env.now,1) 208 | #print("stuck here") 209 | else: 210 | duration = 0 211 | #wait till first connection start time 212 | yield self.env.timeout(connection_start_clock_time-self.last_balance_charging_clock_time) 213 | 214 | #start charging 215 | #print("start charging 1 of 2 at: {}".format(format_minutes(self.env.now))) 216 | self.power_demand = POWER_DEMAND_WHEN_CHARGING 217 | yield self.env.timeout(duration) 218 | 219 | #stop charging and wait till second connection 220 | self.power_demand = 0 221 | yield self.env.timeout(end_clock_time-(connection_start_clock_time+duration)) 222 | 223 | def charge(self,count): 224 | self.power_demand = POWER_DEMAND_WHEN_CHARGING 225 | #print("charging starts at: {}".format(format_minutes(self.env.now))) 226 | duration = charge_duration_calculation(self.env.now,count) 227 | #print("charge duration {}".format(format_minutes(duration))) 228 | balance_time_duration = (24*60)-(self.connection_clock_times[count-1]+duration) 229 | #positive balance time means charging ends before midnight 230 | if balance_time_duration>=0: 231 | #print("charging at {} ends befor midnight".format(format_minutes(self.env.now))) 232 | #print("connection time {}".format(format_minutes(self.connection_times[count-1]))) 233 | yield self.env.timeout(duration) 234 | return balance_time_duration 235 | else: 236 | #charge till midnight and return the balance time 237 | #print("charging at till midnight from {}, left on tomorrow {}".format(format_minutes(self.env.now),balance_time)) 238 | yield self.env.timeout((24*60)-self.connection_clock_times[count-1]) 239 | return balance_time_duration 240 | 241 | 242 | def connection_clock_time_calculation(self,count): 243 | if self.last_balance_charging_clock_time==0: 244 | clock_time = daily_connection_time_calculation(self.env.now,count) 245 | 246 | else: 247 | clock_time = 0 248 | while clock_time