def setUpClass(self): # This method instantiates the fleet and executes a simple request to get the device response for evaluation # Create test fleet kwargs = {} kwargs['start_time'] = start_time kwargs['service_weight'] = 0.75 kwargs['sim_step'] = delt grid_type = 1 fleet = create_fleet(fleet_name, grid_type, **kwargs) if fleet is None: raise 'Could not create fleet with name ' + fleet_name cycle = 5 #24 dt_day = [(start_time + delt * i) for i in range(cycle)] p_needed = [(100 * i) for i in range(cycle)] requests = [ FleetRequest(ts=dt_day[i], sim_step=delt, start_time=start_time, p=p_needed[i]) for i in range(cycle) ] fleet_responses = fleet.forecast(requests) self.responses = fleet_responses
def main(ts, grid): # Instantiation of an object of the ElectricVehiclesFleet class fleet_test = ElectricVehiclesFleet(grid, ts) dt = 3600 * 1 # time step (in seconds) sim_step = timedelta(seconds=dt) seconds_of_simulation = 24 * 3600 # (in seconds) local_time = fleet_test.get_time_of_the_day(ts) t = np.arange(local_time, local_time + seconds_of_simulation, dt) # array of time in seconds # Power requested (kW): test fleet_test.is_autonomous = False fleet_test.is_P_priority = True # List of requests requests = [] for i in range(len(t)): req = FleetRequest(ts + i * sim_step, sim_step, ts, None, 0.) requests.append(req) FORECAST = fleet_test.forecast(requests) eff_charging = np.zeros([ len(t), ]) eff_discharging = np.zeros([ len(t), ]) energy = np.zeros([ len(t), ]) capacity = np.zeros([ len(t), ]) min_power_service = np.zeros([ len(t), ]) max_power_service = np.zeros([ len(t), ]) min_power_togrid = np.zeros([ len(t), ]) max_power_togrid = np.zeros([ len(t), ]) for i in range(len(t)): eff_charging[i] = FORECAST[i].Eff_charge eff_discharging[i] = FORECAST[i].Eff_discharge energy[i] = FORECAST[i].E capacity[i] = FORECAST[i].C min_power_service[i] = FORECAST[i].P_service_min max_power_service[i] = FORECAST[i].P_service_max min_power_togrid[i] = FORECAST[i].P_togrid_min max_power_togrid[i] = FORECAST[i].P_togrid_max return (eff_charging, eff_discharging, energy, capacity, min_power_service, max_power_service, max_power_togrid, min_power_togrid)
def integration_test(): # Establish the test variables n = 24 dt = 1 SoC0 = 50 # t = numpy.linspace(0, (n - 1), n) # EffMatrix = numpy.zeros((n, n)) ts = datetime.utcnow() # print(n) Fleet = BatteryInverterFleet() Fleet.soc = SoC0 # initialize SoC Power = numpy.zeros(n) # initialize Power Power = Fleet.max_power_charge # Power = Fleet.max_power_discharge # simulate the system with SoC0 and Power requests for T in numpy.arange(0, n): req = FleetRequest(ts,dt,Power[T],0.0) Fleet.process_request(req) SoCFin = Fleet.soc # get final SoC [P2, Cost, Able] = Fleet.cost(SoCFin, SoC0, dt) # retreeve how much power it would take to return to SoC0 P2Charge = max(P2,0) P2Discharge = min(P2,0)
def fleet_test(): Fleet = BatteryInverterFleet() t = numpy.linspace(0, 24, 97) requests = [] ts = datetime.utcnow() dt = 1/4 #hours for i in t: req = FleetRequest(ts,dt,float(10*numpy.sin(2*numpy.pi*i/24)),0.0) requests.append(req) # print the initial SoC print("SoC =", str(Fleet.soc)) FORCAST = Fleet.forecast(requests) # generate a forecast print("SoC =", str(Fleet.soc)) # make sure that the forecast function does not change the SoC # print the forecasted achivable power schedule for i in range(97): rsp = FORCAST[i] print("P =", str(rsp.P_injected)) # process the requests for req in requests: Fleet.process_request(req.sim_step, req.P_req, req.Q_req) print("SoC =", str(Fleet.soc)) # show that process_request function updates the SoC
def request( self, ts, sim_step, p, q=0.0): # added input variables; what's the purpose of sim_step?? fleet_request = FleetRequest(ts=ts, sim_step=sim_step, p=p, q=0.0) fleet_response = self.fleet.process_request(fleet_request) #print(fleet_response.P_service) return fleet_request, fleet_response
def integration_test(Fleet): # Establish the test variables n = 24 del_t = timedelta(hours=1.0) #dt = del_t.total_seconds() SoC0 = copy.copy(numpy.mean(Fleet.soc)) #t = numpy.linspace(0, (n - 1), n) EffMatrix = numpy.zeros((n, n)) ts = datetime.utcnow() print(n) for i in numpy.arange(0, n): print(i) if i == 1: print(i) for j in numpy.arange(0, n): if i != j: #Fleet = BatteryInverterFleet('config_ERM.ini') #Fleet.soc = SoC0 # initialize SoC Power = numpy.zeros(n) # initialize Power Power[i] = Fleet.max_power_charge * Fleet.num_of_devices Power[j] = Fleet.max_power_discharge * Fleet.num_of_devices # simulate the system with SoC0 and Power requests requests = [] for T in numpy.arange(0, n): req = FleetRequest(ts, del_t, Power[T], 0.0) requests.append(req) responses = Fleet.forecast(requests) for T in numpy.arange(0, n): Power[T] = responses[T].P_service SoCFin = responses[n - 1].soc # get final SoC [P2, Cost, Able] = Fleet.cost( SoCFin, SoC0, del_t ) # calculate how much power it would take to return to SoC0 P2Charge = max(P2, 0) P2Discharge = min(P2, 0) if (Power[i] + P2Charge) != 0: EffMatrix[i, j] = -(Power[j] + P2Discharge) / ( Power[i] + P2Charge ) # calculate efficiency DISCHARGE_ENERGY / CHARGE_ENERGY else: EffMatrix[i, j] = 0 if Able == 0: EffMatrix[i, j] = 0 print(EffMatrix) with open('EffMatrix.csv', 'w') as csvfile: writer = csv.writer(csvfile, delimiter=",") writer.writerows(EffMatrix)
def create_base_request(self, ts = datetime(2017, 1, 1, 00, 0, 00, 000000), hrs = 24, sim_step = timedelta(hours = 1)): """ Method to create a list of requests with P_req = None to call the forecast method of the fleet and obtain the API variables that are used by the energy market service class """ requests = [] for i in range(hrs): req = FleetRequest(ts+i*sim_step, sim_step, ts, None, 0.) requests.append(req) return requests
def setUpClass(self): #This method instantiates the fleet and executes a simple request to get the device response for evaluation # Create test fleet kwargs = {} kwargs['start_time'] = start_time kwargs['service_weight'] = 0.75 kwargs['sim_step'] = delt grid_type = 1 fleet = create_fleet(fleet_name, grid_type, **kwargs) if fleet is None: raise 'Could not create fleet with name ' + fleet_name fleet_request = FleetRequest(cur_time, delt, start_time, Prequest, Qrequest) fleet_response = fleet.process_request(fleet_request) self.response = fleet_response
def request_loop(self, start_time, sim_step): responses = [] #inittime = parser.parse("2018-10-12 00:00:00") #delt = timedelta(seconds=2 / 60) delt = sim_step cur_time = start_time end_time = cur_time + timedelta(seconds=149) while cur_time < end_time: fleet_request = FleetRequest(cur_time, delt, start_time) fleet_response = self.fleet_device.process_request(fleet_request) # fleet_response = self.fleet_device.frequency_watt(fleet_request) responses.append(fleet_response) cur_time += delt print("{}".format(cur_time)) return responses
def main(ts, grid): # Instantiation of an object of the ElectricVehiclesFleet class fleet_test = ElectricVehiclesFleet(grid, ts) dt = 1 # time step (in seconds) sim_step = timedelta(seconds = dt) seconds_of_simulation = 149 # (in seconds) local_time = fleet_test.get_time_of_the_day(ts) t = np.arange(local_time,local_time+seconds_of_simulation,dt) # array of time in seconds # Power requested (kW): test power_request = np.empty(len(t), dtype=object) fleet_test.is_autonomous = True fleet_test.is_P_priority = False # List of requests requests = [] for i in range(len(t)): req = FleetRequest(ts+i*sim_step, sim_step, ts, power_request[i], 0.) requests.append(req) # power and frequency empty lists p = [] f = [] e_in = [] i = 0 SOC_time = np.zeros([fleet_test.N_SubFleets, len(t)]) for req in requests: r = fleet_test.process_request(req) p.append(r.P_service) f.append(grid.get_frequency(req.ts_req, 0, req.start_time)) e_in.append(r.Eff_charge) print('t = %s' %str(req.ts_req)) print('service power is = %f MW at f = %f Hz' %(p[i]/1e3, f[i])) SOC_time[:,i] = fleet_test.SOC i+=1 p = np.array(p) f = np.array(f) e_in = np.array(e_in) return t-t[0], f, p/1000, e_in
def setUpClass(self): # This method instantiates the fleet and executes a simple request to get the device response for evaluation # Create test fleet from grid_info_artificial_inertia import GridInfo grid = GridInfo('Grid_Info_data_artificial_inertia.csv') grid_type = 2 kwargs = {} kwargs['start_time'] = start_time kwargs['service_weight'] = 0.75 kwargs['sim_step'] = delt kwargs['autonomous'] = 'autonomous' cur_time = start_time + timedelta(seconds=75) fleet = create_fleet(fleet_name, grid_type, **kwargs) if fleet is None: raise 'Could not create fleet with name ' + fleet_name fleet_request = FleetRequest(cur_time, delt, start_time, Prequest, Qrequest) fleet_response = fleet.process_request(fleet_request) self.response = fleet_response self.f = grid.get_frequency(cur_time, 0, start_time)
def integration_test(): # Establish the test variables n = 24 dt = 1 SoC0 = 50 # t = numpy.linspace(0, (n - 1), n) EffMatrix = numpy.zeros((n, n)) ts = datetime.utcnow() print(n) for i in numpy.arange(0, n): for j in numpy.arange(0, n): if i != j: Fleet = BatteryInverterFleet() Fleet.soc = SoC0 # initialize SoC Power = numpy.zeros(n) # initialize Power Power[i] = Fleet.max_power_charge Power[j] = Fleet.max_power_discharge # simulate the system with SoC0 and Power requests for T in numpy.arange(0, n): req = FleetRequest(ts,dt,Power[T],0.0) Fleet.process_request(req.sim_step, req.P_req, req.Q_req) SoCFin = Fleet.soc # get final SoC [P2, Cost, Able] = Fleet.cost(SoCFin, SoC0, dt) # retreeve how much power it would take to return to SoC0 P2Charge = max(P2,0) P2Discharge = min(P2,0) EffMatrix[i, j] = -(Power[j] +P2Discharge)/ ( Power[i] + P2Charge) # calculate efficiency DISCHARGE_ENERGY / CHARGE_ENERGY if P2<0: print('err') if Able == 0: EffMatrix[i, j] = 0 print(EffMatrix)
def fleet_test1(fleet): p_data = loadmat(join(base_path, 'pdata.mat'), squeeze_me=True) # Power request p_req = p_data['PF'] # Create fleet request fleet.is_autonomous = False fleet.FW21_Enabled = False fleet.is_P_priority = True ts = datetime.utcnow() dt = timedelta(seconds=1) fleet_request = [ FleetRequest(ts=(ts + i * dt), sim_step=dt, start_time=ts, p=v, q=0.) for i, v in enumerate(p_req) ] # Process the request P_togrid, Q_togrid, soc, P_service, P_base, P_service_max, P_service_min, ts = [], [], [], [], [], [], [], [] for fr in fleet_request: fleet_response = fleet.process_request(fr) P_togrid.append(fleet_response.P_togrid) Q_togrid.append(fleet_response.Q_togrid) P_service.append(fleet_response.P_service) soc.append(fleet_response.E) P_base.append(fleet_response.P_base) P_service_max.append(fleet_response.P_service_max) P_service_min.append(fleet_response.P_service_min) ts.append(fleet_response.ts) # Generate the impact metrics file fleet.output_metrics('impact_metrics_%s' % str(datetime.utcnow().strftime('%d_%b_%Y_%H_%M_%S'))) # Plot the results fig1, y1 = subplots(figsize=(20, 12)) y1.plot(ts, p_req, label='p_req') y1.plot(ts, P_service, label='P_service', alpha=0.5) y1.plot(ts, P_base, label='P_base') y1.set_ylabel('P(kW)') y1.set_xlabel('DateTime (mm-dd H:M:S)') y1.legend() grid() show() fig1.savefig(join( base_path, "FC_result_ALL_P_%s.png" % str(datetime.utcnow().strftime('%d_%b_%Y_%H_%M_%S'))), bbox_inches='tight') kwargs = { 'P_request': (p_req, 'kW'), 'P_togrid': (P_togrid, 'kW'), 'P_service': (P_service, 'kW'), 'P_base': (P_base, 'kW'), 'SoC': (soc, '%'), 'P_service_max': (P_service_max, 'kW'), 'P_service_min': (P_service_min, 'kW') } fleet.static_plots(**kwargs) fig1, y1 = subplots(figsize=(20, 12)) p1, = y1.plot(ts, p_req, label='P_request') p2, = y1.plot(ts, P_togrid, label='P_togrid') p2a, = y1.plot(ts, P_service, label='P_service') y1.set_ylabel('P(kW)') y2 = y1.twinx() p3, = y2.plot(ts, array(soc) * 1e2, label='SoC', color='g') y2.set_ylabel('SoC(%)') plots = [p1, p2, p2a, p3] y1.set_xlabel('DateTime (mm-dd H:M:S)') y1.legend(plots, [l.get_label() for l in plots]) grid() show() fig1.savefig(join( base_path, "FC_result_All_Ps_%s.png" % str(datetime.utcnow().strftime('%d_%b_%Y_%H_%M_%S'))), bbox_inches='tight')
def fleet_test2(fleet): # Create fleet request fleet.is_autonomous = True fleet.FW21_Enabled = True fleet.is_P_priority = False ts = datetime.utcnow() dt = timedelta(seconds=1) fleet_request = [ FleetRequest(ts=(ts + i * dt), sim_step=dt, start_time=ts, p=None, q=None) for i in range(149) ] # Process the request P_togrid, Q_togrid, soc, P_service, P_base, P_service_max, P_service_min, ts, f = \ [], [], [], [], [], [], [], [], [] for fr in fleet_request: fleet_response = fleet.process_request(fr) f.append(grid_dat.get_frequency(fr.ts_req, 0, fr.start_time)) P_togrid.append(fleet_response.P_togrid) Q_togrid.append(fleet_response.Q_togrid) P_service.append(fleet_response.P_service) soc.append(fleet_response.E) P_base.append(fleet_response.P_base) P_service_max.append(fleet_response.P_service_max) P_service_min.append(fleet_response.P_service_min) ts.append(fleet_response.ts) print("P_togrid Rx", P_togrid[len(P_togrid) - 1]) print("P_service Rx", P_service[len(P_service) - 1]) # Generate the impact metrics file fleet.output_metrics('impact_metrics_%s' % str(datetime.utcnow().strftime('%d_%b_%Y_%H_%M_%S'))) # Plot the results fig1, y1 = subplots(figsize=(20, 12)) p1, = y1.plot(f, label='Frequency', color='g') y1.set_ylabel('Hz') y2 = y1.twinx() p2, = y2.plot(array(P_togrid) / 240, label='P_togrid') y2.set_ylabel('Power Consumption (p.u.)') plots = [p1, p2] y1.set_xlabel('Time (s)') y1.legend(plots, [l.get_label() for l in plots]) grid() show() fig1.savefig(join( base_path, "FC_result_P_grid_%s.png" % str(datetime.utcnow().strftime('%d_%b_%Y_%H_%M_%S'))), bbox_inches='tight') fig2, y2 = subplots(figsize=(20, 12)) y2.scatter(f, array(P_togrid) / 240, label='P_togrid') y2.set_ylabel('Power Consumption(p.u.)') y2.set_xlabel('Hz') grid() show() fig2.savefig(join( base_path, "FC_result_P_service_%s.png" % str(datetime.utcnow().strftime('%d_%b_%Y_%H_%M_%S'))), bbox_inches='tight')
def request_loop(self, start_time, service_name, fleet_name="PVInverterFleet"): cycle = 24 ndx_start = 0 ndx_end = ndx_start + cycle #device_ts = # normalizes drive cycle and scales to fleet service capacity self.drive_cycle.load_forecast_mw *= self.fleet.assigned_service_kW()/max(self.drive_cycle.load_forecast_mw) # Find the "annual" peak (largest peak in our drive cycle really) and the desired new peak... #self.annual_peak = max(self.drive_cycle.load_forecast_mw) self.annual_peak = max(self.drive_cycle.load_forecast_mw) self.mw_target = self.annual_peak * (1 - self.f_reduction) requests = [] responses = [] # while ndx_end < len(self.drive_cycle.dt): # Loop over days... while ndx_end <= len(self.drive_cycle.dt): # Loop over days... dt_day = self.drive_cycle.dt[ndx_start:ndx_end] dt_day.reset_index(drop=True, inplace=True) mw_day = self.drive_cycle.load_forecast_mw[ndx_start:ndx_end] mw_day.reset_index(drop=True, inplace=True) p_needed = [max(0, mw_day[i] - self.mw_target) for i in range(cycle)] for index, item in enumerate(p_needed): if item == 0: p_needed[index] = None ndx_start += 24 ndx_end += 24 # No need to work on days without high peaks #if max(mw_day) <= self.mw_target: for i in range(24): for j in range(int(3600/self.sim_step.seconds)): fleet_request = FleetRequest(ts=dt_day[i]+j*self.sim_step, sim_step=self.sim_step, start_time=start_time, p=p_needed[i]) fleet_response = self.fleet.process_request(fleet_request) # store requests and responses requests.append(fleet_request) responses.append(fleet_response) print(responses[-1].P_service) ''' else: # Get a 24-hour forecast from fleet forecast_requests = [FleetRequest(ts=dt_day[i], sim_step=self.sim_step, p=p_needed[i]) for i in range(cycle)] forecast_response = self.fleet.forecast(forecast_requests) # See if the forecast can meet the desired load deficit = [forecast_response[i].P_service - p_needed[i] for i in range(24)] insufficient = [deficit[i] < 0 for i in range(cycle)] if any(insufficient): # TODO: NEED TO LOOP BACK AND REBUILD requests until we have a 24-hour request we know can be met pass # Now we know what the fleet can do, so ask it to do it for i in range(24): fleet_request = FleetRequest(ts=dt_day[i], sim_step=self.sim_step, start_time=start_time, p=forecast_response[i].P_service) fleet_response = self.fleet.process_request(fleet_request) # TODO: store performance stats requests.append(fleet_request) responses.append(fleet_response) print(responses[-1].P_service) ''' request_list_1h = [] for r in requests: if r.P_req is not None: request_list_1h.append((r.ts_req, r.P_req / 1000)) else: request_list_1h.append((r.ts_req, r.P_req)) request_df_1h = pd.DataFrame(request_list_1h, columns=['Date_Time', 'Request']) if 'battery' in fleet_name.lower(): # Include battery SoC in response list for plotting purposes response_list_1h = [(r.ts, r.P_service / 1000, r.P_togrid, r.P_base, r.soc) for r in responses] response_df_1h = pd.DataFrame(response_list_1h, columns=['Date_Time', 'Response', 'P_togrid', 'P_base', 'SoC']) else: response_list_1h = [(r.ts, np.nan if r.P_service is None else r.P_service / 1000, r.P_togrid, r.P_base) for r in responses] response_df_1h = pd.DataFrame(response_list_1h, columns=['Date_Time', 'Response', 'P_togrid','P_base']) # This merges/aligns the requests and responses dataframes based on their time stamp # into a single dataframe df_1h = pd.merge( left=request_df_1h, right=response_df_1h, how='left', left_on='Date_Time', right_on='Date_Time') df_1h['P_togrid'] = df_1h['P_togrid'] / 1000 df_1h['P_base'] = df_1h['P_base'] / 1000 # Plot entire analysis period results and save plot to file # We want the plot to cover the entire df_1h dataframe plot_dir = join(dirname(dirname(dirname(abspath(__file__)))), 'integration_test', service_name) ensure_ddir(plot_dir) plot_filename = 'SimResults_PeakManagement_' + fleet_name + '_' + datetime.now().strftime('%Y%m%dT%H%M') + '.png' plt.figure(1) plt.figure(figsize=(15, 8)) plt.subplot(311) if not(all(pd.isnull(df_1h['Request']))): plt.plot(df_1h.Date_Time, df_1h.Request, label='P_Request', linestyle = '-') if not(all(pd.isnull(df_1h['Response']))): plt.plot(df_1h.Date_Time, df_1h.Response, label='P_Response', linestyle = '--') plt.ylabel('Power (MW)') plt.legend() plt.subplot(312) if not(all(pd.isnull(df_1h['P_base']))): plt.plot(df_1h.Date_Time, df_1h.P_base + df_1h.Request, label='P_base + P_Request', linestyle = '-') if not(all(pd.isnull(df_1h['P_togrid']))): plt.plot(df_1h.Date_Time, df_1h.P_togrid, label='P_togrid', linestyle = '--') if not(all(pd.isnull(df_1h['P_base']))): plt.plot(df_1h.Date_Time, df_1h.P_base, label='P_base', linestyle = '-.') plt.ylabel('Power (MW)') plt.legend() if 'battery' is not fleet_name.lower(): plt.xlabel('Time') if 'battery' in fleet_name.lower(): if not(all(pd.isnull(df_1h['SoC']))): plt.subplot(313) plt.plot(df_1h.Date_Time, df_1h.SoC, label='SoC', linestyle = '-') plt.ylabel('SoC (%)') plt.xlabel('Time') plt.savefig(join(plot_dir, plot_filename), bbox_inches='tight') plt.close() # compute and report metrics to csv perf_metrics = pd.DataFrame(columns=['Service_efficacy']) temp_df_1h = df_1h.dropna() perf_metrics['Service_efficacy'] = pd.Series(min(1,abs(temp_df_1h.Response).sum()/abs(temp_df_1h.Request).sum())) metrics_filename = 'Performance_PeakManagement_' + fleet_name + '_' + datetime.now().strftime('%Y%m%dT%H%M') + '.csv' perf_metrics.to_csv(join(plot_dir, metrics_filename) ) # report results to csv results_filename = 'Results_PeakManagement_' + fleet_name + '_' + datetime.now().strftime('%Y%m%dT%H%M') + '.csv' df_1h.to_csv(join(plot_dir, results_filename) )
def fleet_test(Fleet,Grid): mat = spio.loadmat('ERM_model_validation.mat', squeeze_me=True) t = mat['TT'] P = Fleet.num_of_devices* mat['PP']*Fleet.p_rated n = 300#len(t) Pach = numpy.zeros((n)) Qach = numpy.zeros((n)) f = numpy.zeros((n,2)) v = numpy.zeros((n,2)) requests = [] ts = datetime.utcnow() dt = timedelta(hours=0.000277777778) #hours for i in range(n): req = FleetRequest(ts=(ts+i*dt),sim_step=dt,p=P[i],q=None) requests.append(req) idd = 0 Fleet.is_autonomous=False Fleet.VV11_Enabled=False Fleet.FW21_Enabled=False Fleet.is_P_priority=False for idd, req in enumerate(requests): res=Fleet.process_request(req) Pach[idd] = res.P_togrid Qach[idd] = res.Q_togrid ts=res.ts f[idd,0] = Grid.get_frequency(ts,0) f[idd,1] = Grid.get_frequency(ts,1) v[idd,0] = Grid.get_voltage(ts,0) v[idd,1] = Grid.get_voltage(ts,1) print('iteration # ',idd,' of total number of iteration ',n,' (',100*idd/n,'% complete)') # if numpy.mod(idd,10000) == 0: #print('iteration # ',idd,' of total number of iteration ',n,' (',100*idd/n,'% complete)') # idd+=1 # res=Fleet.forecast(req) # for req in requests: # res=Fleet.forecast(req) # print(res.P_togrid_max) # Pach[i] = res.P_togrid_max # Qach[i] = res.Q_togrid_max # f[i,0] = Grid.get_frequency(ts+i*dt,0) # f[i,1] = Grid.get_frequency(ts+i*dt,1) # v[i,0] = Grid.get_voltage(ts+i*dt,0) # v[i,1] = Grid.get_voltage(ts+i*dt,1) # # if numpy.mod(i,10000) == 0: # print(str(100*i/n) + ' %') Pach[i] = res.P_togrid Qach[i] = res.Q_togrid f[i,0] = Grid.get_frequency(ts+i*dt,0) f[i,1] = Grid.get_frequency(ts+i*dt,1) v[i,0] = Grid.get_voltage(ts+i*dt,0) v[i,1] = Grid.get_voltage(ts+i*dt,1) plt.figure(1) plt.subplot(211) plt.plot(t[0:n], P[0:n], label='Power Requested') plt.plot(t[0:n], Pach, label='Power Achieved by Fleet') plt.xlabel('Time (hours)') plt.ylabel('Real Power (kW)') plt.legend(loc='lower right') plt.subplot(212) plt.plot(t[0:n],60.036*numpy.ones(n)) plt.plot(t[0:n],59.964*numpy.ones(n)) plt.plot(t[0:n],f[0:n,0], label='Grid Frequency') #plt.plot(t[0:n],100*S[0:n], label='Recorded SoC') plt.xlabel('Time (hours)') plt.ylabel('frequency (Hz)') #plt.legend(loc='lower right') plt.figure(2) plt.subplot(211) plt.plot(t[0:n], Qach, label='Reactive Power Achieved by Fleet') plt.ylabel('Reactive Power (kvar)') plt.legend(loc='lower right') plt.subplot(212) plt.plot(t[0:n],240*(1-.03)*numpy.ones(n)) plt.plot(t[0:n],240*(1-.001)*numpy.ones(n)) plt.plot(t[0:n],240*(1+.001)*numpy.ones(n)) plt.plot(t[0:n],240*(1+.03)*numpy.ones(n)) plt.plot(t[0:n], v[0:n,0], label='Voltage at location 1') plt.plot(t[0:n], v[0:n,1], label='Voltage at location 2') plt.xlabel('Time (hours)') plt.ylabel('Voltage (V)') plt.legend(loc='lower right') plt.show()
def request_loop(self, sensitivity_P=0.0001, sensitivity_Q=0.0005, start_time=parser.parse("2017-08-01 16:00:00"), end_time=parser.parse("2017-08-01 17:00:00")): # Sensitivity_P, Sensitivity_Q are values depending on feeder characteristics # We can use dummy value to conduct test #sensitivity_P = 0.001 #sensitivity_Q = 0.005 assigned_service_kW = self._fleet.assigned_service_kW() assigned_service_kVar = self._fleet.assigned_service_kW() cur_time = start_time #end_time = endtime delt = self.sim_step volt = self.drive_cycle["voltage"] time = self.drive_cycle["time"] List_Time = list(time.values) dts = maya.parse(start_time).datetime() - maya.parse( List_Time[0]).datetime() dts = (dts).total_seconds() Vupper = self.Vupper Vlower = self.Vlower responses = [] requests = [] while cur_time < end_time: # normal operation for n in range(len(list(time.values))): dta = maya.parse(List_Time[n]).datetime() dtb = maya.parse(cur_time).datetime() - timedelta(seconds=dts) if dta == dtb: index = n # index = list(time.values).index(cur_time) cur_voltage = volt.values[index] #cur_voltage = 1.055 if cur_voltage >= self.Vlower and cur_voltage <= self.Vupper: Prequest = 0 Qrequest = 0 else: if cur_voltage > Vupper: dV = Vupper - cur_voltage Qrequest = -dV / sensitivity_Q # need Q absorption if Qrequest < -1 * assigned_service_kVar: Qrequest = -1 * assigned_service_kVar Prequest = -dV / sensitivity_P # need P curtailment if Prequest < -1 * assigned_service_kW: Prequest = -1 * assigned_service_kW elif cur_voltage < Vlower: dV = Vlower - cur_voltage Qrequest = dV / sensitivity_Q # need Q injection if Qrequest < assigned_service_kVar: Qrequest = -1 * assigned_service_kVar Prequest = dV / sensitivity_P # need P injection if Prequest < assigned_service_kW: Prequest = -assigned_service_kW fleet_request = FleetRequest(ts=cur_time, sim_step=delt, p=Prequest, q=Qrequest) fleet_response = self.fleet.process_request(fleet_request) responses.append(fleet_response) requests.append(fleet_request) cur_time += delt print("{}".format(cur_time)) Qach = numpy.zeros((len(responses))) Pach = numpy.zeros((len(responses))) # Time[idd]=res.ts ts_request = [r.ts for r in responses] Pach = [r.P_togrid for r in responses] Qach = [r.Q_togrid for r in responses] Pservice = [r.P_service for r in responses] Qservice = [r.Q_service for r in responses] Preq = [r.P_req for r in requests] Qreq = [r.Q_req for r in requests] fig = plt.figure(1) plt.subplot(211) plt.plot(ts_request, Preq, label='Req.') plt.plot(ts_request, Pach, label='Achieved') plt.plot(ts_request, Pservice, label='Service') plt.xlabel('Time') plt.ylabel('kW') plt.title('Fleet Active Power') plt.legend(loc='lower right') plt.subplot(212) plt.plot(ts_request, Qreq, label='Req.') plt.plot(ts_request, Qach, label='Achieved') plt.plot(ts_request, Qservice, label='Service') #plt.plot(t[0:n],100*S[0:n], label='Recorded SoC') plt.xlabel('Time') plt.ylabel('kVar') plt.title('Fleet Reactive Power') plt.legend(loc='lower right') data_folder = os.path.dirname(sys.modules['__main__'].__file__) plot_filename = datetime.now().strftime( '%Y%m%d' ) + '_VoltageRegulation_FleetResponse_' + self.fleet.__class__.__name__ + '.png' File_Path_fig = join(data_folder, 'integration_test', 'voltage_regulation', plot_filename) plt.savefig(File_Path_fig, bbox_inches='tight') # File_Path_fig = os.path.join(self.base_path , 'VR_Fleet_Response.png') # fig.savefig(File_Path_fig) #plt.legend(loc='lower right') plt.close ServiceEefficacy = [] ValueProvided = [] ValueEfficacy = [] CSV_FileName = datetime.now().strftime( '%Y%m%d' ) + '_Voltage_Regulation_' + self.fleet.__class__.__name__ + '.csv' data_folder = os.path.dirname(sys.modules['__main__'].__file__) File_Path_CSV = join(data_folder, 'integration_test', 'Voltage_Regulation', CSV_FileName) self.write_csv(File_Path_CSV, 'Time', 'service efficacy (%)', 'value provided ($)', 'value efficacy (%)') for idd in range(len(Pach)): service_efficacy, value_provided, value_efficacy = self.calculation( Prequest=Preq[idd], Qrequest=Qreq[idd], P0=Pach[idd], Q0=Qach[idd], price_P=1, price_Q=1) ServiceEefficacy.append(service_efficacy) ValueProvided.append(value_provided) ValueEfficacy.append(value_efficacy) self.write_csv(File_Path_CSV, ts_request[idd], service_efficacy, value_provided, value_efficacy) fig, axs = plt.subplots(3, 1) axs[0].plot(ts_request, ServiceEefficacy) axs[0].set_title('ServiceEefficacy') #axs[0].set_xlabel('distance (m)') axs[0].set_ylabel('%') fig.suptitle('Service Metrics', fontsize=16) axs[1].plot(ts_request, ValueProvided) #axs[1].set_xlabel('time (s)') axs[1].set_title('ValueProvided') axs[1].set_ylabel('$') axs[2].plot(ts_request, ValueEfficacy) #axs[1].set_xlabel('time (s)') axs[2].set_title('ValueEfficacy') axs[2].set_ylabel('%') plot_filename = datetime.now().strftime( '%Y%m%d') + '_VoltageRegulation_ServiceMetrics' + '.png' File_Path_fig = join(data_folder, 'integration_test', 'voltage_regulation', plot_filename) plt.savefig(File_Path_fig, bbox_inches='tight') plt.show() return [requests, responses]
def fleet_test(Fleet): mat = spio.loadmat('ERM_model_validation.mat', squeeze_me=True) t = mat['TT'] P = -Fleet.num_of_devices * mat['PP'] S = mat['SS'] n = len(S) #len(t) t = t[numpy.arange(1000, n - 1000, 45)] P = P[numpy.arange(1000, n - 1000, 45)] * 0 S = S[numpy.arange(1000, n - 1000, 45)] n = len(t) print(n) Pach = numpy.zeros((n)) Qach = numpy.zeros((n)) f = numpy.zeros((n, 2)) v = numpy.zeros((n, 2)) SOC = numpy.zeros((n, Fleet.num_of_devices)) #V = numpy.zeros(n) requests = [] ts = datetime.utcnow() dt = timedelta(hours=(0.000277777778 * 45 / 3)) #hours for i in range(n): req = FleetRequest(ts=(ts + i * dt), sim_step=dt, p=P[i], q=None) requests.append(req) """ # print the initial SoC print("SoC =", str(Fleet.soc)) FORCAST = Fleet.forecast(requests) # generate a forecast print("SoC =", str(Fleet.soc)) # make sure that the forecast function does not change the SoC """ # print the forecasted achivable power schedule """ for i in range(n): rsp = FORCAST[i] P[i] = rsp.P_service """ # process the requests i = 0 for req in requests[:n]: Fleet.process_request(req) Pach[i] = sum(Fleet.P_service) Qach[i] = sum(Fleet.Q_service) f[i, 0] = Grid.get_frequency(ts + i * dt, 0) f[i, 1] = Grid.get_frequency(ts + i * dt, 1) v[i, 0] = Grid.get_voltage(ts + i * dt, 0) v[i, 1] = Grid.get_voltage(ts + i * dt, 1) """ if v[i] < 100: print(str(100*i/n) + ' %') """ if numpy.mod(i, numpy.floor(n / 20)) == 0: print(str(100 * i / n) + ' %') for j in range(Fleet.num_of_devices): SOC[i, j] = Fleet.soc[ j] # show that process_request function updates the SoC #V[i] = Fleet.vbat i = i + 1 plt.figure(1) plt.subplot(211) plt.plot(t[0:n], P[0:n], label='Power Requested') plt.plot(t[0:n], Pach, label='Power Achieved by Fleet') plt.xlabel('Time (hours)') plt.ylabel('Real Power (kW)') plt.legend(loc='lower right') plt.subplot(212) plt.plot(t[0:n], f[0:n, 0], label='Grid Frequency') #plt.plot(t[0:n],100*S[0:n], label='Recorded SoC') plt.xlabel('Time (hours)') plt.ylabel('frequency (Hz)') #plt.legend(loc='lower right') plt.figure(2) plt.subplot(211) plt.plot(t[0:n], Qach, label='Reactive Power Achieved by Fleet') plt.ylabel('Reactive Power (kvar)') plt.legend(loc='lower right') plt.subplot(212) plt.plot(t[0:n], v[0:n, 0], label='Voltage at location 1') plt.plot(t[0:n], v[0:n, 1], label='Voltage at location 2') plt.xlabel('Time (hours)') plt.ylabel('Voltage (V)') plt.legend(loc='lower right') plt.show()
from fleet_config import FleetConfig if __name__ == '__main__': haf = HomeAcFleet() # Init simulation time frame start_time = datetime.utcnow() end_time = datetime.utcnow() + timedelta(hours=3) # Create requests for each hour in simulation time frame cur_time = start_time sim_time_step = timedelta(hours=1) fleet_requests = [] while cur_time < end_time: req = FleetRequest(ts=cur_time, sim_step=sim_time_step, p=1000, q=1000) fleet_requests.append(req) cur_time += sim_time_step # Use case 1 res = haf.process_request(fleet_requests[0]) print(res) # Use case 2 forecast = haf.forecast(fleet_requests) print(forecast) # Use case 3 fleet_config = FleetConfig(is_P_priority=True, is_autonomous=False, autonomous_threshold=0.1) haf.change_config(fleet_config)
fleet_test.is_P_priority = True dt = 5*60 # time step (in seconds) sim_step = timedelta(seconds = dt) seconds_of_simulation = 24*3600 # (in seconds) local_time = fleet_test.get_time_of_the_day(ts) t = np.arange(local_time,local_time+seconds_of_simulation,dt) # array of time in seconds # Power requested (kW): test power_request = 50000*(1 + np.sin(2*np.pi*(t/seconds_of_simulation))) # power_request = np.zeros([len(t), ]) # List of requests requests = [] for i in range(len(t)): req = FleetRequest(ts+i*sim_step, sim_step, ts, power_request[i], 0.) requests.append(req) print("SOC init = ", fleet_test.SOC) # Measure cpu time cpu_time = time.clock() FORECAST = fleet_test.forecast(requests) cpu_time = (time.clock() - cpu_time)/len(t) # check that the state of charge do not change when calling the forecast method print("SOC check = ", fleet_test.SOC) print("CPU time per time step = %f [sec]" %cpu_time) power_service = [] max_power_service = [] power_response = [] energy_stored = np.zeros([len(t),])
def request(self, ts, sim_step, start_time, p, q=0.0): fleet_request = FleetRequest(ts=ts, sim_step=sim_step, start_time=start_time, p=p, q=0.0) fleet_response = self.fleet.process_request(fleet_request) return fleet_request, fleet_response
def main(): #Test case: Run a forecast for the day of July 26th #Configure the simulation to be run. Need to set the number of timesteps, start time, and the length of the timestep (in minutes) Steps = 24 #num steps in simulation, if greater than 1 assuming a forecast is being requested Timestep = 1 / 60. #minutes, NOTE, MUST BE A DIVISOR OF 60. Acceptable numbers are: 0.1, 0.2, 0.5, 1,2,3,4,5,6,10,12,15,20,30, 60, etc. allowable_timesteps = [1 / 60.,0.1, 0.2, 0.5, 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60] if Timestep not in allowable_timesteps: print("Timestep must be a divisor of 60") return starttime = 206*24 # 0-8759, hour of the year to start simulation if Steps > 1: forecast = 1 else: forecast = 0 Q_request = 0 # reactive power request, water heater can't provide reactive power Timestep = datetime.timedelta(minutes=Timestep) startday = (starttime // 24) + 1 monthindex = [[1,31],[2,59],[3,90],[4,120],[5,151],[6,181],[7,212],[8,243],[9,273],[10,304],[11,334],[12,365]] #doesn't account for leap years for m in monthindex: if startday <= m[1]: startmonth = m[0] break if startmonth > 1: startday -= monthindex[(m[0]-2)][1] starthour = starttime % 24 StartTime = datetime.datetime(2018,startmonth,startday,starthour) grid = GridInfo('Grid_Info_Data_2.csv') ######################################################################## #generate load request signal and regulation # NOTE: code is set up to deal with capacity separately from regulation, the only interface is in the capacity signal there is a single timestep # where regulation is called, the entire code switches into regulation mode for that single timestep (which is much longer than a regulation timestep) # when the calculations are complete, it returns conditions to be used for subsequent capacity timesteps P_request = [] FleetResponse = [0] for step in range(Steps): capacity_needed = 1e6 # capacity_needed = 1e6 + 2e5*random.random()#Watts needed, >0 is capacity add, <0 is capacity shed # Fleet_size_represented = capacity_needed/4500 # approximately how many WH would be needed to be able to provide this capacity # magnitude_load_add_shed = capacity_needed/Fleet_size_represented #def magnitude of request for load add/shed if step % 12 == 0 or step % 12 == 1 or step % 12 == 2: # this is my aribtrary but not random way of creating load add/shed events. should be replaced with a more realistic signal at some point if step > 1: s = -capacity_needed else: # service = ['none',0] s = 0 elif step % 7 == 0 or step % 7 == 1: s = capacity_needed else: s = 0 P_request.append(s) ############################################################################ # Call fleet #creating service request object ServiceRequest = FleetRequest(StartTime, Timestep, P_request, Q_request) # initializing fleet fleet = WaterHeaterFleet(grid,StartTime,Timestep) #calling fleet FleetResponse = fleet.process_request(ServiceRequest) #Gather data to plot and look at the results #for y in range FleetResponse[0].AvailableCapacityAdd: #for x in range(len(FleetResponse)): # for y in range FleetResponse[0].AvailableCapacityAdd: ############################################################################ #Plotting load add/shed responses for n in range(len(FleetResponse.IsAvailableAdd)): plt.figure(n+1) plt.clf() plt.plot(FleetResponse.IsAvailableAdd[n],'r*-',label = 'AvailAdd') plt.plot(FleetResponse.IsAvailableShed[n],'bs-',label = 'AvailShed') plt.ylabel('Availability') plt.xlabel('step') plt.title('Water Heater {} Availability'.format(n+1)) plt.legend() plt.ylim([-1,2]) plt.show() for n in range(len(FleetResponse.IsAvailableAdd)): plt.figure(n+1) plt.clf() plt.plot(FleetResponse.Tset[n],'r*-',label = 'Tset') plt.plot(FleetResponse.Ttank[n],'bs-',label = 'Ttank') plt.ylabel('Temperature (F)') plt.xlabel('step') plt.title('Water Heater {} Setpoint and tank temperature'.format(n+1)) plt.legend() plt.ylim([100,160]) plt.show() for n in range(len(FleetResponse.IsAvailableAdd)): plt.figure(n+1) plt.clf() plt.plot(FleetResponse.IsAvailableAdd[n],'r*-',label = 'AvailAdd') plt.plot(FleetResponse.IsAvailableShed[n],'bs-',label = 'AvailShed') plt.ylabel('Availability') plt.xlabel('step') plt.title('Water Heater {} Availability'.format(n+1)) plt.legend() plt.ylim([-1,2]) plt.show()
def fleet_test(Fleet,fig,writer): mat = spio.loadmat('ERM_model_validation.mat', squeeze_me=True) t = mat['TT'] P = -Fleet.num_of_devices* mat['PP'] S = mat['SS'] n = len(S)#len(t) t = t[numpy.arange(1000,n-1000,45)] P = P[numpy.arange(1000,n-1000,45)] S = S[numpy.arange(1000,n-1000,45)] n = len(t) print(n) Pach = numpy.zeros((n)) Qach = numpy.zeros((n)) f = numpy.zeros((n,2)) v = numpy.zeros((n,2)) SOC = numpy.zeros((n,Fleet.num_of_devices)) #V = numpy.zeros(n) requests = [] ts = datetime.utcnow() dt = timedelta(hours=(0.000277777778*45/3)) #hours for i in range(n): req = FleetRequest(ts=(ts+i*dt),sim_step=dt,p=P[i],q=None) requests.append(req) """ # print the initial SoC print("SoC =", str(Fleet.soc)) FORCAST = Fleet.forecast(requests) # generate a forecast print("SoC =", str(Fleet.soc)) # make sure that the forecast function does not change the SoC """ # print the forecasted achivable power schedule """ for i in range(n): rsp = FORCAST[i] P[i] = rsp.P_service """ # process the requests i = 0 for req in requests[:n-10]: writer.grab_frame() Fleet.process_request(req) Pach[i] = sum(Fleet.P_service) Qach[i] = sum(Fleet.Q_service) """ f[i,0] = Grid.get_frequency(ts+i*dt,0) f[i,1] = Grid.get_frequency(ts+i*dt,1) v[i,0] = Grid.get_voltage(ts+i*dt,0) v[i,1] = Grid.get_voltage(ts+i*dt,1) """ """ if v[i] < 100: print(str(100*i/n) + ' %') """ if numpy.mod(i,numpy.floor(n/20)) == 0: print(str(100*i/n) + ' %') for j in range(Fleet.num_of_devices): SOC[i,j] = Fleet.soc[j] # show that process_request function updates the SoC #V[i] = Fleet.vbat i = i + 1 fig.set_figheight(5) yield t, Pach, P, f, v, SOC, S*100, i """ plt.figure(1)