├── BEDA.m ├── Battery_LA.m ├── Battery_LI.m ├── Capacity_fading.m ├── DE.m ├── DR_demo.m ├── Dispatch_obj_LI_DE.m ├── Dispatch_obj_LI_DE_parallel.m ├── Dispatch_obj_LI_DE_v2.m ├── Dispatch_obj_LI_DE_v2_output.m ├── Dispatch_obj_LI_DE_v3.m ├── Dispatch_obj_LI_DE_v4_DPSP.m ├── Dispatch_obj_LI_DE_v5_varySOC.m ├── Dispatch_opt_CVX.m ├── Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_basecase.mat ├── Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowPV.mat ├── Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowWT.mat ├── Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowWTandPV.mat ├── Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_peakyLoad.mat ├── Dispatch_opt_nsnw_DG8kW_wP_DEmin_basecase.mat ├── Dispatch_opt_nsnw_noP_DEmin_basecase.mat ├── Dispatch_opt_nsnw_noP_DEmin_lowPV.mat ├── Dispatch_opt_nsnw_noP_DEmin_lowWT.mat ├── Dispatch_opt_nsnw_noP_DEmin_lowWTandPV.mat ├── Dispatch_opt_nsnw_wP_DEmin_basecase.mat ├── Dispatch_opt_v2.m ├── Dispatch_opt_v3_varySOC.m ├── HOMER_comparison.homer ├── HOMER_comparison_default.homer ├── LI_DE_1h_DPSP.m ├── Load.mat ├── Load_day.mat ├── Load_week.mat ├── MT.m ├── Objective_LA_DE_v2_1h.m ├── Objective_LA_MT_v2_1h.m ├── Objective_LI_DE.m ├── Objective_LI_DE_v10_1h_ind_VaryParams_output.m ├── Objective_LI_DE_v2.asv ├── Objective_LI_DE_v2_1h.m ├── Objective_LI_DE_v2_1h_vectorized.m ├── Objective_LI_DE_v3_1h.m ├── Objective_LI_DE_v4_1h_convex.m ├── Objective_LI_DE_v5_1h_ind.m ├── Objective_LI_DE_v6_1h_indPrated.m ├── Objective_LI_DE_v7_1h_dispatch.m ├── Objective_LI_DE_v8_1h_optPrated.m ├── Objective_LI_DE_v9_1h_ind_VaryParams.m ├── Objective_LI_MT_v2_1h.m ├── Plots.asv ├── Plots.m ├── README.md ├── SOC_3d.png ├── Sizing_LI-DE_3equal123_paretosearch_Ps_Pw_200pts_DG7kW.mat ├── Sizing_LI-DE_4equal_gamultiobj_Ps_Pw_fraction0.5_DG7kW.mat ├── Sizing_LI-DE_4equal_paretosearch_Ps_Pw_200pts_DG7kW.mat ├── Sizing_LI-DE_5equal_gamultiobj_Ps_Pw_fraction0.5.mat ├── Sizing_LI-DE_5equal_gamultiobj_Ps_Pw_fraction0.5_DG7kW.mat ├── Sizing_LI-DE_5equal_gamultiobj_ns_nw_fraction0.5.mat ├── Sizing_LI-DE_5equal_paretosearch_Ps_Pw_200pts.mat ├── Sizing_LI-DE_5equal_paretosearch_Ps_Pw_200pts_DG7kW.mat ├── Sizing_LI-DE_5equal_paretosearch_ns_nw_200pts.mat ├── Sizing_VaryParams.m ├── Sizing_Vary_BS_price.mat ├── Sizing_Vary_DE_Rating_0-20.mat ├── Sizing_Vary_DE_price.mat ├── Sizing_Vary_inflation.mat ├── Sizing_Vary_interest.mat ├── Sizing_Vary_w1.mat ├── Sizing_Vary_w2.mat ├── Sizing_Vary_w3.mat ├── Sizing_Vary_w3_DGrated_7kW.mat ├── Sizing_Vary_w4.mat ├── Sizing_Vary_w5.mat ├── Sizing_opt.m ├── Sizing_opt_v2.m ├── Sizing_opt_v3.m ├── Sizing_result_gen.m ├── Solar.m ├── VarySOC_base_1d.mat ├── VarySOC_base_3d.mat ├── VarySOC_peakyLoad.mat ├── Wind.m ├── irradiance.mat ├── irradiance_low.mat ├── load_peaky.mat ├── load_shift_curtail.mat ├── load_shift_v2.mat ├── positive.m ├── sizing_pareto.m ├── temp.mat ├── test_simulation.m ├── wind_speed.mat └── wind_speed_low.mat /BEDA.m: -------------------------------------------------------------------------------- 1 | TAC = 17097; 2 | LCOE_grid = 0.125; 3 | CRF = 0.0582; 4 | C_ext = 157470; 5 | load('Load.mat'); 6 | P_load = sum(sum(Load)); 7 | BEDA_val = (TAC - (LCOE_grid * P_load))/(C_ext*CRF) -------------------------------------------------------------------------------- /Battery_LA.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Battery_LA.m -------------------------------------------------------------------------------- /Battery_LI.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Battery_LI.m -------------------------------------------------------------------------------- /Capacity_fading.m: -------------------------------------------------------------------------------- 1 | %% LI 2 | Eb_init = 100; 3 | E_C = zeros(1,5475); 4 | E_C(1) = Eb_init; 5 | cycles_LI = 1; 6 | cycles = 0:1:5474; 7 | 8 | for i = 2:1:5475 9 | E_C(i) = Eb_init*(1 - (cycles_LI*0.055e-3)); 10 | cycles_LI = cycles_LI+1; 11 | end 12 | 13 | plot(cycles,E_C); -------------------------------------------------------------------------------- /DE.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/DE.m -------------------------------------------------------------------------------- /DR_demo.m: -------------------------------------------------------------------------------- 1 | % Demand response program implementation 2 | % Follow the model used in that one good paper I read in detail 3 | % Maximize net benefit to grid operator with a set budget to compensate customers 4 | % Start with simple network with only a few representative loads and then make it more complex -------------------------------------------------------------------------------- /Dispatch_obj_LI_DE.m: -------------------------------------------------------------------------------- 1 | function [cost, soc_LI, DPSP, P_dump, P_lost, P_load, P_w, P_s, P_RES] = Dispatch_obj_LI_DE(P_DE, P_b_LI) 2 | % Optimal dispatch of DE and BS on a day-ahead basis - Using inbuilt MATLAB solvers 3 | % Initial attempt: No MPC, static optimization over finite horizon based on certain/known historical load/climate data i.e. similar to LQR 4 | % But in reality, need some form of receding horizon MPC since controller doesn't have access to future climate/load data! 5 | 6 | % Assuming that any excess DE power cannot go towards charging battery 7 | % i.e. purpose of DE is only to serve as backup to meet excess load 8 | % P_DE and P_b_LI are 1x24 vectors 9 | 10 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 11 | load('temp.mat'); % Ambient air temperature (C) 12 | load('wind_speed.mat'); % (m/s) 13 | load('Load_day.mat'); % Hourly power (kW) demand profile for a single representative day 14 | 15 | % Optimal sizing results using 5 equal weights - from v2 16 | % Oversize RES (round up n_s and n_w to nearest integer) and storage capacity 17 | n_s = 15.1187; 18 | n_w = 4.3061; 19 | Eb_init = 106.5333; % (kWh) 20 | 21 | % Discretize 1 day into 1 h time intervals 22 | delta_t = 3600; % Calculation period (s) = 1 h 23 | 24 | P_s = zeros(1,24); % (kW) 25 | P_w = zeros(1,24); % (kW) 26 | P_RES = zeros(1,24); % (kW) 27 | P_dump = zeros(1,24); % Excess power (RES output) sent to dump loads/ground (kW) 28 | soc_LI = zeros(1,25); 29 | DE_ON = zeros(1,24); % Boolean variable to keep track of whether DE is online/committed 30 | P_lost = zeros(1,24); % Lost load (later -- DR) 31 | P_load = zeros(1,24); 32 | 33 | % Startup and shutdown costs of conventional generators 34 | DE_startup = 0; 35 | DE_shutdown = 0; 36 | 37 | % Fuel costs 38 | C_fuel_DE = 0; 39 | 40 | % Fixed system parameters 41 | % SOLAR 42 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 43 | % For 255 W system - Monocrystalline Si 44 | eta_r = 0.154; % Manufacturer rated efficiency 45 | T_r = 25; % Standard test conditions (reference cell temperature) 46 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 47 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 48 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 49 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 50 | Ps_rated = 255; % Rated max power of each module (W) 51 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 52 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 53 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 54 | OM_s = (1/100)*(IC_s/365); % Fixed daily O&M costs ($/y) - from Kaabeche et al. 2011a 55 | 56 | % WIND 57 | beta_w = 1/7; % Typical value of power law exponent for open land 58 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 59 | h_ref = 1; % Installation height of TAHMO measurement stations (m) 60 | h_hub = 14.5; % Tower height to hub/nacelle (m) 61 | Pw_rated = 3.5; % Rated power of each WT (kW) 62 | Pw_rated_total = n_w * Pw_rated; 63 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 64 | OM_w = (3/100)*(IC_w/365); % Fixed daily O&M costs ($/y) 65 | v_c = 2.8; % Cut-in speed (m/s) 66 | v_r = 11; % Rated wind speed (m/s) 67 | v_f = 22; % Cut-out or failure speed (m/s) 68 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 69 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 70 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 71 | 72 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 73 | SOC_min_LI = 0.1; 74 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 75 | delta = 0.075; % Self-discharge rate of battery (%/month) 76 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 77 | IC_LI = 300 * Eb_init; 78 | OM_LI = (1/100) * (IC_LI/365); % Fixed daily O&M cost from Kaabeche et al. 2011a ($/y) 79 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 80 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 81 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 82 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 83 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 84 | 85 | % Diesel generator specs from Moshi et al. 2016 86 | P_DE_rated = 16; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 87 | P_DE_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 88 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 89 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 90 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 91 | IC_DE = 12500; % Initial capital cost ($) 92 | Fixed_OM_DE = (2/100)*(IC_DE/365); % Fixed daily O&M costs ($/d) 93 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 94 | SUC_DE = 0.45; % Start-up cost ($/kW) 95 | SDC_DE = 0.23; % Shut-down cost ($) 96 | 97 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 98 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 99 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 100 | t_inv = 20; % Lifetime of converter 101 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 102 | 103 | P_load = Load_day; 104 | 105 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 106 | CO2 = 0.649 * sum(P_load); 107 | CO = 4.063288937 * sum(P_load); 108 | NOx = 18.85658039 * sum(P_load); 109 | SO2 = 0.007381439 * sum(P_load); 110 | VOC = 1.502443664 * sum(P_load); 111 | PM = 1.338208931 * sum(P_load); 112 | PM10 = 1.338208931 * sum(P_load); 113 | PM25 = 1.338208931 * sum(P_load); 114 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 115 | 116 | CO2 = 0; 117 | 118 | for t = 1:1:24 119 | % SOLAR 120 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 121 | T_a = temp(t); 122 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 123 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 124 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 125 | 126 | if (P_s(t) > Ps_rated_total) 127 | P_s(t) = Ps_rated_total; 128 | end 129 | 130 | % WIND 131 | v_ref = wind_speed(t); 132 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 133 | 134 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 135 | if (v_hub < v_c || v_hub > v_f) 136 | P_w(t) = 0; 137 | elseif (v_c <= v_hub && v_hub <= v_r) 138 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 139 | else 140 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 141 | end 142 | 143 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 144 | 145 | if (t == 1) 146 | soc_LI(t) = 0.9; 147 | end 148 | 149 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 150 | cycles_LI = cycles_LI + 1; % Increment cycle number 151 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 152 | end 153 | 154 | % Lower limit on P_DE or not 155 | if (P_DE(t) >= 1e-4) % DE online during hour t (P_DE_min or 1e-4) 156 | DE_ON(t) = 1; 157 | end 158 | 159 | % To enforce lower limit constraint on P_DE 160 | % if (P_DE(t) < P_DE_min) 161 | % P_DE(t) = 0; 162 | % %DE_ON(t) = 0; 163 | % end 164 | 165 | if (DE_ON(1) == 1) 166 | DE_startup = DE_startup + SUC_DE; 167 | end 168 | 169 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 170 | DE_startup = DE_startup + SUC_DE; 171 | end 172 | 173 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 174 | DE_shutdown = DE_shutdown + SDC_DE; 175 | end 176 | 177 | fuel_DE = 0.08145 * P_DE_rated + 0.246 * P_DE(t); 178 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 179 | CO2 = CO2 + 0.649 * P_DE(t); 180 | 181 | % Battery dynamics 182 | % P_b_LI +ve -> Discharging 183 | % P_b_LI -ve -> Charging 184 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 185 | 186 | if (P_RES(t) == P_load(t)/eta_inv) 187 | continue 188 | elseif (P_RES(t) > P_load(t)/eta_inv) % Excess supply 189 | % Need to rectify AC DE output before sending to DC bus for dump loads 190 | % P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); % Sign of P_b_LI takes care of both charge/discharge cases 191 | 192 | P_dump(t) = P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv; 193 | 194 | % if (P_b_LI(t) >= 0) % Battery is discharged - Power output 195 | % P_dump(t) = P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv; 196 | % else % Battery is charged - Power input 197 | % P_dump(t) = P_RES(t) - abs(P_b_LI(t)) + P_DE(t)*eta_rec - P_load(t)/eta_inv; 198 | % end 199 | else % Excess demand 200 | Excess_demand = P_load(t) - P_RES(t) * eta_inv; 201 | % P_lost(t) = max(0, Excess_demand - P_DE(t) - P_b_LI(t)); 202 | % P_dump(t) = max(0, (P_DE_min - Excess_demand) * eta_rec); 203 | 204 | P_lost(t) = Excess_demand - P_DE(t) - (P_b_LI(t) * eta_inv); 205 | %P_dump(t) = (P_DE_min - Excess_demand) * eta_rec; 206 | P_dump(t) = (P_DE_min - Excess_demand + (P_b_LI(t) * eta_inv)) * eta_rec; 207 | % if (P_b_LI(t) >= 0) % Battery is discharged 208 | % P_lost(t) = Excess_demand - P_DE(t)*eta_rec - P_b_LI(t); 209 | % P_dump(t) = max(0, P_DE_min - Excess_demand/eta_rec); 210 | % else % Battery is charged 211 | % P_lost(t) = Excess_demand - P_DE(t)*eta_rec + abs(P_b_LI(t)); 212 | % P_dump(t) = max(0, P_DE_min - Excess_demand/eta_rec); 213 | % end 214 | 215 | end 216 | 217 | if (P_lost(t) < 0) 218 | P_lost(t) = 0; 219 | end 220 | 221 | if (P_dump(t) < 0) 222 | P_dump(t) = 0; 223 | end 224 | 225 | end 226 | 227 | CO = 4.063288937 * sum(P_DE); 228 | NOx = 18.85658039 * sum(P_DE); 229 | SO2 = 0.007381439 * sum(P_DE); 230 | VOC = 1.502443664 * sum(P_DE); 231 | PM = 1.338208931 * sum(P_DE); 232 | PM10 = 1.338208931 * sum(P_DE); 233 | PM25 = 1.338208931 * sum(P_DE); 234 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 235 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 236 | 237 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 238 | Cost = C_fuel_DE + Var_OM_DE + OM_s + OM_w + OM_LI + Fixed_OM_DE + DE_startup + DE_shutdown; 239 | E_gen = sum(P_DE .* eta_rec + P_RES); 240 | COE = Cost/sum(P_load); % Unit cost of electricity ($/kWh) - considering only real-time, operational costs 241 | 242 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 243 | Var_OM_DE = Variable_OM_DE * 24; 244 | fuel_DE = 24 * 0.08145 * P_DE_rated + 0.246 * sum(P_load); 245 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 246 | DE_startup = SUC_DE; 247 | DE_shutdown = SDC_DE; 248 | Cost_base = C_fuel_DE + Var_OM_DE + Fixed_OM_DE + DE_startup + DE_shutdown; 249 | COE_base = Cost_base/sum(P_load); 250 | 251 | DPSP = sum(P_lost)/sum(P_load); 252 | Dump = sum(P_dump)/E_gen; 253 | REF = sum(P_RES)/E_gen; 254 | 255 | % No longer need to min DPSP since it's a constraint 256 | Costs = [COE/COE_base Emissions Dump 1-REF]; 257 | w = [0.25 0.25 0.25 0.25]; % Weights of different cost terms 258 | cost = Costs * w'; 259 | 260 | end 261 | 262 | -------------------------------------------------------------------------------- /Dispatch_obj_LI_DE_parallel.m: -------------------------------------------------------------------------------- 1 | function [cost, soc_LI, DPSP] = Dispatch_obj_LI_DE_no_DR_parallel(P_DE, P_b_LI) 2 | % Using parallel computing toolbox to speed up calculations 3 | 4 | % Optimal dispatch of DE and BS on a day-ahead basis - Using inbuilt MATLAB solvers 5 | % Initial attempt: No MPC, static optimization over finite horizon based on certain/known historical load/climate data i.e. similar to LQR 6 | % But in reality, need some form of receding horizon MPC since controller doesn't have access to future climate/load data! 7 | 8 | % Assuming that any excess DE power cannot go towards charging battery 9 | % P_DE and P_b_LI are 1x24 vectors 10 | 11 | delete(gcp('nocreate')); 12 | parpool('local',4); 13 | poolobj = gcp; 14 | addAttachedFiles(poolobj,{'irradiance.mat','temp.mat','wind_speed.mat','Load_day.mat'}) 15 | 16 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 17 | load('temp.mat'); % Ambient air temperature (C) 18 | load('wind_speed.mat'); % (m/s) 19 | load('Load_day.mat'); % Hourly power (kW) demand profile for a single representative day 20 | 21 | % Optimal sizing results using 5 equal weights - from v2 22 | % Oversize RES (round up n_S and n_w to nearest integer) and storage capacity 23 | n_s = 119; 24 | n_w = 5; 25 | Eb_init = 4.82; % (kWh) 26 | 27 | % Discretize 1 day into 1 h time intervals 28 | delta_t = 3600; % Calculation period (s) = 1 h 29 | 30 | P_s = zeros(1,24); % (kW) 31 | P_w = zeros(1,24); % (kW) 32 | P_RES = zeros(1,24); % (kW) 33 | P_dump = zeros(1,24); % Excess power (RES output) sent to dump loads/ground (kW) 34 | soc_LI = zeros(1,25); 35 | DE_ON = zeros(1,24); % Boolean variable to keep track of whether DE is online/committed 36 | P_lost = zeros(1,24); % Lost load (later -- DR) 37 | P_load = zeros(1,24); 38 | 39 | % Startup and shutdown costs of conventional generators 40 | DE_startup = 0; 41 | DE_shutdown = 0; 42 | 43 | % Variable O&M costs of DE 44 | Var_OM_DE = 0; 45 | 46 | % Fuel costs 47 | C_fuel_DE = 0; 48 | CO2 = 0; 49 | 50 | % Fixed system parameters 51 | % SOLAR 52 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 53 | % For 255 W system - Monocrystalline Si 54 | eta_r = 0.154; % Manufacturer rated efficiency 55 | T_r = 25; % Standard test conditions (reference cell temperature) 56 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 57 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 58 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 59 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 60 | Ps_rated = 255; % Rated max power of each module (W) 61 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 62 | 63 | % WIND 64 | beta_w = 1/7; % Typical value of power law exponent for open land 65 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 66 | h_ref = 2; % Installation height of TAHMO measurement stations (m) 67 | h_hub = 14.5; % Tower height to hub/nacelle (m) 68 | Pw_rated = 3.5; % Rated power of each WT (kW) 69 | v_c = 2.8; % Cut-in speed (m/s) 70 | v_r = 11; % Rated wind speed (m/s) 71 | v_f = 22; % Cut-out or failure speed (m/s) 72 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 73 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 74 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 75 | 76 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 77 | SOC_min_LI = 0.1; 78 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 79 | delta = 0.075; % Self-discharge rate of battery (%/month) 80 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 81 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 82 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 83 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 84 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 85 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 86 | 87 | % Diesel generator specs from Moshi et al. 2016 88 | P_DE_rated = 16; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 89 | P_DE_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 90 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 91 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 92 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 93 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 94 | SUC_DE = 0.45; % Start-up cost ($/kW) 95 | SDC_DE = 0.23; % Shut-down cost ($) 96 | 97 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 98 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 99 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 100 | t_inv = 10; % Lifetime of converter 101 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 102 | 103 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 104 | fuel_DE = 24 * 0.06 * P_DE_rated + 0.0246 * sum(Load_day); 105 | CO2 = 3.5 * fuel_DE; 106 | CO = 4.063288937 * sum(Load_day); 107 | NOx = 18.85658039 * sum(Load_day); 108 | SO2 = 0.007381439 * sum(Load_day); 109 | VOC = 1.502443664 * sum(Load_day); 110 | PM = 1.338208931 * sum(Load_day); 111 | PM10 = 1.338208931 * sum(Load_day); 112 | PM25 = 1.338208931 * sum(Load_day); 113 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 114 | 115 | CO2 = 0; 116 | 117 | parfor t = 1:1:24 118 | % SOLAR 119 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 120 | T_a = temp(t); 121 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 122 | T_c = T_a + ((T_c_NOCT - 20)/0.8)*I; % Cell temp (C) 123 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 124 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 125 | 126 | % WIND 127 | v_ref = wind_speed(t); 128 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 129 | 130 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 131 | if (v_hub < v_c || v_hub > v_f) 132 | P_w(t) = 0; 133 | elseif (v_c <= v_hub && v_hub <= v_r) 134 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 135 | else 136 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 137 | end 138 | 139 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 140 | 141 | P_load(t) = Load_day(t); % (kW) 142 | 143 | fuel_DE = 0.06 * P_DE_rated + 0.0246 * P_DE(t); 144 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 145 | CO2 = CO2 + 3.5 * fuel_DE; 146 | 147 | if (P_RES(t) == P_load(t)/eta_inv) 148 | continue 149 | elseif (P_RES(t) > P_load(t)/eta_inv) 150 | % soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 151 | if (P_b_LI(t) >= 0) % Battery is discharged 152 | P_dump(t) = P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv; 153 | else % Battery is charged 154 | P_dump(t) = P_RES(t) - abs(P_b_LI(t)) + P_DE(t)*eta_rec - P_load(t)/eta_inv; 155 | end 156 | else 157 | % soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 158 | Excess_demand = P_load(t)/eta_inv - P_RES(t); 159 | if (P_b_LI(t) >= 0) % Battery is discharged 160 | P_lost(t) = Excess_demand - P_DE(t)*eta_rec - P_b_LI(t); 161 | P_dump(t) = max(0, P_DE_min - Excess_demand/eta_rec); 162 | else % Battery is charged 163 | P_lost(t) = Excess_demand - P_DE(t)*eta_rec - abs(P_b_LI(t)); 164 | P_dump(t) = max(0, P_DE_min - Excess_demand/eta_rec); 165 | end 166 | end 167 | end 168 | 169 | % Handle battery operations separately since parfor loop iterations must be independent 170 | % DE_ON variable can also introduce potential dependencies between iterations 171 | for t = 1:1:24 172 | if (P_DE(t) >= 1e-4) % DE online during hour t 173 | DE_ON(t)= 1; 174 | end 175 | 176 | if (DE_ON(1) == 1) 177 | DE_startup = DE_startup + SUC_DE; 178 | end 179 | 180 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 181 | DE_startup = DE_startup + SUC_DE; 182 | end 183 | 184 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 185 | DE_shutdown = DE_shutdown + SDC_DE; 186 | end 187 | 188 | if (t == 1) 189 | soc_LI(t) = 0.9; 190 | end 191 | 192 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 193 | cycles_LI = cycles_LI + 1; % Increment cycle number 194 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 195 | end 196 | % Battery dynamics 197 | % P_b_LI +ve -> Discharging 198 | % P_b_LI -ve -> Charging 199 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 200 | end 201 | 202 | CO = 4.063288937 * sum(P_DE); 203 | NOx = 18.85658039 * sum(P_DE); 204 | SO2 = 0.007381439 * sum(P_DE); 205 | VOC = 1.502443664 * sum(P_DE); 206 | PM = 1.338208931 * sum(P_DE); 207 | PM10 = 1.338208931 * sum(P_DE); 208 | PM25 = 1.338208931 * sum(P_DE); 209 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 210 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 211 | 212 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 213 | Cost = C_fuel_DE + Var_OM_DE; 214 | E_gen = sum(P_DE + P_RES); 215 | COE = Cost/E_gen; % Unit cost of electricity ($/kWh) 216 | 217 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 218 | Var_OM_DE = Variable_OM_DE * 8760; 219 | fuel_DE = 8760 * 0.06 * P_DE_rated + 0.0246 * sum(Load_day); 220 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 221 | Cost_base = Var_OM_DE + C_fuel_DE; 222 | COE_base = Cost_base/sum(Load_day); 223 | 224 | DPSP = sum(P_lost)/sum(Load_day); 225 | Dump = sum(P_dump)/E_gen; 226 | REF = sum(P_RES)/E_gen; 227 | 228 | Costs = [COE/COE_base Emissions DPSP Dump 1-REF]; 229 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 230 | cost = Costs * w'; 231 | 232 | 233 | -------------------------------------------------------------------------------- /Dispatch_obj_LI_DE_v2.m: -------------------------------------------------------------------------------- 1 | function [cost, soc_LI, DPSP, P_dump, P_lost, P_load, P_w, P_s, P_RES] = Dispatch_obj_LI_DE_v2(P_DE, P_b_LI) 2 | % Optimal dispatch of DE and BS on a day-ahead basis - Using inbuilt MATLAB solvers 3 | % Initial attempt: No MPC, static optimization over finite horizon based on certain/known historical load/climate data i.e. similar to LQR 4 | % But in reality, need some form of receding horizon MPC since controller doesn't have access to future climate/load data! 5 | 6 | % Assuming that any excess DE power cannot go towards charging battery 7 | % i.e. purpose of DE is only to serve as backup to meet excess load 8 | % P_DE and P_b_LI are 1x24 vectors 9 | 10 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 11 | load('temp.mat'); % Ambient air temperature (C) 12 | load('wind_speed.mat'); % (m/s) 13 | load('load_shift_v2.mat'); % Hourly power (kW) demand profile for a single representative day 14 | 15 | % Optimal sizing results using 5 equal weights - from v2 16 | % Oversize RES (round up n_s and n_w to nearest integer) and storage capacity 17 | % Using DG = 16 kW 18 | n_s = 15.1187; 19 | n_w = 4.3061; 20 | Eb_init = 106.5333; % (kWh) 21 | 22 | % Using DG = 8 kW 23 | % n_s = 8.0095; 24 | % n_w = 4.6226; 25 | % Eb_init = 118.1596; % (kWh) 26 | 27 | % Discretize 1 day into 1 h time intervals 28 | delta_t = 3600; % Calculation period (s) = 1 h 29 | 30 | P_s = zeros(1,24); % (kW) 31 | P_w = zeros(1,24); % (kW) 32 | P_RES = zeros(1,24); % (kW) 33 | P_dump = zeros(1,24); % Excess power (RES output) sent to dump loads/ground (kW) 34 | soc_LI = zeros(1,25); 35 | DE_ON = zeros(1,24); % Boolean variable to keep track of whether DE is online/committed 36 | P_lost = zeros(1,24); % Lost load AC 37 | P_load = zeros(1,24); 38 | 39 | % Startup and shutdown costs of conventional generators 40 | DE_startup = 0; 41 | DE_shutdown = 0; 42 | 43 | % Fuel costs 44 | C_fuel_DE = 0; 45 | 46 | % Fixed system parameters 47 | % SOLAR 48 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 49 | % For 255 W system - Monocrystalline Si 50 | eta_r = 0.154; % Manufacturer rated efficiency 51 | T_r = 25; % Standard test conditions (reference cell temperature) 52 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 53 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 54 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 55 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 56 | Ps_rated = 255; % Rated max power of each module (W) 57 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 58 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 59 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 60 | OM_s = (1/100)*(IC_s/365); % Fixed daily O&M costs ($/y) - from Kaabeche et al. 2011a 61 | 62 | % WIND 63 | beta_w = 1/7; % Typical value of power law exponent for open land 64 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 65 | h_ref = 1; % Installation height of TAHMO measurement stations (m) 66 | h_hub = 14.5; % Tower height to hub/nacelle (m) 67 | Pw_rated = 3.5; % Rated power of each WT (kW) 68 | Pw_rated_total = n_w * Pw_rated; 69 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 70 | OM_w = (3/100)*(IC_w/365); % Fixed daily O&M costs ($/y) 71 | v_c = 2.8; % Cut-in speed (m/s) 72 | v_r = 11; % Rated wind speed (m/s) 73 | v_f = 22; % Cut-out or failure speed (m/s) 74 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 75 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 76 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 77 | 78 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 79 | SOC_min_LI = 0.1; 80 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 81 | delta = 0.075; % Self-discharge rate of battery (%/month) 82 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 83 | IC_LI = 300 * Eb_init; 84 | OM_LI = (1/100) * (IC_LI/365); % Fixed daily O&M cost from Kaabeche et al. 2011a ($/y) 85 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 86 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 87 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 88 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 89 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 90 | 91 | % Diesel generator specs from Moshi et al. 2016 92 | P_DE_rated = 8; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 93 | P_DE_min = 0.3*P_DE_rated; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 94 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 95 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 96 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 97 | IC_DE = (12500/16)*P_DE_rated; % Initial capital cost ($) 98 | Fixed_OM_DE = (2/100)*(IC_DE/365); % Fixed daily O&M costs ($/d) 99 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 100 | SUC_DE = 0.45; % Start-up cost ($/kW) 101 | SDC_DE = 0.23; % Shut-down cost ($) 102 | 103 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 104 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 105 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 106 | t_inv = 20; % Lifetime of converter 107 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 108 | 109 | P_load = load_shift_v2; 110 | 111 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 112 | CO2 = 0.649 * sum(P_load); 113 | CO = 4.063288937 * sum(P_load); 114 | NOx = 18.85658039 * sum(P_load); 115 | SO2 = 0.007381439 * sum(P_load); 116 | VOC = 1.502443664 * sum(P_load); 117 | PM = 1.338208931 * sum(P_load); 118 | PM10 = 1.338208931 * sum(P_load); 119 | PM25 = 1.338208931 * sum(P_load); 120 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 121 | 122 | CO2 = 0; 123 | 124 | for t = 1:1:24 125 | % SOLAR 126 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 127 | T_a = temp(t); 128 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 129 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 130 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 131 | 132 | if (P_s(t) > Ps_rated_total) 133 | P_s(t) = Ps_rated_total; 134 | end 135 | 136 | % WIND 137 | v_ref = wind_speed(t); 138 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 139 | 140 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 141 | if (v_hub < v_c || v_hub > v_f) 142 | P_w(t) = 0; 143 | elseif (v_c <= v_hub && v_hub <= v_r) 144 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 145 | else 146 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 147 | end 148 | 149 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 150 | 151 | if (t == 1) 152 | soc_LI(t) = 0.9; 153 | end 154 | 155 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 156 | cycles_LI = cycles_LI + 1; % Increment cycle number 157 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 158 | end 159 | 160 | % Lower limit on P_DE or not 161 | if (P_DE(t) >= P_DE_min) % DE online during hour t (P_DE_min or 1e-4) 162 | DE_ON(t) = 1; 163 | end 164 | 165 | % To enforce lower limit constraint on P_DE 166 | if (P_DE(t) < P_DE_min) 167 | P_DE(t) = 0; 168 | end 169 | 170 | if (DE_ON(1) == 1) 171 | DE_startup = DE_startup + SUC_DE; 172 | end 173 | 174 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 175 | DE_startup = DE_startup + SUC_DE; 176 | end 177 | 178 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 179 | DE_shutdown = DE_shutdown + SDC_DE; 180 | end 181 | 182 | fuel_DE = 0.08145 * P_DE_rated + 0.246 * P_DE(t); 183 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 184 | CO2 = CO2 + 0.649 * P_DE(t); 185 | 186 | % Battery dynamics 187 | % P_b_LI +ve -> Discharging 188 | % P_b_LI -ve -> Charging 189 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 190 | 191 | if (P_RES(t) == P_load(t)/eta_inv) 192 | continue 193 | elseif (P_RES(t) > P_load(t)/eta_inv) % Excess supply 194 | % Need to rectify AC DE output before sending to DC bus for dump loads 195 | P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); % Sign of P_b_LI takes care of both charge/discharge case 196 | else % Excess demand (AC) 197 | Excess_demand = P_load(t) - (P_RES(t) * eta_inv); 198 | P_lost(t) = max(0, Excess_demand - P_DE(t) - (P_b_LI(t) * eta_inv)); % AC 199 | P_dump(t) = max(0, (P_DE_min - Excess_demand + (P_b_LI(t) * eta_inv)) * eta_rec); % DC 200 | end 201 | end 202 | 203 | CO = 4.063288937 * sum(P_DE); 204 | NOx = 18.85658039 * sum(P_DE); 205 | SO2 = 0.007381439 * sum(P_DE); 206 | VOC = 1.502443664 * sum(P_DE); 207 | PM = 1.338208931 * sum(P_DE); 208 | PM10 = 1.338208931 * sum(P_DE); 209 | PM25 = 1.338208931 * sum(P_DE); 210 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 211 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 212 | 213 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 214 | Cost = C_fuel_DE + Var_OM_DE + OM_s + OM_w + OM_LI + Fixed_OM_DE + DE_startup + DE_shutdown; 215 | E_gen = sum(P_DE * eta_rec + P_RES); 216 | COE = Cost/sum(P_load); % Unit cost of electricity ($/kWh) - considering only real-time, operational costs 217 | 218 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 219 | Var_OM_DE = Variable_OM_DE * 24; 220 | fuel_DE = 24 * 0.08145 * P_DE_rated + 0.246 * sum(P_load); 221 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 222 | DE_startup = SUC_DE; 223 | DE_shutdown = SDC_DE; 224 | Cost_base = C_fuel_DE + Var_OM_DE + Fixed_OM_DE + DE_startup + DE_shutdown; 225 | COE_base = Cost_base/sum(P_load); 226 | 227 | DPSP = sum(P_lost)/sum(P_load); 228 | Dump = sum(P_dump)/E_gen; 229 | REF = sum(P_RES)/E_gen; 230 | 231 | % No longer need to min DPSP since it's a constraint 232 | Costs = [COE/COE_base Emissions Dump 1-REF]; 233 | w = [0.25 0.25 0.25 0.25]; % Weights of different cost terms 234 | cost = Costs * w'; 235 | 236 | end 237 | -------------------------------------------------------------------------------- /Dispatch_obj_LI_DE_v2_output.m: -------------------------------------------------------------------------------- 1 | function [Costs, DE_hours, BS_cycles] = Dispatch_obj_LI_DE_v2_output(P_DE, P_b_LI) 2 | % Outputs individual objectives 3 | 4 | % Assuming that any excess DE power cannot go towards charging battery 5 | % i.e. purpose of DE is only to serve as backup to meet excess load 6 | % P_DE and P_b_LI are 1x24 vectors 7 | 8 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 9 | load('temp.mat'); % Ambient air temperature (C) 10 | load('wind_speed.mat'); % (m/s) 11 | load('Load_day.mat'); % Hourly power (kW) demand profile for a single representative day 12 | 13 | % Optimal sizing results using 5 equal weights - from v2 14 | % Using DG = 16 kW 15 | % n_s = 15.1187; 16 | % n_w = 4.3061; 17 | % Eb_init = 106.5333; % (kWh) 18 | 19 | % Using DG = 8 kW 20 | n_s = 8.0095; 21 | n_w = 4.6226; 22 | Eb_init = 118.1596; % (kWh) 23 | 24 | % Discretize 1 day into 1 h time intervals 25 | delta_t = 3600; % Calculation period (s) = 1 h 26 | 27 | P_s = zeros(1,24); % (kW) 28 | P_w = zeros(1,24); % (kW) 29 | P_RES = zeros(1,24); % (kW) 30 | P_dump = zeros(1,24); % Excess power (RES output) sent to dump loads/ground (kW) 31 | soc_LI = zeros(1,25); 32 | DE_ON = zeros(1,24); % Boolean variable to keep track of whether DE is online/committed 33 | P_lost = zeros(1,24); % Lost load AC 34 | P_load = zeros(1,24); 35 | 36 | % Startup and shutdown costs of conventional generators 37 | DE_startup = 0; 38 | DE_shutdown = 0; 39 | 40 | % Fuel costs 41 | C_fuel_DE = 0; 42 | 43 | % Fixed system parameters 44 | % SOLAR 45 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 46 | % For 255 W system - Monocrystalline Si 47 | eta_r = 0.154; % Manufacturer rated efficiency 48 | T_r = 25; % Standard test conditions (reference cell temperature) 49 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 50 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 51 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 52 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 53 | Ps_rated = 255; % Rated max power of each module (W) 54 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 55 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 56 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 57 | OM_s = (1/100)*(IC_s/365); % Fixed daily O&M costs ($/y) - from Kaabeche et al. 2011a 58 | 59 | % WIND 60 | beta_w = 1/7; % Typical value of power law exponent for open land 61 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 62 | h_ref = 1; % Installation height of TAHMO measurement stations (m) 63 | h_hub = 14.5; % Tower height to hub/nacelle (m) 64 | Pw_rated = 3.5; % Rated power of each WT (kW) 65 | Pw_rated_total = n_w * Pw_rated; 66 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 67 | OM_w = (3/100)*(IC_w/365); % Fixed daily O&M costs ($/y) 68 | v_c = 2.8; % Cut-in speed (m/s) 69 | v_r = 11; % Rated wind speed (m/s) 70 | v_f = 22; % Cut-out or failure speed (m/s) 71 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 72 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 73 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 74 | 75 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 76 | SOC_min_LI = 0.1; 77 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 78 | delta = 0.075; % Self-discharge rate of battery (%/month) 79 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 80 | IC_LI = 300 * Eb_init; 81 | OM_LI = (1/100) * (IC_LI/365); % Fixed daily O&M cost from Kaabeche et al. 2011a ($/y) 82 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 83 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 84 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 85 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 86 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 87 | 88 | % Diesel generator specs from Moshi et al. 2016 89 | P_DE_rated = 8; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 90 | P_DE_min = 0.3*P_DE_rated; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 91 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 92 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 93 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 94 | IC_DE = 12500; % Initial capital cost ($) 95 | Fixed_OM_DE = (2/100)*(IC_DE/365); % Fixed daily O&M costs ($/d) 96 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 97 | SUC_DE = 0.45; % Start-up cost ($/kW) 98 | SDC_DE = 0.23; % Shut-down cost ($) 99 | 100 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 101 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 102 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 103 | t_inv = 20; % Lifetime of converter 104 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 105 | 106 | P_load = Load_day; 107 | 108 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 109 | CO2 = 0.649 * sum(P_load); 110 | CO = 4.063288937 * sum(P_load); 111 | NOx = 18.85658039 * sum(P_load); 112 | SO2 = 0.007381439 * sum(P_load); 113 | VOC = 1.502443664 * sum(P_load); 114 | PM = 1.338208931 * sum(P_load); 115 | PM10 = 1.338208931 * sum(P_load); 116 | PM25 = 1.338208931 * sum(P_load); 117 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 118 | 119 | CO2 = 0; 120 | 121 | for t = 1:1:24 122 | % SOLAR 123 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 124 | T_a = temp(t); 125 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 126 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 127 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 128 | 129 | if (P_s(t) > Ps_rated_total) 130 | P_s(t) = Ps_rated_total; 131 | end 132 | 133 | % WIND 134 | v_ref = wind_speed(t); 135 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 136 | 137 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 138 | if (v_hub < v_c || v_hub > v_f) 139 | P_w(t) = 0; 140 | elseif (v_c <= v_hub && v_hub <= v_r) 141 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 142 | else 143 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 144 | end 145 | 146 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 147 | 148 | if (t == 1) 149 | soc_LI(t) = 0.9; 150 | end 151 | 152 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 153 | cycles_LI = cycles_LI + 1; % Increment cycle number 154 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 155 | end 156 | 157 | P_load(t) = Load_day(t); % (kW) 158 | 159 | % Lower limit on P_DE or not 160 | if (P_DE(t) >= P_DE_min) % DE online during hour t (P_DE_min or 1e-4) 161 | DE_ON(t) = 1; 162 | end 163 | 164 | % To enforce lower limit constraint on P_DE 165 | if (P_DE(t) < P_DE_min) 166 | P_DE(t) = 0; 167 | end 168 | 169 | if (DE_ON(1) == 1) 170 | DE_startup = DE_startup + SUC_DE; 171 | end 172 | 173 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 174 | DE_startup = DE_startup + SUC_DE; 175 | end 176 | 177 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 178 | DE_shutdown = DE_shutdown + SDC_DE; 179 | end 180 | 181 | fuel_DE = 0.08145 * P_DE_rated + 0.246 * P_DE(t); 182 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 183 | CO2 = CO2 + 0.649 * P_DE(t); 184 | 185 | % Battery dynamics 186 | % P_b_LI +ve -> Discharging 187 | % P_b_LI -ve -> Charging 188 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 189 | 190 | if (P_RES(t) == P_load(t)/eta_inv) 191 | continue 192 | elseif (P_RES(t) > P_load(t)/eta_inv) % Excess supply 193 | % Need to rectify AC DE output before sending to DC bus for dump loads 194 | P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); % Sign of P_b_LI takes care of both charge/discharge case 195 | else % Excess demand (AC) 196 | Excess_demand = P_load(t) - (P_RES(t) * eta_inv); 197 | P_lost(t) = max(0, Excess_demand - P_DE(t) - (P_b_LI(t) * eta_inv)); % AC 198 | P_dump(t) = max(0, (P_DE_min - Excess_demand + (P_b_LI(t) * eta_inv)) * eta_rec); % DC 199 | end 200 | end 201 | 202 | CO = 4.063288937 * sum(P_DE); 203 | NOx = 18.85658039 * sum(P_DE); 204 | SO2 = 0.007381439 * sum(P_DE); 205 | VOC = 1.502443664 * sum(P_DE); 206 | PM = 1.338208931 * sum(P_DE); 207 | PM10 = 1.338208931 * sum(P_DE); 208 | PM25 = 1.338208931 * sum(P_DE); 209 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 210 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 211 | 212 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 213 | Cost = C_fuel_DE + Var_OM_DE + OM_s + OM_w + OM_LI + Fixed_OM_DE + DE_startup + DE_shutdown; 214 | E_gen = sum(P_DE * eta_rec + P_RES); 215 | COE = Cost/sum(P_load); % Unit cost of electricity ($/kWh) - considering only real-time, operational costs 216 | 217 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 218 | Var_OM_DE = Variable_OM_DE * 24; 219 | fuel_DE = 24 * 0.08145 * P_DE_rated + 0.246 * sum(P_load); 220 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 221 | DE_startup = SUC_DE; 222 | DE_shutdown = SDC_DE; 223 | Cost_base = C_fuel_DE + Var_OM_DE + Fixed_OM_DE + DE_startup + DE_shutdown; 224 | COE_base = Cost_base/sum(P_load); 225 | 226 | DPSP = sum(P_lost)/sum(P_load); 227 | Dump = sum(P_dump)/E_gen; 228 | REF = sum(P_RES)/E_gen; 229 | 230 | % No longer need to min DPSP since it's a constraint 231 | Costs = [COE/COE_base Emissions DPSP Dump 1-REF]; 232 | DE_hours = sum(DE_ON); 233 | BS_cycles = sum(cycles_LI); 234 | 235 | end 236 | -------------------------------------------------------------------------------- /Dispatch_obj_LI_DE_v3.m: -------------------------------------------------------------------------------- 1 | function [cost, soc_LI, DPSP, P_dump, P_lost, P_load, P_w, P_s, P_RES] = Dispatch_obj_LI_DE_v3(P_DE, P_b_LI) 2 | % Optimal dispatch of DE and BS on a day-ahead basis - Using inbuilt MATLAB solvers 3 | % Initial attempt: No MPC, static optimization over finite horizon based on certain/known historical load/climate data i.e. similar to LQR 4 | % But in reality, need some form of receding horizon MPC since controller doesn't have access to future climate/load data! 5 | 6 | % Assuming that any excess DE power cannot go towards charging battery 7 | % i.e. purpose of DE is only to serve as backup to meet excess load 8 | % P_DE and P_b_LI are 1x24 vectors 9 | 10 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 11 | load('temp.mat'); % Ambient air temperature (C) 12 | load('wind_speed.mat'); % (m/s) 13 | load('load_shift_curtail.mat'); % Hourly power (kW) demand profile for a single representative day 14 | 15 | % Optimal sizing results using 5 equal weights - from v2 16 | % Oversize RES (round up n_s and n_w to nearest integer) and storage capacity 17 | % Using DG = 16 kW 18 | n_s = 15.1187; 19 | n_w = 4.3061; 20 | Eb_init = 106.5333; % (kWh) 21 | 22 | % Using DG = 8 kW 23 | % n_s = 8.0095; 24 | % n_w = 4.6226; 25 | % Eb_init = 118.1596; % (kWh) 26 | 27 | % Discretize 1 day into 1 h time intervals 28 | delta_t = 3600; % Calculation period (s) = 1 h 29 | 30 | P_s = zeros(1,24); % (kW) 31 | P_w = zeros(1,24); % (kW) 32 | P_RES = zeros(1,24); % (kW) 33 | P_dump = zeros(1,24); % Excess power (RES output) sent to dump loads/ground (kW) 34 | soc_LI = zeros(1,25); 35 | DE_ON = zeros(1,24); % Boolean variable to keep track of whether DE is online/committed 36 | P_lost = zeros(1,24); % Lost load AC 37 | P_load = zeros(1,24); 38 | 39 | % Startup and shutdown costs of conventional generators 40 | DE_startup = 0; 41 | DE_shutdown = 0; 42 | 43 | % Fuel costs 44 | C_fuel_DE = 0; 45 | 46 | % Fixed system parameters 47 | % SOLAR 48 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 49 | % For 255 W system - Monocrystalline Si 50 | eta_r = 0.154; % Manufacturer rated efficiency 51 | T_r = 25; % Standard test conditions (reference cell temperature) 52 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 53 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 54 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 55 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 56 | Ps_rated = 255; % Rated max power of each module (W) 57 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 58 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 59 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 60 | OM_s = (1/100)*(IC_s/365); % Fixed daily O&M costs ($/y) - from Kaabeche et al. 2011a 61 | 62 | % WIND 63 | beta_w = 1/7; % Typical value of power law exponent for open land 64 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 65 | h_ref = 1; % Installation height of TAHMO measurement stations (m) 66 | h_hub = 14.5; % Tower height to hub/nacelle (m) 67 | Pw_rated = 3.5; % Rated power of each WT (kW) 68 | Pw_rated_total = n_w * Pw_rated; 69 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 70 | OM_w = (3/100)*(IC_w/365); % Fixed daily O&M costs ($/y) 71 | v_c = 2.8; % Cut-in speed (m/s) 72 | v_r = 11; % Rated wind speed (m/s) 73 | v_f = 22; % Cut-out or failure speed (m/s) 74 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 75 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 76 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 77 | 78 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 79 | SOC_min_LI = 0.1; 80 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 81 | delta = 0.075; % Self-discharge rate of battery (%/month) 82 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 83 | IC_LI = 300 * Eb_init; 84 | OM_LI = (1/100) * (IC_LI/365); % Fixed daily O&M cost from Kaabeche et al. 2011a ($/y) 85 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 86 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 87 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 88 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 89 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 90 | 91 | % Diesel generator specs from Moshi et al. 2016 92 | P_DE_rated = 8; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 93 | P_DE_min = 0.3*P_DE_rated; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 94 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 95 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 96 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 97 | IC_DE = (12500/16)*P_DE_rated; % Initial capital cost ($) 98 | Fixed_OM_DE = (2/100)*(IC_DE/365); % Fixed daily O&M costs ($/d) 99 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 100 | SUC_DE = 0.45; % Start-up cost ($/kW) 101 | SDC_DE = 0.23; % Shut-down cost ($) 102 | 103 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 104 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 105 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 106 | t_inv = 20; % Lifetime of converter 107 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 108 | 109 | P_load = load_shift_curtail; 110 | 111 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 112 | CO2 = 0.649 * sum(P_load); 113 | CO = 4.063288937 * sum(P_load); 114 | NOx = 18.85658039 * sum(P_load); 115 | SO2 = 0.007381439 * sum(P_load); 116 | VOC = 1.502443664 * sum(P_load); 117 | PM = 1.338208931 * sum(P_load); 118 | PM10 = 1.338208931 * sum(P_load); 119 | PM25 = 1.338208931 * sum(P_load); 120 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 121 | 122 | CO2 = 0; 123 | 124 | for t = 1:1:24 125 | % SOLAR 126 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 127 | T_a = temp(t); 128 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 129 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 130 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 131 | 132 | if (P_s(t) > Ps_rated_total) 133 | P_s(t) = Ps_rated_total; 134 | end 135 | 136 | % WIND 137 | v_ref = wind_speed(t); 138 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 139 | 140 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 141 | if (v_hub < v_c || v_hub > v_f) 142 | P_w(t) = 0; 143 | elseif (v_c <= v_hub && v_hub <= v_r) 144 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 145 | else 146 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 147 | end 148 | 149 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 150 | 151 | if (t == 1) 152 | soc_LI(t) = 0.9; 153 | end 154 | 155 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 156 | cycles_LI = cycles_LI + 1; % Increment cycle number 157 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 158 | end 159 | 160 | % Lower limit on P_DE or not 161 | if (P_DE(t) >= P_DE_min) % DE online during hour t (P_DE_min or 1e-4) 162 | DE_ON(t) = 1; 163 | end 164 | 165 | % To enforce lower limit constraint on P_DE 166 | if (P_DE(t) < P_DE_min) 167 | P_DE(t) = 0; 168 | end 169 | 170 | if (DE_ON(1) == 1) 171 | DE_startup = DE_startup + SUC_DE; 172 | end 173 | 174 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 175 | DE_startup = DE_startup + SUC_DE; 176 | end 177 | 178 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 179 | DE_shutdown = DE_shutdown + SDC_DE; 180 | end 181 | 182 | fuel_DE = 0.08145 * P_DE_rated + 0.246 * P_DE(t); 183 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 184 | CO2 = CO2 + 0.649 * P_DE(t); 185 | 186 | % Battery dynamics 187 | % P_b_LI +ve -> Discharging 188 | % P_b_LI -ve -> Charging 189 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 190 | 191 | P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); 192 | P_lost(t) = max(0, P_load(t) - (P_RES(t) + P_b_LI(t)) * eta_inv - P_DE(t)); 193 | 194 | % if (P_RES(t) == P_load(t)/eta_inv) 195 | % continue 196 | % elseif (P_RES(t) > P_load(t)/eta_inv) % Excess supply 197 | % % Need to rectify AC DE output before sending to DC bus for dump loads 198 | % P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); % Sign of P_b_LI takes care of both charge/discharge case 199 | % else % Excess demand (AC) 200 | % P_lost(t) = max(0, P_load(t) - (P_RES(t) + P_b_LI(t)) * eta_inv - P_DE(t)); 201 | % if (P_lost(t) == 0) 202 | % P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); 203 | % end 204 | % end 205 | end 206 | 207 | CO = 4.063288937 * sum(P_DE); 208 | NOx = 18.85658039 * sum(P_DE); 209 | SO2 = 0.007381439 * sum(P_DE); 210 | VOC = 1.502443664 * sum(P_DE); 211 | PM = 1.338208931 * sum(P_DE); 212 | PM10 = 1.338208931 * sum(P_DE); 213 | PM25 = 1.338208931 * sum(P_DE); 214 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 215 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 216 | 217 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 218 | Cost = C_fuel_DE + Var_OM_DE + OM_s + OM_w + OM_LI + Fixed_OM_DE + DE_startup + DE_shutdown; 219 | E_gen = sum(P_DE * eta_rec + P_RES); 220 | COE = Cost/sum(P_load); % Unit cost of electricity ($/kWh) - considering only real-time, operational costs 221 | 222 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 223 | Var_OM_DE = Variable_OM_DE * 24; 224 | fuel_DE = 24 * 0.08145 * P_DE_rated + 0.246 * sum(P_load); 225 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 226 | DE_startup = SUC_DE; 227 | DE_shutdown = SDC_DE; 228 | Cost_base = C_fuel_DE + Var_OM_DE + Fixed_OM_DE + DE_startup + DE_shutdown; 229 | COE_base = Cost_base/sum(P_load); 230 | 231 | DPSP = sum(P_lost)/sum(P_load); 232 | Dump = sum(P_dump)/E_gen; 233 | REF = sum(P_RES)/E_gen; 234 | 235 | % No longer need to min DPSP since it's a constraint 236 | Costs = [COE/COE_base Emissions Dump 1-REF]; 237 | w = [0.25 0.25 0.25 0.25]; % Weights of different cost terms 238 | cost = Costs * w'; 239 | 240 | end 241 | -------------------------------------------------------------------------------- /Dispatch_obj_LI_DE_v4_DPSP.m: -------------------------------------------------------------------------------- 1 | function [cost, soc_LI, DPSP, P_dump, P_lost, P_load, P_w, P_s, P_RES] = Dispatch_obj_LI_DE_v4_DPSP(P_DE, P_b_LI) 2 | % Optimal dispatch of DE and BS on a day-ahead basis - Using inbuilt MATLAB solvers 3 | % Initial attempt: No MPC, static optimization over finite horizon based on certain/known historical load/climate data i.e. similar to LQR 4 | % But in reality, need some form of receding horizon MPC since controller doesn't have access to future climate/load data! 5 | 6 | % Assuming that any excess DE power cannot go towards charging battery 7 | % i.e. purpose of DE is only to serve as backup to meet excess load 8 | % P_DE and P_b_LI are 1x24 vectors 9 | 10 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 11 | load('temp.mat'); % Ambient air temperature (C) 12 | load('wind_speed.mat'); % (m/s) 13 | load('load_peaky.mat'); % Hourly power (kW) demand profile for a single representative day 14 | 15 | % Optimal sizing results using 5 equal weights - from v2 16 | % Oversize RES (round up n_s and n_w to nearest integer) and storage capacity 17 | % Using DG = 16 kW 18 | % n_s = 15.1187; 19 | % n_w = 4.3061; 20 | % Eb_init = 106.5333; % (kWh) 21 | 22 | % Using DG = 8 kW 23 | n_s = 8.0095; 24 | n_w = 4.6226; 25 | Eb_init = 118.1596; % (kWh) 26 | 27 | % Discretize 1 day into 1 h time intervals 28 | delta_t = 3600; % Calculation period (s) = 1 h 29 | 30 | P_s = zeros(1,24); % (kW) 31 | P_w = zeros(1,24); % (kW) 32 | P_RES = zeros(1,24); % (kW) 33 | P_dump = zeros(1,24); % Excess power (RES output) sent to dump loads/ground (kW) 34 | soc_LI = zeros(1,25); 35 | DE_ON = zeros(1,24); % Boolean variable to keep track of whether DE is online/committed 36 | P_lost = zeros(1,24); % Lost load AC 37 | P_load = zeros(1,24); 38 | 39 | % Startup and shutdown costs of conventional generators 40 | DE_startup = 0; 41 | DE_shutdown = 0; 42 | 43 | % Fuel costs 44 | C_fuel_DE = 0; 45 | 46 | % Fixed system parameters 47 | % SOLAR 48 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 49 | % For 255 W system - Monocrystalline Si 50 | eta_r = 0.154; % Manufacturer rated efficiency 51 | T_r = 25; % Standard test conditions (reference cell temperature) 52 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 53 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 54 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 55 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 56 | Ps_rated = 255; % Rated max power of each module (W) 57 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 58 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 59 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 60 | OM_s = (1/100)*(IC_s/365); % Fixed daily O&M costs ($/y) - from Kaabeche et al. 2011a 61 | 62 | % WIND 63 | beta_w = 1/7; % Typical value of power law exponent for open land 64 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 65 | h_ref = 1; % Installation height of TAHMO measurement stations (m) 66 | h_hub = 14.5; % Tower height to hub/nacelle (m) 67 | Pw_rated = 3.5; % Rated power of each WT (kW) 68 | Pw_rated_total = n_w * Pw_rated; 69 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 70 | OM_w = (3/100)*(IC_w/365); % Fixed daily O&M costs ($/y) 71 | v_c = 2.8; % Cut-in speed (m/s) 72 | v_r = 11; % Rated wind speed (m/s) 73 | v_f = 22; % Cut-out or failure speed (m/s) 74 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 75 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 76 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 77 | 78 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 79 | SOC_min_LI = 0.1; 80 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 81 | delta = 0.075; % Self-discharge rate of battery (%/month) 82 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 83 | IC_LI = 300 * Eb_init; 84 | OM_LI = (1/100) * (IC_LI/365); % Fixed daily O&M cost from Kaabeche et al. 2011a ($/y) 85 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 86 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 87 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 88 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 89 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 90 | 91 | % Diesel generator specs from Moshi et al. 2016 92 | P_DE_rated = 8; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 93 | P_DE_min = 0.3*P_DE_rated; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 94 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 95 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 96 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 97 | IC_DE = 12500; % Initial capital cost ($) 98 | Fixed_OM_DE = (2/100)*(IC_DE/365); % Fixed daily O&M costs ($/d) 99 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 100 | SUC_DE = 0.45; % Start-up cost ($/kW) 101 | SDC_DE = 0.23; % Shut-down cost ($) 102 | 103 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 104 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 105 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 106 | t_inv = 20; % Lifetime of converter 107 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 108 | 109 | P_load = load_peaky; 110 | 111 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 112 | CO2 = 0.649 * sum(P_load); 113 | CO = 4.063288937 * sum(P_load); 114 | NOx = 18.85658039 * sum(P_load); 115 | SO2 = 0.007381439 * sum(P_load); 116 | VOC = 1.502443664 * sum(P_load); 117 | PM = 1.338208931 * sum(P_load); 118 | PM10 = 1.338208931 * sum(P_load); 119 | PM25 = 1.338208931 * sum(P_load); 120 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 121 | 122 | CO2 = 0; 123 | 124 | for t = 1:1:24 125 | % SOLAR 126 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 127 | T_a = temp(t); 128 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 129 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 130 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 131 | 132 | if (P_s(t) > Ps_rated_total) 133 | P_s(t) = Ps_rated_total; 134 | end 135 | 136 | % WIND 137 | v_ref = wind_speed(t); 138 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 139 | 140 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 141 | if (v_hub < v_c || v_hub > v_f) 142 | P_w(t) = 0; 143 | elseif (v_c <= v_hub && v_hub <= v_r) 144 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 145 | else 146 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 147 | end 148 | 149 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 150 | 151 | if (t == 1) 152 | soc_LI(t) = 0.9; 153 | end 154 | 155 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 156 | cycles_LI = cycles_LI + 1; % Increment cycle number 157 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 158 | end 159 | 160 | % Lower limit on P_DE or not 161 | if (P_DE(t) >= P_DE_min) % DE online during hour t (P_DE_min or 1e-4) 162 | DE_ON(t) = 1; 163 | end 164 | 165 | % To enforce lower limit constraint on P_DE 166 | if (P_DE(t) < P_DE_min) 167 | P_DE(t) = 0; 168 | end 169 | 170 | if (DE_ON(1) == 1) 171 | DE_startup = DE_startup + SUC_DE; 172 | end 173 | 174 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 175 | DE_startup = DE_startup + SUC_DE; 176 | end 177 | 178 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 179 | DE_shutdown = DE_shutdown + SDC_DE; 180 | end 181 | 182 | fuel_DE = 0.08145 * P_DE_rated + 0.246 * P_DE(t); 183 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 184 | CO2 = CO2 + 0.649 * P_DE(t); 185 | 186 | % Battery dynamics 187 | % P_b_LI +ve -> Discharging 188 | % P_b_LI -ve -> Charging 189 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 190 | 191 | if (P_RES(t) == P_load(t)/eta_inv) 192 | continue 193 | elseif (P_RES(t) > P_load(t)/eta_inv) % Excess supply 194 | % Need to rectify AC DE output before sending to DC bus for dump loads 195 | P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); % Sign of P_b_LI takes care of both charge/discharge case 196 | else % Excess demand (AC) 197 | Excess_demand = P_load(t) - (P_RES(t) * eta_inv); 198 | P_lost(t) = max(0, Excess_demand - P_DE(t) - (P_b_LI(t) * eta_inv)); % AC 199 | P_dump(t) = max(0, (P_DE_min - Excess_demand + (P_b_LI(t) * eta_inv)) * eta_rec); % DC 200 | end 201 | end 202 | 203 | CO = 4.063288937 * sum(P_DE); 204 | NOx = 18.85658039 * sum(P_DE); 205 | SO2 = 0.007381439 * sum(P_DE); 206 | VOC = 1.502443664 * sum(P_DE); 207 | PM = 1.338208931 * sum(P_DE); 208 | PM10 = 1.338208931 * sum(P_DE); 209 | PM25 = 1.338208931 * sum(P_DE); 210 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 211 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 212 | 213 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 214 | Cost = C_fuel_DE + Var_OM_DE + OM_s + OM_w + OM_LI + Fixed_OM_DE + DE_startup + DE_shutdown; 215 | E_gen = sum(P_DE * eta_rec + P_RES); 216 | COE = Cost/sum(P_load); % Unit cost of electricity ($/kWh) - considering only real-time, operational costs 217 | 218 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 219 | Var_OM_DE = Variable_OM_DE * 24; 220 | fuel_DE = 24 * 0.08145 * P_DE_rated + 0.246 * sum(P_load); 221 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 222 | DE_startup = SUC_DE; 223 | DE_shutdown = SDC_DE; 224 | Cost_base = C_fuel_DE + Var_OM_DE + Fixed_OM_DE + DE_startup + DE_shutdown; 225 | COE_base = Cost_base/sum(P_load); 226 | 227 | DPSP = sum(P_lost)/sum(P_load); 228 | Dump = sum(P_dump)/E_gen; 229 | REF = sum(P_RES)/E_gen; 230 | 231 | % No longer need to min DPSP since it's a constraint 232 | Costs = [COE/COE_base Emissions DPSP Dump 1-REF]; 233 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 234 | cost = Costs * w'; 235 | 236 | end 237 | -------------------------------------------------------------------------------- /Dispatch_obj_LI_DE_v5_varySOC.m: -------------------------------------------------------------------------------- 1 | function [Costs, cost, soc_LI, DPSP, P_dump, P_lost, P_load, P_w, P_s, P_RES] = Dispatch_obj_LI_DE_v5_varySOC(P_DE, P_b_LI, SOC_initial) 2 | % Optimal dispatch of DE and BS on a day-ahead basis - Using inbuilt MATLAB solvers 3 | % Initial attempt: No MPC, static optimization over finite horizon based on certain/known historical load/climate data i.e. similar to LQR 4 | % But in reality, need some form of receding horizon MPC since controller doesn't have access to future climate/load data! 5 | 6 | % Assuming that any excess DE power cannot go towards charging battery 7 | % i.e. purpose of DE is only to serve as backup to meet excess load 8 | % P_DE and P_b_LI are 1x24 vectors 9 | 10 | % Vary over one week / 3 days instead of 1 day 11 | 12 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 13 | load('temp.mat'); % Ambient air temperature (C) 14 | load('wind_speed.mat'); % (m/s) 15 | load('Load_week.mat'); % Hourly power (kW) demand profile for a single representative day 16 | 17 | % Optimal sizing results using 5 equal weights - from v2 18 | % Oversize RES (round up n_s and n_w to nearest integer) and storage capacity 19 | % Using DG = 16 kW 20 | n_s = 15.1187; 21 | n_w = 4.3061; 22 | Eb_init = 106.5333; % (kWh) 23 | 24 | % Discretize 1 day into 1 h time intervals 25 | delta_t = 3600; % Calculation period (s) = 1 h 26 | hour = 0; % Keeps track of the hour in the day 27 | 28 | dim = 72; % 3 days 29 | 30 | P_s = zeros(1,dim); % (kW) 31 | P_w = zeros(1,dim); % (kW) 32 | P_RES = zeros(1,dim); % (kW) 33 | P_dump = zeros(1,dim); % Excess power (RES output) sent to dump loads/ground (kW) 34 | soc_LI = zeros(1,dim+1); 35 | DE_ON = zeros(1,dim); % Boolean variable to keep track of whether DE is online/committed 36 | P_lost = zeros(1,dim); % Lost load AC 37 | P_load = zeros(1,dim); 38 | 39 | % Startup and shutdown costs of conventional generators 40 | DE_startup = 0; 41 | DE_shutdown = 0; 42 | 43 | % Fuel costs 44 | C_fuel_DE = 0; 45 | 46 | % Fixed system parameters 47 | % SOLAR 48 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 49 | % For 255 W system - Monocrystalline Si 50 | eta_r = 0.154; % Manufacturer rated efficiency 51 | T_r = 25; % Standard test conditions (reference cell temperature) 52 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 53 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 54 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 55 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 56 | Ps_rated = 255; % Rated max power of each module (W) 57 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 58 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 59 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 60 | OM_s = (1/100)*(IC_s/365); % Fixed daily O&M costs ($/y) - from Kaabeche et al. 2011a 61 | 62 | % WIND 63 | beta_w = 1/7; % Typical value of power law exponent for open land 64 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 65 | h_ref = 1; % Installation height of TAHMO measurement stations (m) 66 | h_hub = 14.5; % Tower height to hub/nacelle (m) 67 | Pw_rated = 3.5; % Rated power of each WT (kW) 68 | Pw_rated_total = n_w * Pw_rated; 69 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 70 | OM_w = (3/100)*(IC_w/365); % Fixed daily O&M costs ($/y) 71 | v_c = 2.8; % Cut-in speed (m/s) 72 | v_r = 11; % Rated wind speed (m/s) 73 | v_f = 22; % Cut-out or failure speed (m/s) 74 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 75 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 76 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 77 | 78 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 79 | SOC_min_LI = 0.1; 80 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 81 | delta = 0.075; % Self-discharge rate of battery (%/month) 82 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 83 | IC_LI = 300 * Eb_init; 84 | OM_LI = (1/100) * (IC_LI/365); % Fixed daily O&M cost from Kaabeche et al. 2011a ($/y) 85 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 86 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 87 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 88 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 89 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 90 | 91 | % Diesel generator specs from Moshi et al. 2016 92 | P_DE_rated = 8; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 93 | P_DE_min = 0.3*P_DE_rated; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 94 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 95 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 96 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 97 | IC_DE = (12500/16)*P_DE_rated; % Initial capital cost ($) 98 | Fixed_OM_DE = (2/100)*(IC_DE/365); % Fixed daily O&M costs ($/d) 99 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 100 | SUC_DE = 0.45; % Start-up cost ($/kW) 101 | SDC_DE = 0.23; % Shut-down cost ($) 102 | 103 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 104 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 105 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 106 | t_inv = 20; % Lifetime of converter 107 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 108 | 109 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 110 | 111 | CO2 = 0; 112 | 113 | for t = 1:1:dim 114 | % SOLAR 115 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 116 | T_a = temp(t); 117 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 118 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 119 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 120 | 121 | if (P_s(t) > Ps_rated_total) 122 | P_s(t) = Ps_rated_total; 123 | end 124 | 125 | % WIND 126 | v_ref = wind_speed(t); 127 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 128 | 129 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 130 | if (v_hub < v_c || v_hub > v_f) 131 | P_w(t) = 0; 132 | elseif (v_c <= v_hub && v_hub <= v_r) 133 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 134 | else 135 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 136 | end 137 | 138 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 139 | 140 | if (t == 1) 141 | soc_LI(t) = SOC_initial; 142 | end 143 | 144 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 145 | cycles_LI = cycles_LI + 1; % Increment cycle number 146 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 147 | end 148 | 149 | % Lower limit on P_DE or not 150 | if (P_DE(t) >= P_DE_min) % DE online during hour t (P_DE_min or 1e-4) 151 | DE_ON(t) = 1; 152 | end 153 | 154 | % To enforce lower limit constraint on P_DE 155 | if (P_DE(t) < P_DE_min) 156 | P_DE(t) = 0; 157 | end 158 | 159 | if (DE_ON(1) == 1) 160 | DE_startup = DE_startup + SUC_DE; 161 | end 162 | 163 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 164 | DE_startup = DE_startup + SUC_DE; 165 | end 166 | 167 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 168 | DE_shutdown = DE_shutdown + SDC_DE; 169 | end 170 | 171 | fuel_DE = 0.08145 * P_DE_rated + 0.246 * P_DE(t); 172 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 173 | CO2 = CO2 + 0.649 * P_DE(t); 174 | 175 | day_number = ceil(t/24); 176 | if (hour >= 24) 177 | hour = 0; 178 | end 179 | hour = hour + 1; 180 | P_load(t) = Load_week(day_number,hour); % (kW) - AC 181 | 182 | % Battery dynamics 183 | % P_b_LI +ve -> Discharging 184 | % P_b_LI -ve -> Charging 185 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 186 | 187 | P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); 188 | P_lost(t) = max(0, P_load(t) - (P_RES(t) + P_b_LI(t)) * eta_inv - P_DE(t)); 189 | 190 | % if (P_RES(t) == P_load(t)/eta_inv) 191 | % continue 192 | % elseif (P_RES(t) > P_load(t)/eta_inv) % Excess supply 193 | % % Need to rectify AC DE output before sending to DC bus for dump loads 194 | % P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); % Sign of P_b_LI takes care of both charge/discharge case 195 | % else % Excess demand (AC) 196 | % P_lost(t) = max(0, P_load(t) - (P_RES(t) + P_b_LI(t)) * eta_inv - P_DE(t)); 197 | % if (P_lost(t) == 0) 198 | % P_dump(t) = max(0, P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv); 199 | % end 200 | % end 201 | end 202 | 203 | CO2 = 0.649 * sum(P_load); 204 | CO = 4.063288937 * sum(P_load); 205 | NOx = 18.85658039 * sum(P_load); 206 | SO2 = 0.007381439 * sum(P_load); 207 | VOC = 1.502443664 * sum(P_load); 208 | PM = 1.338208931 * sum(P_load); 209 | PM10 = 1.338208931 * sum(P_load); 210 | PM25 = 1.338208931 * sum(P_load); 211 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 212 | 213 | CO = 4.063288937 * sum(P_DE); 214 | NOx = 18.85658039 * sum(P_DE); 215 | SO2 = 0.007381439 * sum(P_DE); 216 | VOC = 1.502443664 * sum(P_DE); 217 | PM = 1.338208931 * sum(P_DE); 218 | PM10 = 1.338208931 * sum(P_DE); 219 | PM25 = 1.338208931 * sum(P_DE); 220 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 221 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 222 | 223 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 224 | Cost = C_fuel_DE + Var_OM_DE + OM_s + OM_w + OM_LI + Fixed_OM_DE + DE_startup + DE_shutdown; 225 | E_gen = sum(P_DE * eta_rec + P_RES); 226 | COE = Cost/sum(P_load); % Unit cost of electricity ($/kWh) - considering only real-time, operational costs 227 | 228 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 229 | Var_OM_DE = Variable_OM_DE * dim; 230 | fuel_DE = 24 * 0.08145 * P_DE_rated + 0.246 * sum(P_load); 231 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 232 | DE_startup = SUC_DE; 233 | DE_shutdown = SDC_DE; 234 | Cost_base = C_fuel_DE + Var_OM_DE + Fixed_OM_DE + DE_startup + DE_shutdown; 235 | COE_base = Cost_base/sum(P_load); 236 | 237 | DPSP = sum(P_lost)/sum(P_load); 238 | Dump = sum(P_dump)/E_gen; 239 | REF = sum(P_RES)/E_gen; 240 | 241 | % No longer need to min DPSP since it's a constraint 242 | Costs = [COE/COE_base Emissions Dump 1-REF]; 243 | w = [0.25 0.25 0.25 0.25]; % Weights of different cost terms 244 | cost = Costs * w'; 245 | 246 | end -------------------------------------------------------------------------------- /Dispatch_opt_CVX.m: -------------------------------------------------------------------------------- 1 | % Optimal dispatch of DE and BS on a day-ahead basis - Using CVX 2 | % Initial attempt: No MPC, static optimization over finite horizon i.e. similar to LQR 3 | % But in reality, need some form of receding horizon MPC since controller doesn't have access to future climate/load data! 4 | 5 | % Assuming that any excess DE power cannot go towards charging battery 6 | 7 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 8 | load('temp.mat'); % Ambient air temperature (C) 9 | load('wind_speed.mat'); % (m/s) 10 | load('Load_day.mat'); % Hourly power (kW) demand profile for a single representative day 11 | 12 | % Optimal sizing results using 5 equal weights - from v2 13 | % Oversize RES (round up n_S and n_w to nearest integer) and storage capacity 14 | n_s = 119; 15 | n_w = 5; 16 | Eb_init = 4.82; % (kWh) 17 | 18 | % Discretize 1 day into 1 h time intervals 19 | delta_t = 3600; % Calculation period (s) = 1 h 20 | 21 | P_s = zeros(1,24); % (kW) 22 | P_w = zeros(1,24); % (kW) 23 | P_RES = zeros(1,24); % (kW) 24 | P_dump = zeros(1,24); % Excess power (RES output) sent to dump loads/ground (kW) 25 | soc_LI = zeros(1,25); 26 | DE_ON = zeros(1,24); % Boolean variable to keep track of whether DE is online/committed 27 | P_lost = zeros(1,24); % Lost load (later -- DR) 28 | P_load = zeros(1,24); 29 | 30 | % Startup and shutdown costs of conventional generators 31 | DE_startup = 0; 32 | DE_shutdown = 0; 33 | 34 | % Variable O&M costs of DE 35 | Var_OM_DE = 0; 36 | 37 | % Fuel costs 38 | C_fuel_DE = 0; 39 | CO2 = 0; 40 | 41 | % Fixed system parameters 42 | % SOLAR 43 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 44 | % For 255 W system - Monocrystalline Si 45 | eta_r = 0.154; % Manufacturer rated efficiency 46 | T_r = 25; % Standard test conditions (reference cell temperature) 47 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 48 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 49 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 50 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 51 | Ps_rated = 255; % Rated max power of each module (W) 52 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 53 | 54 | % WIND 55 | beta_w = 1/7; % Typical value of power law exponent for open land 56 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 57 | h_ref = 2; % Installation height of TAHMO measurement stations (m) 58 | h_hub = 14.5; % Tower height to hub/nacelle (m) 59 | Pw_rated = 3.5; % Rated power of each WT (kW) 60 | v_c = 2.8; % Cut-in speed (m/s) 61 | v_r = 11; % Rated wind speed (m/s) 62 | v_f = 22; % Cut-out or failure speed (m/s) 63 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 64 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 65 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 66 | 67 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 68 | SOC_min_LI = 0.1; 69 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 70 | delta = 0.075; % Self-discharge rate of battery (%/month) 71 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 72 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 73 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 74 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 75 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 76 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 77 | 78 | % Diesel generator specs from Moshi et al. 2016 79 | P_DE_rated = 16; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 80 | P_DE_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 81 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 82 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 83 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 84 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 85 | SUC_DE = 0.45; % Start-up cost ($/kW) 86 | SDC_DE = 0.23; % Shut-down cost ($) 87 | 88 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 89 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 90 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 91 | t_inv = 10; % Lifetime of converter 92 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 93 | 94 | % Normalize emissions wrt a base case where the DE is continuously run for the whole day - to meet all the load 95 | fuel_DE = 24 * 0.06 * P_DE_rated + 0.0246 * sum(Load_day); 96 | CO2 = 3.5 * fuel_DE; 97 | CO = 4.063288937 * sum(Load_day); 98 | NOx = 18.85658039 * sum(Load_day); 99 | SO2 = 0.007381439 * sum(Load_day); 100 | VOC = 1.502443664 * sum(Load_day); 101 | PM = 1.338208931 * sum(Load_day); 102 | PM10 = 1.338208931 * sum(Load_day); 103 | PM25 = 1.338208931 * sum(Load_day); 104 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 105 | 106 | CO2 = 0; 107 | 108 | cvx_begin 109 | % CVX variables can be vectors! 110 | variable P_DE(1,24) 111 | variable P_b_LI(1,24) 112 | 113 | for t = 1:1:24 114 | % SOLAR 115 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 116 | T_a = temp(t); 117 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 118 | T_c = T_a + ((T_c_NOCT - 20)/0.8)*I; % Cell temp (C) 119 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 120 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 121 | 122 | % WIND 123 | v_ref = wind_speed(t); 124 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 125 | 126 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 127 | if (v_hub < v_c || v_hub > v_f) 128 | P_w(t) = 0; 129 | elseif (v_c <= v_hub && v_hub <= v_r) 130 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 131 | else 132 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 133 | end 134 | 135 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 136 | 137 | if (t == 1) 138 | soc_LI(t) = 0.9; 139 | end 140 | 141 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 142 | cycles_LI = cycles_LI + 1; % Increment cycle number 143 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 144 | end 145 | 146 | P_load(t) = Load_day(t); % (kW) 147 | 148 | if (P_DE(t) >= 1e-4) % DE online during hour t 149 | DE_ON(t)= 1; 150 | end 151 | 152 | if (DE_ON(1) == 1) 153 | DE_startup = DE_startup + SUC_DE; 154 | end 155 | 156 | if (t ~= 1 && DE_ON(t) == 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 157 | DE_startup = DE_startup + SUC_DE; 158 | end 159 | 160 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 161 | DE_shutdown = DE_shutdown + SDC_DE; 162 | end 163 | 164 | fuel_DE = 0.06 * P_DE_rated + 0.0246 * P_DE(t); 165 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); 166 | CO2 = CO2 + 3.5 * fuel_DE; 167 | 168 | % Battery dynamics 169 | % P_b_LI +ve -> Discharging 170 | % P_b_LI -ve -> Charging 171 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 172 | 173 | if (P_RES(t) == P_load(t)/eta_inv) 174 | continue 175 | elseif (P_RES(t) > P_load(t)/eta_inv) 176 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 177 | if (P_b_LI(t) >= 0) % Battery is discharged 178 | P_dump(t) = P_RES(t) + P_b_LI(t) + P_DE(t)*eta_rec - P_load(t)/eta_inv; 179 | else % Battery is charged 180 | P_dump(t) = P_RES(t) - abs(P_b_LI(t)) + P_DE(t)*eta_rec - P_load(t)/eta_inv; 181 | end 182 | else 183 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 184 | Excess_demand = P_load(t)/eta_inv - P_RES(t); 185 | if (P_b_LI(t) >= 0) % Battery is discharged 186 | P_lost(t) = Excess_demand - P_DE(t)*eta_rec - P_b_LI(t); 187 | P_dump(t) = max(0, P_DE_min - Excess_demand/eta_rec); 188 | else % Battery is charged 189 | P_lost(t) = Excess_demand - P_DE(t)*eta_rec - abs(P_b_LI(t)); 190 | P_dump(t) = max(0, P_DE_min - Excess_demand/eta_rec); 191 | end 192 | end 193 | end 194 | 195 | CO = 4.063288937 * sum(P_DE); 196 | NOx = 18.85658039 * sum(P_DE); 197 | SO2 = 0.007381439 * sum(P_DE); 198 | VOC = 1.502443664 * sum(P_DE); 199 | PM = 1.338208931 * sum(P_DE); 200 | PM10 = 1.338208931 * sum(P_DE); 201 | PM25 = 1.338208931 * sum(P_DE); 202 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 203 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 204 | 205 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 206 | Cost = C_fuel_DE + Var_OM_DE; 207 | E_gen = sum(P_DE + P_RES); 208 | COE = Cost/E_gen; % Unit cost of electricity ($/kWh) 209 | 210 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 211 | Var_OM_DE = Variable_OM_DE * 8760; 212 | fuel_DE = 8760 * 0.06 * P_DE_rated + 0.0246 * sum(Load_day); 213 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 214 | Cost_base = Fixed_OM_DE + Var_OM_DE + C_fuel_DE; 215 | COE_base = Cost_base/sum(Load_day); 216 | 217 | DPSP = sum(P_lost)/sum(Load_day); 218 | Dump = sum(P_dump)/E_gen; 219 | REF = sum(P_RES)/E_gen; 220 | 221 | Costs = [LCOE/LCOE_base Emissions DPSP Dump 1-REF]; 222 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 223 | cost = Costs * w'; 224 | 225 | minimize cost 226 | subject to 227 | 228 | P_DE >= zeros(1,24); 229 | P_DE <= P_DE_rated*ones(1,24); 230 | DPSP <= 0.005; 231 | soc_LI >= SOC_min_LI*ones(1,25); 232 | soc_LI <= SOC_max_LI*ones(1,25); 233 | P_b_LI <= P_max_LI*ones(1,24); 234 | P_b_LI >= -P_max_LI*ones(1,24); 235 | 236 | cvx_end 237 | 238 | 239 | -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_basecase.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_basecase.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowPV.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowPV.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowWT.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowWT.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowWTandPV.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_lowWTandPV.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_peakyLoad.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_DG8kW_wP_DEmin_UpdatedSizing_peakyLoad.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_DG8kW_wP_DEmin_basecase.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_DG8kW_wP_DEmin_basecase.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_noP_DEmin_basecase.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_noP_DEmin_basecase.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_noP_DEmin_lowPV.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_noP_DEmin_lowPV.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_noP_DEmin_lowWT.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_noP_DEmin_lowWT.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_noP_DEmin_lowWTandPV.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_noP_DEmin_lowWTandPV.mat -------------------------------------------------------------------------------- /Dispatch_opt_nsnw_wP_DEmin_basecase.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Dispatch_opt_nsnw_wP_DEmin_basecase.mat -------------------------------------------------------------------------------- /Dispatch_opt_v2.m: -------------------------------------------------------------------------------- 1 | %% Using - solve Constrained Nonlinear Optimization, Problem-Based 2 | % https://uk.mathworks.com/help/optim/ug/solve-constrained-nonlinear-optimization-problem-based.html 3 | 4 | % Create vector-valued optimization variables 5 | P_DE = optimvar('P_DE', 24)'; 6 | P_b_LI = optimvar('P_b_LI', 24)'; 7 | 8 | % https://uk.mathworks.com/help/optim/ug/fcn2optimexpr.html 9 | [cost, soc_LI, DPSP, P_dump, P_lost, P_load, P_w, P_s, P_RES] = fcn2optimexpr(@Dispatch_obj_LI_DE_v3, P_DE, P_b_LI,'OutputSize',{[1,1],[1,25],[1,1],... 10 | [1,24],[1,24],[1,24],[1,24],[1,24],[1,24]}); 11 | prob = optimproblem; 12 | 13 | prob.Objective = cost; 14 | 15 | P_DE_rated = 8; % (kW) 16 | SOC_min_LI = 0.1; 17 | SOC_max_LI = 0.9; 18 | P_max_LI = 3.68; % (kW) 19 | 20 | % All are bound constraints so can just convert to bounded optimization 21 | Constraint1 = P_DE >= zeros(1,24); 22 | Constraint2 = P_DE <= P_DE_rated*ones(1,24); 23 | Constraint3 = soc_LI >= SOC_min_LI*ones(1,25); 24 | Constraint4 = soc_LI <= SOC_max_LI*ones(1,25); 25 | Constraint5 = P_b_LI <= P_max_LI*ones(1,24); 26 | Constraint6 = P_b_LI >= -P_max_LI*ones(1,24); 27 | Constraint7 = DPSP <= 0.0100; 28 | 29 | prob.Constraints.Constraint1 = Constraint1; 30 | prob.Constraints.Constraint2 = Constraint2; 31 | prob.Constraints.Constraint3 = Constraint3; 32 | prob.Constraints.Constraint4 = Constraint4; 33 | prob.Constraints.Constraint5 = Constraint5; 34 | prob.Constraints.Constraint6 = Constraint6; 35 | prob.Constraints.Constraint7 = Constraint7; 36 | 37 | showproblem(prob) 38 | 39 | % Initial guess (start point) 40 | x0.P_DE = 7.*ones(1,24); % To ensure feasible initial point i.e. DPSP = 0 41 | x0.P_b_LI = ones(1,24); 42 | 43 | % Trying sqp algorithm, sometimes faster/more accurate than default interior-point 44 | options = optimoptions('fmincon','Algorithm','sqp','UseParallel',true,... 45 | 'MaxFunctionEvaluations',100000,'MaxIterations',10000,'Display','iter'); 46 | 47 | % Solve the problem 48 | tic 49 | [sol,fval] = solve(prob,x0,'Options',options) 50 | dispatch_time = toc; -------------------------------------------------------------------------------- /Dispatch_opt_v3_varySOC.m: -------------------------------------------------------------------------------- 1 | %% Using - solve Constrained Nonlinear Optimization, Problem-Based 2 | % https://uk.mathworks.com/help/optim/ug/solve-constrained-nonlinear-optimization-problem-based.html 3 | 4 | dim = 24*3; 5 | SOC_initial = linspace(0.1,0.9,9); 6 | Costs_soc = zeros(size(SOC_initial,2),4); 7 | DPSP_soc = zeros(size(SOC_initial,2),1); 8 | P_LI_soc = zeros(size(SOC_initial,2),dim); 9 | P_DE_soc = zeros(size(SOC_initial,2),dim); 10 | 11 | % Vary over one week instead of 1 day 12 | 13 | for i = 1:1:size(SOC_initial,2) 14 | % Create vector-valued optimization variables 15 | P_DE = optimvar('P_DE', dim)'; 16 | P_b_LI = optimvar('P_b_LI', dim)'; 17 | 18 | % https://uk.mathworks.com/help/optim/ug/fcn2optimexpr.html 19 | [Costs, cost, soc_LI, DPSP, P_dump, P_lost, P_load, P_w, P_s, P_RES] = fcn2optimexpr(@Dispatch_obj_LI_DE_v5_varySOC, ... 20 | P_DE, P_b_LI, SOC_initial(i),'OutputSize',{[1,4],[1,1],[1,dim+1],[1,1],[1,dim],[1,dim],[1,dim],[1,dim],[1,dim],[1,dim]}); 21 | prob = optimproblem; 22 | 23 | prob.Objective = cost; 24 | 25 | P_DE_rated = 8; % (kW) 26 | SOC_min_LI = 0.1; 27 | SOC_max_LI = 0.9; 28 | P_max_LI = 3.68; % (kW) 29 | 30 | % All are bound constraints so can just convert to bounded optimization 31 | Constraint1 = P_DE >= zeros(1,dim); 32 | Constraint2 = P_DE <= P_DE_rated*ones(1,dim); 33 | Constraint3 = soc_LI >= SOC_min_LI*ones(1,dim+1); 34 | Constraint4 = soc_LI <= SOC_max_LI*ones(1,dim+1); 35 | Constraint5 = P_b_LI <= P_max_LI*ones(1,dim); 36 | Constraint6 = P_b_LI >= -P_max_LI*ones(1,dim); 37 | Constraint7 = DPSP <= 0.0100; 38 | 39 | prob.Constraints.Constraint1 = Constraint1; 40 | prob.Constraints.Constraint2 = Constraint2; 41 | prob.Constraints.Constraint3 = Constraint3; 42 | prob.Constraints.Constraint4 = Constraint4; 43 | prob.Constraints.Constraint5 = Constraint5; 44 | prob.Constraints.Constraint6 = Constraint6; 45 | prob.Constraints.Constraint7 = Constraint7; 46 | 47 | showproblem(prob) 48 | 49 | % Initial guess (start point) 50 | x0.P_DE = 7.*ones(1,dim); % To ensure feasible initial point i.e. DPSP = 0 51 | x0.P_b_LI = ones(1,dim); 52 | 53 | % Trying sqp algorithm, sometimes faster/more accurate than default interior-point 54 | options = optimoptions('fmincon','Algorithm','sqp','UseParallel',true,... 55 | 'MaxFunctionEvaluations',100000,'MaxIterations',10000); 56 | 57 | % Solve the problem 58 | [sol,fval] = solve(prob,x0,'Options',options); 59 | P_LI_soc(i,:) = sol.P_b_LI; 60 | P_DE_soc(i,:) = sol.P_DE; 61 | [Costs_soc(i,:), cost, soc_LI, DPSP_soc(i), P_dump, P_lost, P_load, P_w, P_s, P_RES] = Dispatch_obj_LI_DE_v5_varySOC(P_DE_soc(i,:),P_LI_soc(i,:),SOC_initial(i)); 62 | 63 | end 64 | 65 | %% 66 | COE = Costs_soc(:,1); 67 | Emissions = Costs_soc(:,2); 68 | Dump = Costs_soc(:,3); 69 | REF = ones(size(SOC_initial,2),1) - Costs_soc(:,4); 70 | w = [0.2 0.2 0.2 0.2]; 71 | cost_soc = Costs_soc * w' + 0.2.*DPSP_soc; 72 | 73 | hold on 74 | plot(SOC_initial,COE); 75 | plot(SOC_initial,Emissions); 76 | plot(SOC_initial,DPSP_soc); 77 | plot(SOC_initial,Dump); 78 | plot(SOC_initial,REF); 79 | plot(SOC_initial,cost_soc) 80 | legend('Normalized COE','Emissions','DPSP','Dump energy ratio','REF','Weighted cost') -------------------------------------------------------------------------------- /HOMER_comparison.homer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/HOMER_comparison.homer -------------------------------------------------------------------------------- /HOMER_comparison_default.homer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/HOMER_comparison_default.homer -------------------------------------------------------------------------------- /LI_DE_1h_DPSP.m: -------------------------------------------------------------------------------- 1 | function [DPSP] = LI_DE_1h_DPSP(x) 2 | % Outputs DPSP which can be used to specify non-linear constraint for Pareto 3 | 4 | % Function performs optimal dispatch to output overall weighted cost function that needs to be minimized 5 | % Variable inputs (that we minimize w.r.t) are: 6 | % no. of solar PV arrays, no. of wind turbines, initial battery capacity (in kWh) 7 | n_s = x(1); 8 | n_w = x(2); 9 | Eb_init = x(3); 10 | 11 | % Given fixed inputs: Wind speed, ambient external air temperature, solar radiation, electricity demand 12 | % Have all of this data available over a whole year with hourly resolution 13 | 14 | % LOAD ALL FIXED EXTERNAL/EXOGENOUS INPUT VARIABLES 15 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 16 | load('temp.mat'); % Ambient air temperature (C) 17 | load('wind_speed.mat'); % (m/s) 18 | load('Load.mat'); % Hourly power (kW) demand profiles 19 | % Hourly energy demand profile = power demand * time interval 20 | 21 | % Initialize variables 22 | P_s = zeros(1,8760); % (kW) - DC 23 | P_w = zeros(1,8760); % (kW) - AC 24 | P_DE = zeros(1,8760); % (kW) - AC 25 | P_b_LI = zeros(1,8760); % (kW) - DC 26 | P_RES = zeros(1,8760); % (kW) - DC 27 | P_dump = zeros(1,8760); % Excess power (RES output) sent to dump loads/ground as DC (kW) 28 | soc_LI = zeros(1,8761); % between 0 and 1 29 | DE_ON = zeros(1,8760); % Boolean variable to keep track of whether DE is online/committed during that hour 30 | % Lost load or Amount of demand response (curtailment/shifting) needed to balance MG 31 | P_lost = zeros(1,8760); % (kW) - AC 32 | 33 | % COSTS 34 | i = 0.09; % Nominal interest/discount rate (https://tradingeconomics.com/kenya/interest-rate) 35 | f = 0.057; % Inflation/escalation rate (https://tradingeconomics.com/kenya/inflation-cpi) 36 | r = (i-f)/(1+f); % Real discount/interest rate 37 | t_overall = 25; % Overall system lifetime (y) = lifetime of solar (longest surviving components) 38 | CRF = (r*(1+r)^t_overall)/((1+r)^t_overall - 1); % Capital recovery factor 39 | 40 | % Startup and shutdown costs of conventional generators 41 | DE_startup = 0; 42 | DE_shutdown = 0; 43 | 44 | % Fuel costs 45 | C_fuel_DE = 0; 46 | 47 | % Fixed system parameters 48 | % SOLAR 49 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 50 | % For 255 W system - Monocrystalline Si 51 | eta_r = 0.154; % Manufacturer rated efficiency 52 | T_r = 25; % Standard test conditions (reference cell temperature) 53 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 54 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 55 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 56 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (of Pmax) 57 | t_s = 25; % Lifetime of solar PV array (y) 58 | Ps_rated = 255; % Rated max power of each module (W) 59 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 60 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 61 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 62 | % likely to be a slight underestimate since this is the global weighted 63 | % average for larger utility scale projects 64 | OM_s = (1/100)*IC_s; % Fixed annual O&M costs ($/y) - from Kaabeche et al. 2011a 65 | 66 | % Battery O&M cost as $/kWh-installed 67 | 68 | % WIND 69 | beta_w = 1/7; % Typical value of power law exponent for open land 70 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 71 | h_ref = 1; % Installation height of TAHMO measurement stations (m) - wind speed measured approx. at sea level 72 | h_hub = 14.5; % Tower height to hub/nacelle (m) 73 | Pw_rated = 3.5; % Rated power of each WT (kW) 74 | Pw_rated_total = n_w * Pw_rated; 75 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 76 | % This figure is likely to be an underestimate since it averages over both 77 | % large and small-scale turbines, but the initial capital cost per kW of 78 | % installed capacity likely to be higher for the small WT used in this 79 | % project (lacks economies of scale) 80 | 81 | OM_w = (3/100)*IC_w; % Fixed annual O&M costs ($/y) 82 | t_w = 20; % Lifetime of wind turbine system (y) 83 | v_c = 2.8; % Cut-in or start-up wind speed (m/s) 84 | v_r = 11; % Rated wind speed (m/s) 85 | v_f = 22; % Cut-out or failure/braking speed (m/s) 86 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 87 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 88 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 89 | 90 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 91 | % Updated parameters for powerwall - https://www.tesla.com/en_GB/powerwall 92 | SOC_min_LI = 0.1; 93 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 94 | delta = 0.075; % Self-discharge rate of battery (7.5%/month) 95 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 96 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 97 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 98 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 99 | cycled = 0; % Keeps track of whether the BS has already been self-discharged in the current time step 100 | % IC1_LI = 300; % Initial energy/capacity capital costs ($/kWh) - NREL 101 | % IC2_LI = 120; % Initial power capital costs ($/kW) 102 | % IC_LI = IC1_LI * Eb_init + IC2_LI * P_max_LI; % Total initial capital costs for LI 103 | IC_LI = 300 * Eb_init; % Assuming a price of $300/kWh 104 | OM_LI = (1/100) * IC_LI; % from Kaabeche et al. 2011a ($/y) 105 | RC_LI = 0.9*IC_LI; % Replacement cost at end of service period/lifetime - assumed to be 90% of IC since new installation and permitting fees aren't incurred 106 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 107 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 108 | %t_LI = 15; % Average lifetime of Li-ion battery (y) - 5 years beyond Tesla powerwall warranty period 109 | t_LI = 5475; % cycles 110 | 111 | % Diesel generator specs from Moshi et al. 2016 112 | P_DE_rated = 16; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 113 | P_DE_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 114 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard, DG must be able to reach rated capacity within 10 min 115 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 116 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 117 | IC_DE = 12500; % Initial capital cost for 16 kW rated DE ($) - slightly higher than replacement 118 | RC_DE = 11000; % Replacement cost ($) 119 | Fixed_OM_DE = (2/100)*IC_DE; % Fixed O&M costs ($/y) 120 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 121 | SUC_DE = 0.45; % Start-up cost ($) 122 | SDC_DE = 0.23; % Shut-down cost ($) 123 | % t_DE = 14; % Average lifetime of diesel engine (y) - avg expected life expectancy (https://www.wpowerproducts.com/news/diesel-engine-life-expectancy/) 124 | t_DE = 15000; % Lifetime (h), from Moshi et al. 2016 125 | 126 | % Bidirectional converter between AC and DC buses (can act as either rectifier or inverter) 127 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 128 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 129 | t_inv = 20; % Lifetime of converter (y) - Moshi et al. 2016 130 | P_inv_rated = 12.52; % Maximum rated power of inverter (kW) 131 | IC_inv = 2800; % ($) 132 | % Assume converter has zero maintenance costs 133 | 134 | % Start with delta_t = 1 h and then maybe discretize over smaller time intervals 135 | delta_t = 3600; % Calculation period (s) = 1 hour 136 | 137 | hour = 0; % Keeps track of the hour in the day 138 | 139 | % Normalize emissions wrt a base case where the DE is continuously run for the whole year to meet all the load 140 | CO2 = 0.649 * sum(sum(Load)); 141 | CO = 4.063288937 * sum(sum(Load)); 142 | NOx = 18.85658039 * sum(sum(Load)); 143 | SO2 = 0.007381439 * sum(sum(Load)); 144 | VOC = 1.502443664 * sum(sum(Load)); 145 | PM = 1.338208931 * sum(sum(Load)); 146 | PM10 = 1.338208931 * sum(sum(Load)); 147 | PM25 = 1.338208931 * sum(sum(Load)); 148 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 149 | 150 | CO2 = 0; 151 | 152 | for t = 1:1:8760 % Simulate over one year with a time-step of 1 h 153 | 154 | Excess_demand = 0; 155 | 156 | % SOLAR 157 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 158 | T_a = temp(t); 159 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 160 | % Alternative model - Kaabeche et al. 2011b 161 | % T_c = T_a + ((T_c_NOCT - 20)/0.8)*I; % Cell temp (C) 162 | % eta_PV = eta_r * eta_pc * (1 - beta_s*(T_c - T_r)); 163 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 164 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) - DC 165 | 166 | if (P_s(t) > Ps_rated_total) 167 | P_s(t) = Ps_rated_total; 168 | end 169 | 170 | % WIND 171 | v_ref = wind_speed(t); 172 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 173 | 174 | if (v_hub < v_c || v_hub > v_f) 175 | P_w(t) = 0; 176 | elseif (v_c <= v_hub && v_hub <= v_r) 177 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); % Source? 178 | % Alternative formula - Borhanazad et al. 2014 179 | % Pw = ((v_hub^3)*P_rated - P_rated*v_cutin^3)/(v_rated^3 - v_cutin^3); 180 | % Also include commonly known formula using Cp and swept area? 181 | % But need to know variation of Cp with TSR for my specific WT model 182 | 183 | else 184 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) - AC 185 | end 186 | 187 | % Rectify AC power from WT to DC 188 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 189 | 190 | % BATTERY 191 | % Assume battery starts out fully charged (at max safe SOC) 192 | if (t == 1) 193 | soc_LI(t) = 0.9; 194 | end 195 | 196 | if (soc_LI(t) > SOC_max_LI) 197 | soc_LI(t) = SOC_max_LI; 198 | end 199 | 200 | if (soc_LI(t) < SOC_min_LI) 201 | soc_LI(t) = SOC_min_LI; 202 | end 203 | 204 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 205 | cycles_LI = cycles_LI + 1; % Increment cycle number 206 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 207 | end 208 | 209 | day_number = ceil(t/24); 210 | if (hour >= 24) 211 | hour = 0; 212 | end 213 | hour = hour + 1; 214 | P_load = Load(day_number,hour); % (kW) - AC 215 | 216 | if (P_RES(t) == P_load/eta_inv) % Since RES power needs to inverted to meet AC load 217 | continue 218 | elseif (P_RES(t) > P_load/eta_inv) % Excess supply/generation 219 | if (soc_LI(t) >= SOC_max_LI) % Battery can't be charged further 220 | P_dump(t) = P_RES(t) - P_load/eta_inv; % Send excess power to dump loads/ground - DC 221 | else % Charge battery system 222 | if (P_RES(t) - P_load/eta_inv <= P_max_LI) 223 | P_b_LI(t) = -(P_RES(t) - P_load/eta_inv); % (kW) 224 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 225 | cycled = 1; 226 | else 227 | P_b_LI(t) = -P_max_LI; 228 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 229 | P_dump(t) = P_RES(t) - P_load/eta_inv - P_max_LI; 230 | cycled = 1; 231 | end 232 | end 233 | else % Insufficient supply/generation 234 | Excess_demand = P_load/eta_inv - P_RES(t); % DC 235 | if (soc_LI(t) > SOC_min_LI) % Discharge battery 236 | if (Excess_demand <= P_max_LI) 237 | P_b_LI(t) = Excess_demand; 238 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 239 | Excess_demand = 0; % All load has been met/satisfied 240 | cycled = 1; 241 | else 242 | P_b_LI(t) = P_max_LI; 243 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 244 | Excess_demand = Excess_demand - P_max_LI; 245 | cycled = 1; 246 | end 247 | elseif (soc_LI(t) <= SOC_min_LI || Excess_demand > 0) % Need to use backup DE to meet excess load 248 | DE_ON(t) = 1; % Turn DE on 249 | % Power produced by DE is already AC - so can directly meet load 250 | Excess_demand = Excess_demand * eta_inv; % AC 251 | if (Excess_demand <= P_DE_rated) 252 | if (Excess_demand >= P_DE_min) 253 | P_DE(t) = Excess_demand; 254 | % No dumped load 255 | else 256 | P_DE(t) = P_DE_min; 257 | P_dump(t) = (P_DE_min - Excess_demand) * eta_rec; % (kW) - DC 258 | % If we allow excess generator output to charge battery 259 | % DE output must 1st be rectified to DC before charging battery 260 | if (soc_LI(t) < SOC_max_LI) 261 | if (P_dump(t) <= P_max_LI) 262 | if (cycled == 0) % Battery hasn't been cycled/operated yet before in this time step 263 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) + P_dump(t)*1000*delta_t*(eta_overall/E_C); 264 | else % Battery has already been cycled so don't include self-discharge again 265 | soc_LI(t+1) = soc_LI(t+1) + P_dump(t)*1000*delta_t*(eta_overall/E_C); 266 | end 267 | P_dump(t) = 0; 268 | else 269 | if (cycled == 0) % Battery hasn't been cycled/operated yet before in this time step 270 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) + P_max_LI*1000*delta_t*(eta_overall/E_C); 271 | else % Battery has already been cycled so don't include self-discharge again 272 | soc_LI(t+1) = soc_LI(t+1) + P_max_LI*1000*delta_t*(eta_overall/E_C); 273 | end 274 | P_dump(t) = P_dump(t) - P_max_LI; 275 | end 276 | end 277 | end 278 | else 279 | P_DE(t) = P_DE_rated; 280 | P_lost(t) = Excess_demand - P_DE_rated; 281 | end 282 | else 283 | DE_ON(t) = 0; % Turn DE off 284 | end 285 | end 286 | 287 | cycled = 0; % Reset 288 | end 289 | 290 | % Reliability measure - % of load that's not not met 291 | DPSP = sum(P_lost)/sum(sum(Load)); 292 | 293 | end -------------------------------------------------------------------------------- /Load.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Load.mat -------------------------------------------------------------------------------- /Load_day.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Load_day.mat -------------------------------------------------------------------------------- /Load_week.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Load_week.mat -------------------------------------------------------------------------------- /MT.m: -------------------------------------------------------------------------------- 1 | function [C_MT, Emissions_MT] = MT(P_MT) 2 | % Model for micro gas turbine (MT) - Wu et al. 2014 3 | L = 9.7e-3; % Thermal value of gas (kg/kW) 4 | C_nl = 1; % Price of natural gas ($/m^3) 5 | 6 | % Simpler model for fuel consumption cost in controllable DG (MT, DE, FC) 7 | % C_MT = C_nl * (E_GT_total / eta_e); 8 | 9 | % Actual source: https://www.epa.gov/sites/production/files/2015-07/documents/catalog_of_chp_technologies_section_5._characterization_-_microturbines.pdf 10 | % Another useful source: https://www.energy.gov/sites/prod/files/2016/09/f33/CHP-Microturbines_0.pdf 11 | 12 | % All values based on HHV of NG 13 | P_rated_MT = 28; % kW - but this is much larger than the peak load 14 | Fuel_MT = 0.434; % Fuel input in MMBtu/h of online operation 15 | C_NG = 2.19; % Cost of natural gas per MMBtu - https://markets.businessinsider.com/commodities/natural-gas-price 16 | eta_e = 0.247; % Electric efficiency 17 | eta_t = 0.469; % Thermal efficiency 18 | eta_overall = 0.716; % Overall efficiency 19 | 20 | IC_MT = 3220; % Initial installed capital cost (inc. complete MT package + construction/installation) in $/kW 21 | Fixed_OM_mt = (2/100)*IC_MT; 22 | Variable_OM_MT = 0.013; % $/kWh 23 | 24 | Emissions_MT = 731.6445; % kgCO2(e) / MWh -------------------------------------------------------------------------------- /Objective_LA_MT_v2_1h.m: -------------------------------------------------------------------------------- 1 | function [cost] = Objective_LA_MT_v2_1h(x) 2 | % With modified strategy for excess demand scenario/case (elseif statement & not self-discharging twice in the same time-step) 3 | % Normalized LCOE and emissions to always lie between 0 and 1 4 | 5 | n_s = x(1); 6 | n_w = x(2); 7 | Eb_init = x(3); 8 | 9 | % LOAD ALL FIXED EXTERNAL/EXOGENOUS INPUT VARIABLES 10 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 11 | load('temp.mat'); % Ambient air temperature (C) 12 | load('wind_speed.mat'); % (m/s) 13 | load('Load.mat'); % Hourly power (kW) demand profiles 14 | 15 | % Initialize variables 16 | P_s = zeros(1,8760); % (kW) - DC 17 | P_w = zeros(1,8760); % (kW) - AC 18 | P_MT = zeros(1,8760); % (kW) - AC 19 | P_b_LA = zeros(1,8760); % (kW) - DC 20 | P_RES = zeros(1,8760); % (kW) - DC 21 | P_dump = zeros(1,8760); % Excess power (RES output) sent to dump loads/ground as DC (kW) 22 | soc_LA = zeros(1,8761); % between 0 and 1 23 | MT_ON = zeros(1,8760); % Boolean variable to keep track of whether MT is online/committed during that hour 24 | P_lost = zeros(1,8760); % (kW) - AC 25 | 26 | % COSTS 27 | i = 0.09; % Nominal interest/discount rate (https://tradingeconomics.com/kenya/interest-rate) 28 | f = 0.057; % Inflation/escalation rate (https://tradingeconomics.com/kenya/inflation-cpi) 29 | r = (i-f)/(1+f); % Real discount/interest rate 30 | t_overall = 25; % Overall system lifetime (y) = lifetime of solar (longest surviving components) 31 | CRF = (r*(1+r)^t_overall)/((1+r)^t_overall - 1); % Capital recovery factor 32 | 33 | % Startup and shutdown costs of conventional generators 34 | MT_startup = 0; 35 | MT_shutdown = 0; 36 | 37 | % Fuel costs 38 | C_fuel_MT = 0; 39 | 40 | % Fixed system parameters 41 | % SOLAR 42 | eta_r = 0.154; % Manufacturer rated efficiency 43 | T_r = 25; % Standard test conditions (reference cell temperature) 44 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 45 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 46 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 47 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (of Pmax) 48 | t_s = 25; % Lifetime of solar PV array (y) 49 | Ps_rated = 255; % Rated max power of each module (W) 50 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 51 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 52 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 53 | OM_s = (1/100)*IC_s; % Fixed annual O&M costs ($/y) - from Kaabeche et al. 2011a 54 | 55 | % WIND 56 | beta_w = 1/7; % Typical value of power law exponent for open land 57 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 58 | h_ref = 1; % Installation height of TAHMO measurement stations (m) - wind speed measured approx. at sea level 59 | h_hub = 14.5; % Tower height to hub/nacelle (m) 60 | Pw_rated = 3.5; % Rated power of each WT (kW) 61 | Pw_rated_total = n_w * Pw_rated; 62 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 63 | 64 | OM_w = (3/100)*IC_w; % Fixed annual O&M costs ($/y) 65 | t_w = 20; % Lifetime of wind turbine system (y) 66 | v_c = 2.8; % Cut-in or start-up wind speed (m/s) 67 | v_r = 11; % Rated wind speed (m/s) 68 | v_f = 22; % Cut-out or failure/braking speed (m/s) 69 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 70 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 71 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 72 | 73 | % Lead-acid battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 74 | SOC_min_LA = 0.5; 75 | SOC_max_LA = 0.9; % 40% DoD - much lower compared to Li-ion 76 | delta = 0.05; % Self-discharge rate of battery (5%/month) 77 | P_max_LA = 0.42; % Max continuous real power (kW) 78 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 79 | eta_overall = 0.75; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 80 | cycles_LA = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 81 | cycled = 0; % Keeps track of whether the BS has already been self-discharged in the current time step 82 | IC_LA = 255 * Eb_init; % Assuming a price of $255/kWh 83 | OM_LA = (1/100) * IC_LA; % from Kaabeche et al. 2011a ($/y) 84 | RC_LA = 0.9*IC_LA; % Replacement cost at end of service period/lifetime - assumed to be 90% of IC since new installation and permitting fees aren't incurred 85 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 86 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 87 | t_LA = 1400; % Average lifetime (cycles) 88 | 89 | % MT specs from https://www.energy.gov/sites/prod/files/2016/09/f33/CHP-Microturbines_0.pdf 90 | P_MT_rated = 16; % Rated maximum power of MT (kW) = approx. peak load * 1.5 91 | P_MT_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 92 | Ramp = (P_MT_rated*1000)/10; % Max ramp rate of MT (W/min) - NERC disturbance control standard, DG must be able to reach rated capacity within 10 min 93 | IC_MT = 3220 * P_MT_rated; % Initial capital cost - https://www.energy.gov/sites/prod/files/2016/09/f33/CHP-Microturbines_0.pdf 94 | RC_MT = 0.9*IC_MT; % Replacement cost ($) 95 | Fixed_OM_MT = (2/100)*IC_MT; % Fixed O&M costs ($/y) 96 | Variable_OM_MT = 0.013; % Variable O&M costs ($/kWh) 97 | C_NG = 2.19; % Cost of natural gas in $/MMBtu - https://markets.businessinsider.com/commodities/natural-gas-price 98 | SUC_MT = 0.45; % Start-up cost ($) - assum similar startup/shutdown costs to MT 99 | SDC_MT = 0.23; % Shut-down cost ($) 100 | t_MT = 40000; % Lifetime (h), from https://www.epa.gov/sites/production/files/2015-07/documents/catalog_of_chp_technologies_section_5._characterization_-_microturbines.pdf 101 | 102 | % Bidirectional converter between AC and DC buses (can act as either rectifier or inverter) 103 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 104 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 105 | t_inv = 20; % Lifetime of converter (y) - Moshi et al. 2016 106 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be larger than peak load (1.5x) 107 | IC_inv = 2800; % ($) 108 | 109 | % Start with delta_t = 1 h and then maybe discretize over smaller time intervals 110 | delta_t = 3600; % Calculation period (s) = 1 hour 111 | 112 | hour = 0; % Keeps track of the hour in the day 113 | 114 | % Normalize emissions wrt a base case where the MT is continuously run for the whole year at rated power - to meet all the load 115 | CO2 = 0.631 * sum(sum(Load)); 116 | CO = 2.851087583 * sum(sum(Load)); 117 | NOx = 20.88408858 * sum(sum(Load)); 118 | SO2 = 0.003009766 * sum(sum(Load)); 119 | VOC = 0.604000601 * sum(sum(Load)); 120 | PM = 0.046974355 * sum(sum(Load)); 121 | PM10 = 0.046974355 * sum(sum(Load)); 122 | PM25 = 0.046974355 * sum(sum(Load)); 123 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 124 | 125 | CO2 = 0; 126 | 127 | for t = 1:1:8760 % Simulate over one year with a time-step of 1 h 128 | 129 | Excess_demand = 0; 130 | 131 | % SOLAR 132 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 133 | T_a = temp(t); 134 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 135 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 136 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) - DC 137 | 138 | if (P_s(t) > Ps_rated_total) 139 | P_s(t) = Ps_rated_total; 140 | end 141 | 142 | % WIND 143 | v_ref = wind_speed(t); 144 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 145 | 146 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 147 | if (v_hub < v_c || v_hub > v_f) 148 | P_w(t) = 0; 149 | elseif (v_c <= v_hub && v_hub <= v_r) 150 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 151 | % Alternative formula 152 | % Pw = ((v_hub^3)*P_rated - P_rated*v_cutin^3)/(v_rated^3 - v_cutin^3); 153 | else 154 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) - AC 155 | end 156 | 157 | % Rectify AC power from WT to DC 158 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 159 | 160 | % BATTERY 161 | % Assume battery starts out fully charged (at max safe SOC) 162 | if (t == 1) 163 | soc_LA(t) = 0.9; 164 | end 165 | 166 | if (soc_LA(t) > SOC_max_LA) 167 | soc_LA(t) = SOC_max_LA; 168 | end 169 | 170 | if (soc_LA(t) < SOC_min_LA) 171 | soc_LA(t) = SOC_min_LA; 172 | end 173 | 174 | if (t ~= 1 && soc_LA(t) == SOC_max_LA && soc_LA(t-1) < SOC_max_LA) % Complete 1 charge-discharge cycle 175 | cycles_LA = cycles_LA + 1; % Increment cycle number 176 | E_C = Eb_init*(1 - (cycles_LA*0.0214)/100); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 177 | end 178 | 179 | day_number = ceil(t/24); 180 | if (hour >= 24) 181 | hour = 0; 182 | end 183 | hour = hour + 1; 184 | P_load = Load(day_number,hour); % (kW) - AC 185 | 186 | if (P_RES(t) == P_load/eta_inv) % Since RES power needs to inverted to meet AC load 187 | continue 188 | elseif (P_RES(t) > P_load/eta_inv) % Excess supply/generation 189 | if (soc_LA(t) >= SOC_max_LA) % Battery can't be charged further 190 | P_dump(t) = P_RES(t) - P_load/eta_inv; % Send excess power to dump loads/ground - DC 191 | else % Charge battery system 192 | if (P_RES(t) - P_load/eta_inv <= P_max_LA) 193 | P_b_LA(t) = -(P_RES(t) - P_load/eta_inv); % (kW) 194 | soc_LA(t+1) = soc_LA(t)*(1-delta_hour) - P_b_LA(t)*1000*delta_t*(eta_overall/E_C); 195 | cycled = 1; 196 | else 197 | P_b_LA(t) = -P_max_LA; 198 | soc_LA(t+1) = soc_LA(t)*(1-delta_hour) - P_b_LA(t)*1000*delta_t*(eta_overall/E_C); 199 | P_dump(t) = P_RES(t) - P_load/eta_inv - P_max_LA; 200 | cycled = 1; 201 | end 202 | end 203 | else % Insufficient supply/generation 204 | Excess_demand = P_load/eta_inv - P_RES(t); % DC 205 | if (soc_LA(t) > SOC_min_LA) % Discharge battery 206 | if (Excess_demand <= P_max_LA) 207 | P_b_LA(t) = Excess_demand; 208 | soc_LA(t+1) = soc_LA(t)*(1-delta_hour) - P_b_LA(t)*1000*delta_t*(eta_overall/E_C); 209 | Excess_demand = 0; % All load has been met/satisfied 210 | cycled = 1; 211 | else 212 | P_b_LA(t) = P_max_LA; 213 | soc_LA(t+1) = soc_LA(t)*(1-delta_hour) - P_b_LA(t)*1000*delta_t*(eta_overall/E_C); 214 | Excess_demand = Excess_demand - P_max_LA; 215 | cycled = 1; 216 | end 217 | elseif (soc_LA(t) <= SOC_min_LA || Excess_demand > 0) % Need to use backup MT to meet excess load 218 | MT_ON(t) = 1; % Turn MT on 219 | % Power produced by MT is already AC - so can directly meet load 220 | Excess_demand = Excess_demand * eta_inv; % AC 221 | if (Excess_demand <= P_MT_rated) 222 | if (Excess_demand >= P_MT_min) 223 | P_MT(t) = Excess_demand; 224 | % No dumped load 225 | else 226 | P_MT(t) = P_MT_min; 227 | P_dump(t) = (P_MT_min - Excess_demand) * eta_rec; % (kW) - DC 228 | % If we allow excess generator output to charge battery 229 | % MT output must 1st be rectified to DC before charging battery 230 | if (soc_LA(t) < SOC_max_LA) 231 | if (P_dump(t) <= P_max_LA) 232 | if (cycled == 0) % Battery hasn't been cycled/operated yet before in this time step 233 | soc_LA(t+1) = soc_LA(t)*(1-delta_hour) + P_dump(t)*1000*delta_t*(eta_overall/E_C); 234 | else % Battery has already been cycled so don't include self-discharge again 235 | soc_LA(t+1) = soc_LA(t+1) + P_dump(t)*1000*delta_t*(eta_overall/E_C); 236 | end 237 | P_dump(t) = 0; 238 | else 239 | if (cycled == 0) % Battery hasn't been cycled/operated yet before in this time step 240 | soc_LA(t+1) = soc_LA(t)*(1-delta_hour) + P_max_LA*1000*delta_t*(eta_overall/E_C); 241 | else % Battery has already been cycled so don't include self-discharge again 242 | soc_LA(t+1) = soc_LA(t+1) + P_max_LA*1000*delta_t*(eta_overall/E_C); 243 | end 244 | P_dump(t) = P_dump(t) - P_max_LA; 245 | end 246 | end 247 | end 248 | else 249 | P_MT(t) = P_MT_rated; 250 | P_lost(t) = Excess_demand - P_MT_rated; 251 | end 252 | 253 | if (t ~= 1 && MT_ON(t-1) == 0) % i.e. MT was offline in the last/most recent time step 254 | MT_startup = MT_startup + SUC_MT; 255 | % Ramp_actual = (Excess_Demand - P_MT(t-1))/60 % actual ramp rate (W/min) 256 | end 257 | else 258 | MT_ON(t) = 0; % Turn MT off 259 | if (t ~= 1 && MT_ON(t-1) == 1) % i.e. MT was online in the last/most recent time step 260 | MT_shutdown = MT_shutdown + SDC_MT; 261 | end 262 | end 263 | end 264 | 265 | % Also need to account for (varying) MT efficiency while calculating its fuel consumption! 266 | % fuel_MT = 0.06 * P_MT_rated + 0.0246 * P_MT(t); % fuel consumption (L/h) where P is in kW - Kaabeche and Ibtiouen 2014 267 | % C_fuel_MT = C_fuel_MT + 3.20 * (fuel_MT / 3.78541); % Diesel fuel cost assuming a price of $3.20/US liquid gallon (value for east Africa from NREL ReOpt) 268 | 269 | CO2 = CO2 + 0.631 * P_MT(t); % Usign emission coefficient of 0.631 kg/kWh - https://www.energy.gov/sites/prod/files/2016/09/f33/CHP-Microturbines_0.pdf 270 | cycled = 0; % Reset 271 | end 272 | 273 | if (MT_ON(1) == 1) 274 | MT_startup = MT_startup + SUC_MT; 275 | end 276 | 277 | Var_OM_MT = Variable_OM_MT * sum(P_MT); 278 | fuel_MT = (0.84/61) * sum(P_MT); % NG fuel consumption (MMBtu) 279 | % assuming 0.84 MMTBtu/h of operation for a 61 kW MT 280 | 281 | C_fuel_MT = fuel_MT * C_NG; 282 | 283 | % Total initial capital/installed cost 284 | IC = IC_s + IC_w + IC_LA + IC_MT + IC_inv; 285 | 286 | % Total annual recurring costs each year 287 | C_rec = OM_s + OM_w + OM_LA + Fixed_OM_MT + Var_OM_MT + C_fuel_MT + MT_startup + MT_shutdown; 288 | 289 | % Present worth of recurring costs 290 | PW_rec = C_rec * (((1+f)/(1+i))*(((1+f)/(1+i))^t_overall - 1))/(((1+f)/(1+i)) - 1); 291 | 292 | % Battery replaced every 1400 cycles 293 | t_rep_LA = cycles_LA/t_LA; % No. of years between battery replacements 294 | i_adj_LA = (((1+i)^t_rep_LA)/(1+f)^(t_rep_LA - 1)) - 1; % Adjusted nominal interest rate 295 | PW_LA_rep = RC_LA * (((1+f)/(1+i_adj_LA))*(((1+f)/(1+i_adj_LA))^t_overall - 1))/(((1+f)/(1+i_adj_LA)) - 1); 296 | 297 | % Determine frequency of MT replacement based on actual no. of operating hours per year 298 | t_MT_rep = (t_MT/sum(MT_ON)); % No. of years after which MT needs to be replaced 299 | i_adj_MT = (((1+i)^t_MT_rep)/(1+f)^(t_MT_rep - 1)) - 1; % Adjusted nominal interest rate 300 | PW_MT_rep = RC_MT * (((1+f)/(1+i_adj_MT))*(((1+f)/(1+i_adj_MT))^t_overall - 1))/(((1+f)/(1+i_adj_MT)) - 1); 301 | 302 | % Present worth of non-recurring costs 303 | PW_nonrec = PW_LA_rep + PW_MT_rep; 304 | 305 | TNPC = IC + PW_rec + PW_nonrec; % Total (lifecycle) net present cost of system ($) 306 | TAC = TNPC * CRF; % Total annualized cost ($) 307 | LCOE = TAC/sum(sum(Load)); % Energy cost/Levelized cost of electricity ($/kWh) = total annual costs / total load served 308 | 309 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single MT 310 | % Total annual recurring costs each yeaR 311 | Var_OM_MT = Variable_OM_MT * sum(sum(Load)); 312 | C_fuel_MT = C_NG * (0.84/61) * sum(sum(Load)); 313 | MT_startup = SUC_MT; 314 | MT_shutdown = SDC_MT; 315 | C_rec = Fixed_OM_MT + Var_OM_MT + C_fuel_MT + MT_startup + MT_shutdown; 316 | 317 | % Present worth of recurring costs 318 | PW_rec = C_rec * (((1+f)/(1+i))*(((1+f)/(1+i))^t_overall - 1))/(((1+f)/(1+i)) - 1); 319 | 320 | t_MT_rep = (t_MT/8760); % No. of years after which MT needs to be replaced 321 | i_adj_MT = (((1+i)^t_MT_rep)/(1+f)^(t_MT_rep - 1)) - 1; % Adjusted nominal interest rate 322 | PW_MT_rep = RC_MT * (((1+f)/(1+i_adj_MT))*(((1+f)/(1+i_adj_MT))^t_overall - 1))/(((1+f)/(1+i_adj_MT)) - 1); 323 | 324 | % Present worth of non-recurring costs 325 | PW_nonrec = PW_MT_rep; 326 | 327 | IC = IC_MT; 328 | TNPC = IC + PW_rec + PW_nonrec; % Total (lifecycle) net present cost of system ($) 329 | TAC = TNPC * CRF; % Total annualized cost ($) 330 | LCOE_base = TAC/sum(sum(Load)); % Energy cost/Levelized cost of electricity ($/kWh) 331 | 332 | % Emissions factors - EPA database (all in g) 333 | CO = 2.851087583 * sum(P_MT); 334 | NOx = 20.88408858 * sum(P_MT); 335 | SO2 = 0.003009766 * sum(P_MT); 336 | VOC = 0.604000601 * sum(P_MT); 337 | PM = 0.046974355 * sum(P_MT); 338 | PM10 = 0.046974355 * sum(P_MT); 339 | PM25 = 0.046974355 * sum(P_MT); 340 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % Total (kg) 341 | 342 | % Reliability measure - % of load that's not not met 343 | DPSP = sum(P_lost)/sum(sum(Load)); 344 | 345 | % Excess/dump energy as a fraction of total generation 346 | E_gen = sum(P_MT * eta_rec + P_RES); % Total annual DC electrical energy output = P_gen * delta_t = P_gen (in kWh) since delta_t = 1 h 347 | Dump = sum(P_dump)/E_gen; 348 | 349 | % Renewable penetration 350 | REF = sum(P_RES)/E_gen; 351 | 352 | Costs = [LCOE/LCOE_base Emissions/Emissions_base DPSP Dump 1-REF]; 353 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 354 | cost = Costs * w'; 355 | 356 | end -------------------------------------------------------------------------------- /Objective_LI_DE.m: -------------------------------------------------------------------------------- 1 | function [cost] = Objective_LI_DE(x) 2 | % Function performs optimal dispatch to output overall weighted cost function that needs to be minimized 3 | % Variable inputs (that we minimize w.r.t) are: 4 | % no. of solar PV arrays, no. of wind turbines, initial battery capacity (in kWh) 5 | n_s = x(1); 6 | n_w = x(2); 7 | Eb_init = x(3); 8 | 9 | % Given fixed inputs: Wind speed, ambient external air temperature, solar radiation, electricity demand 10 | % Have all of this data available over a whole year with hourly resolution 11 | 12 | % LOAD ALL FIXED EXTERNAL/EXOGENOUS INPUT VARIABLES 13 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 14 | load('temp.mat'); % Ambient air temperature (C) 15 | load('wind_speed.mat'); % (m/s) 16 | load('Load.mat'); % Hourly power (kW) demand profiles 17 | % Hourly energy demand profile = power demand * time interval 18 | 19 | % Initialize variables 20 | P_s = zeros(1,8760); % (kW) 21 | P_w = zeros(1,8760); % (kW) 22 | P_DE = zeros(1,8760); % (kW) 23 | P_b_LI = zeros(1,8760); % (kW) 24 | P_RES = zeros(1,8760); % (kW) 25 | P_dump = zeros(1,8760); % Excess power (RES output) sent to dump loads/ground (kW) 26 | soc_LI = zeros(1,8761); % between 0 and 1 27 | DE_ON = zeros(1,8760); % Boolean variable to keep track of whether DE is online/committed 28 | % Lost load or Amount of demand response (curtailment/shifting) needed to balance MG 29 | P_lost = zeros(1,8760); 30 | 31 | % COSTS 32 | i = 0.1; % Nominal interest/discount rate (from NREL LCOE explorer) 33 | f = 0.035; % Inflation/escalation rate (https://tradingeconomics.com/tanzania/inflation-cpi) 34 | r = (i-f)/(1+f); % Real discount/interest rate 35 | t_overall = 25; % Overall system lifetime (y) = lifetime of solar (longest surviving components) 36 | CRF = (r*(1+r)^t_overall)/((1+r)^t_overall - 1); % Capital recovery factor 37 | 38 | % Startup and shutdown costs of conventional generators 39 | DE_startup = 0; 40 | DE_shutdown = 0; 41 | 42 | % Variable O&M costs of DE 43 | Var_OM_DE = 0; 44 | 45 | % Fuel costs 46 | C_fuel_DE = 0; 47 | CO2 = 0; 48 | 49 | % Fixed system parameters 50 | % SOLAR 51 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 52 | % For 255 W system - Monocrystalline Si 53 | eta_r = 0.154; % Manufacturer rated efficiency 54 | T_r = 25; % Standard test conditions (reference cell temperature) 55 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 56 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 57 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 58 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (midway between the Pmax and Voc coefficients) 59 | t_s = 25; % Lifetime of solar PV array (y) 60 | Ps_rated = 255; % Rated max power of each module (W) 61 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 62 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 63 | IC_s = (Ps_rated_total/1000) * 1750; % Assuming installed PV costs of $1750/kW (source: IRENA costs report 2018, total installed costs) 64 | OM_s = (1/100)*IC_s; % Fixed annual O&M costs ($/y) - from Kaabeche et al. 2011a 65 | 66 | % WIND 67 | beta_w = 1/7; % Typical value of power law exponent for open land 68 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 69 | h_ref = 2; % Installation height of TAHMO measurement stations (m) 70 | h_hub = 14.5; % Tower height to hub/nacelle (m) 71 | Pw_rated = 3.5; % Rated power of each WT (kW) 72 | Pw_rated_total = n_w * Pw_rated; 73 | IC_w = Pw_rated_total * 1500; % Assuming installed PV costs of $1500/kW (source: IRENA costs report 2018, total installed costs) 74 | OM_w = (3/100)*IC_w; % Fixed annual O&M costs ($/y) 75 | t_w = 20; % Lifetime of wind turbine system (y) 76 | v_c = 2.8; % Cut-in speed (m/s) 77 | v_r = 11; % Rated wind speed (m/s) 78 | v_f = 22; % Cut-out or failure speed (m/s) 79 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 80 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 81 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 82 | 83 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 84 | % Updated parameters for powerwall - https://www.tesla.com/en_GB/powerwall 85 | SOC_min_LI = 0.1; 86 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 87 | delta = 0.075; % Self-discharge rate of battery (7.5%/month) 88 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 89 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 90 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 91 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 92 | IC1_LI = 520; % Initial capital energy/capacity costs ($/kWh) 93 | IC2_LI = 120; % Initial capital power costs ($/kW) - source? 94 | IC_LI = IC1_LI * Eb_init + IC2_LI * P_max_LI; % Total initial capital costs for LI 95 | OM_LI = (1/100) * IC_LI; % from Kaabeche et al. 2011a ($/y) 96 | RC_LI = 0.9*IC_LI; % Replacement cost at end of service period/lifetime 97 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 98 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 99 | t_LI = 10; % Average lifetime of Li-ion battery (y) - Tesla powerwall warranty 100 | 101 | % Diesel generator specs from Moshi et al. 2016 102 | P_DE_rated = 16; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 103 | P_DE_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 104 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 105 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 106 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 107 | IC_DE = 12500; % Initial capital cost ($) 108 | RC_DE = 11000; % Replacement cost ($) 109 | Fixed_OM_DE = (2/100)*IC_DE; % Fixed O&M costs ($/y) 110 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 111 | SUC_DE = 0.45; % Start-up cost ($/kW) 112 | SDC_DE = 0.23; % Shut-down cost ($) 113 | t_DE = 5; % Average lifetime of diesel engine (y) - source? 114 | % t_DE = 15000; % Lifetime (h), from Moshi et al. 2016 115 | 116 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 117 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 118 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 119 | t_inv = 10; % Lifetime of converter 120 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 121 | IC_inv = 0.715 * P_inv_rated; % Assuming unit price of $0.715/W 122 | % Assume converter has zero maintenance costs 123 | 124 | % Start with delta_t = 1 h and then maybe discretize over smaller time intervals 125 | delta_t = 3600; % Calculation period (s) = 1 hour 126 | 127 | hour = 0; % Keeps track of the hour in the day 128 | 129 | % Normalize emissions wrt a base case where the DE is continuously run for the whole year at rated power - to meet all the load 130 | fuel_DE = 8760 * 0.06 * P_DE_rated + 0.0246 * sum(sum(Load)); 131 | CO2 = 3.5 * fuel_DE; 132 | CO = 4.063288937 * sum(sum(Load)); 133 | NOx = 18.85658039 * sum(sum(Load)); 134 | SO2 = 0.007381439 * sum(sum(Load)); 135 | VOC = 1.502443664 * sum(sum(Load)); 136 | PM = 1.338208931 * sum(sum(Load)); 137 | PM10 = 1.338208931 * sum(sum(Load)); 138 | PM25 = 1.338208931 * sum(sum(Load)); 139 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 140 | 141 | CO2 = 0; 142 | 143 | for t = 1:1:8760 % Simulate over one year with a time-step of 1 h 144 | 145 | Excess_demand = 0; 146 | 147 | % SOLAR - How does Ps_rated affect these calculations? 148 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 149 | T_a = temp(t); 150 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 151 | % Alternative model - Kaabeche et al. 2011b 152 | T_c = T_a + ((T_c_NOCT - 20)/0.8)*I; % Cell temp (C) 153 | % eta_PV = eta_r * eta_pc * (1 - beta_s*(T_c - T_r)); 154 | % A_c = 1.625 * 1.019; % Surface area of 1 panel rated at 255 W (m^2) 155 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 156 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 157 | 158 | % if (P_s(t) > Ps_rated_total) 159 | % P_s(t) = Ps_rated_total; 160 | % end 161 | 162 | % WIND 163 | v_ref = wind_speed(t); 164 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 165 | 166 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 167 | if (v_hub < v_c || v_hub > v_f) 168 | P_w(t) = 0; 169 | elseif (v_c <= v_hub && v_hub <= v_r) 170 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 171 | % Alternative formula 172 | % Pw = ((v_hub^3)*P_rated - P_rated*v_cutin^3)/(v_rated^3 - v_cutin^3); 173 | else 174 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 175 | end 176 | 177 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 178 | 179 | % BATTERY 180 | % Assume battery starts out fully charged (at max safe SOC) 181 | if (t == 1) 182 | soc_LI(t) = 0.9; 183 | end 184 | 185 | if (soc_LI(t) > SOC_max_LI) 186 | soc_LI(t) = SOC_max_LI; 187 | end 188 | 189 | if (soc_LI(t) < SOC_min_LI) 190 | soc_LI(t) = SOC_min_LI; 191 | end 192 | 193 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 194 | cycles_LI = cycles_LI + 1; % Increment cycle number 195 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 196 | end 197 | 198 | day_number = ceil(t/24); 199 | if (hour >= 24) 200 | hour = 0; 201 | end 202 | hour = hour + 1; 203 | P_load = Load(day_number,hour); % (kW) 204 | 205 | if (P_RES(t) == P_load/eta_inv) 206 | continue 207 | elseif (P_RES(t) > P_load/eta_inv) % Excess supply/generation 208 | if (soc_LI(t) >= SOC_max_LI) % Battery can't be charged further 209 | P_dump(t) = P_RES(t) - P_load/eta_inv; % Send excess power to dump loads/ground 210 | else % Charge battery system 211 | if (P_RES(t) - P_load/eta_inv <= P_max_LI) 212 | P_b_LI(t) = -(P_RES(t) - P_load/eta_inv); 213 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 214 | else 215 | P_b_LI(t) = -P_max_LI; 216 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 217 | P_dump(t) = P_RES(t) - P_load/eta_inv - P_max_LI; 218 | end 219 | end 220 | else % Insufficient supply/generation 221 | Excess_demand = P_load/eta_inv - P_RES(t); 222 | if (soc_LI(t) > SOC_min_LI) % Discharge battery 223 | if (Excess_demand <= P_max_LI) 224 | P_b_LI(t) = Excess_demand; 225 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 226 | Excess_demand = 0; % All load has been met/satisfied 227 | else 228 | P_b_LI(t) = P_max_LI; 229 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 230 | Excess_demand = Excess_demand - P_max_LI; 231 | end 232 | elseif (Excess_demand > 0) % Need to use backup DE to meet excess load 233 | DE_ON(t) = 1; % Turn DE on 234 | if (Excess_demand/eta_rec <= P_DE_rated) 235 | if (Excess_demand/eta_rec >= P_DE_min) 236 | P_DE(t) = Excess_demand/eta_rec; 237 | % No dumped load 238 | else 239 | P_DE(t) = P_DE_min; 240 | P_dump(t) = P_DE_min - Excess_demand/eta_rec; 241 | % If we allow excess generator output to charge battery 242 | if (soc_LI(t) < SOC_max_LI) 243 | if (P_dump(t) <= P_max_LI) 244 | soc_LI(t+1) = max(SOC_min_LI,soc_LI(t+1))*(1-delta_hour) + P_dump(t)*delta_t*(eta_overall/E_C); 245 | P_dump(t) = 0; 246 | else 247 | soc_LI(t+1) = max(SOC_min_LI,soc_LI(t+1))*(1-delta_hour) + P_max_LI*delta_t*(eta_overall/E_C); 248 | P_dump(t) = P_dump(t) - P_max_LI; 249 | end 250 | end 251 | end 252 | else 253 | P_DE(t) = P_DE_rated; 254 | P_lost(t) = Excess_demand/eta_rec - P_DE_rated; 255 | end 256 | 257 | if (t ~= 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 258 | DE_startup = DE_startup + SUC_DE; 259 | % Ramp_actual = (Excess_Demand - P_DE(t-1))/60 % actual ramp rate (W/min) 260 | end 261 | else 262 | DE_ON(t) = 0; % Turn DE off 263 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 264 | DE_shutdown = DE_shutdown + SDC_DE; 265 | end 266 | end 267 | end 268 | 269 | fuel_DE = 0.06 * P_DE_rated + 0.0246 * P_DE(t); % fuel consumption (L/h) where P is in kW - source? 270 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); % Diesel fuel cost assuming a price of $3.20/US liquid gallon (value for Tanzania from NREL ReOpt) 271 | % Alternatively, can model assume fuel consumption cost to be quadratic function of DE power output (Parisio et al. 2014 and others) 272 | % But need to find right coefficients by data fitting 273 | CO2 = CO2 + 3.5 * fuel_DE; % Total CO2 emissions (kg) using emission factor of 3.5 kg/L of diesel - source? 274 | end 275 | 276 | if (DE_ON(1) == 1) 277 | DE_startup = DE_startup + SUC_DE; 278 | end 279 | 280 | % Upon completion of for loop i.e. after iterating through all hours of the year, C_fuel_DE now gives the total fuel cost over the 1st year of MG operation 281 | % It is assumed that on average, the annual fuel cost remains constant for all subsequent years of the system's lifetime 282 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 283 | 284 | % Total initial capital/installed cost 285 | IC = IC_s + IC_w + IC_LI + IC_DE + IC_inv; 286 | 287 | % Total annual recurring costs each year 288 | C_rec = OM_s + OM_w + OM_LI + Fixed_OM_DE + Var_OM_DE + C_fuel_DE; 289 | 290 | % Present worth of recurring costs 291 | PW_rec = C_rec * (((1+f)/(1+i))*(((1+f)/(1+i))^t_overall - 1))/(((1+f)/(1+i)) - 1); 292 | 293 | % Battery replaced every 10 years 294 | i_adj_LI = (((1+i)^t_LI)/(1+f)^(t_LI - 1)) - 1; % Adjusted nominal interest rate 295 | PW_LI_rep = RC_LI * (((1+f)/(1+i_adj_LI))*(((1+f)/(1+i_adj_LI))^t_overall - 1))/(((1+f)/(1+i_adj_LI)) - 1); 296 | 297 | % DE replaced every 5 years 298 | i_adj_DE = (((1+i)^t_DE)/(1+f)^(t_DE - 1)) - 1; % Adjusted nominal interest rate 299 | PW_DE_rep = RC_DE * (((1+f)/(1+i_adj_DE))*(((1+f)/(1+i_adj_DE))^t_overall - 1))/(((1+f)/(1+i_adj_DE)) - 1); 300 | 301 | % Present worth of non-recurring costs 302 | PW_nonrec = PW_LI_rep + PW_DE_rep; 303 | 304 | TNPC = IC + PW_rec + PW_nonrec; % Total (lifecycle) net present cost of system ($) 305 | TAC = TNPC * CRF; % Total annualized cost ($) 306 | E_gen = sum(P_DE + P_RES); % Total annual electrical energy = P_gen * delta_t = P_gen (in kWh) since delta_t = 1 h 307 | LCOE = TAC/E_gen; % Energy cost/Levelized cost of electricity ($/kWh) 308 | 309 | % Emissions factors - EPA database (all in g) 310 | % Alternative source: Wu et al. 2014 311 | CO = 4.063288937 * sum(P_DE); 312 | NOx = 18.85658039 * sum(P_DE); 313 | SO2 = 0.007381439 * sum(P_DE); 314 | VOC = 1.502443664 * sum(P_DE); 315 | PM = 1.338208931 * sum(P_DE); 316 | PM10 = 1.338208931 * sum(P_DE); 317 | PM25 = 1.338208931 * sum(P_DE); 318 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 319 | Emissions = Emissions/Emissions_base; % Always lies between 0 and 1 320 | 321 | % Reliability measure - % of load that's not not met 322 | DPSP = sum(P_lost)/sum(sum(Load)); 323 | 324 | % Excess/dump energy as a fraction of total generation 325 | Dump = sum(P_dump)/E_gen; 326 | 327 | % Renewable penetration 328 | REF = sum(P_RES)/E_gen; 329 | 330 | % time = 1:1:8760; 331 | % plot(time, P_RES); 332 | 333 | Costs = [LCOE Emissions DPSP Dump -REF]; 334 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 335 | cost = Costs * w'; 336 | 337 | end -------------------------------------------------------------------------------- /Objective_LI_DE_v3_1h.m: -------------------------------------------------------------------------------- 1 | function [cost] = Objective_LI_DE_v3_1h(x) 2 | % With modified strategy for excess demand scenario/case 3 | % Assume DE is used only to meet excess load directly and can't be used to charge battery storage 4 | % And real time BS replacement 5 | 6 | % Function performs optimal dispatch to output overall weighted cost function that needs to be minimized 7 | % Variable inputs (that we minimize w.r.t) are: 8 | % no. of solar PV arrays, no. of wind turbines, initial battery capacity (in kWh) 9 | n_s = x(1); 10 | n_w = x(2); 11 | Eb_init = x(3); 12 | 13 | % Given fixed inputs: Wind speed, ambient external air temperature, solar radiation, electricity demand 14 | % Have all of this data available over a whole year with hourly resolution 15 | 16 | % LOAD ALL FIXED EXTERNAL/EXOGENOUS INPUT VARIABLES 17 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 18 | load('temp.mat'); % Ambient air temperature (C) 19 | load('wind_speed.mat'); % (m/s) 20 | load('Load.mat'); % Hourly power (kW) demand profiles 21 | % Hourly energy demand profile = power demand * time interval 22 | 23 | % Initialize variables 24 | P_s = zeros(1,8760); % (kW) 25 | P_w = zeros(1,8760); % (kW) 26 | P_DE = zeros(1,8760); % (kW) 27 | P_b_LI = zeros(1,8760); % (kW) 28 | P_RES = zeros(1,8760); % (kW) 29 | P_dump = zeros(1,8760); % Excess power (RES output) sent to dump loads/ground (kW) 30 | soc_LI = zeros(1,8761); % between 0 and 1 31 | DE_ON = zeros(1,8760); % Boolean variable to keep track of whether DE is online/committed 32 | % Lost load or Amount of demand response (curtailment/shifting) needed to balance MG 33 | P_lost = zeros(1,8760); 34 | 35 | % COSTS 36 | i = 0.09; % Nominal interest/discount rate (https://tradingeconomics.com/kenya/interest-rate) 37 | f = 0.057; % Inflation/escalation rate (https://tradingeconomics.com/kenya/inflation-cpi) 38 | r = (i-f)/(1+f); % Real discount/interest rate 39 | t_overall = 25; % Overall system lifetime (y) = lifetime of solar (longest surviving components) 40 | CRF = (r*(1+r)^t_overall)/((1+r)^t_overall - 1); % Capital recovery factor 41 | 42 | % Startup and shutdown costs of conventional generators 43 | DE_startup = 0; 44 | DE_shutdown = 0; 45 | 46 | % Fuel costs 47 | C_fuel_DE = 0; 48 | 49 | % Fixed system parameters 50 | % SOLAR 51 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 52 | % For 255 W system - Monocrystalline Si 53 | eta_r = 0.154; % Manufacturer rated efficiency 54 | T_r = 25; % Standard test conditions (reference cell temperature) 55 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 56 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 57 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 58 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (of Pmax) 59 | t_s = 25; % Lifetime of solar PV array (y) 60 | Ps_rated = 255; % Rated max power of each module (W) 61 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 62 | Ps_rated_total = n_s * Ps_rated; % Total solar PV installed capacity in microgrid (W) 63 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 64 | OM_s = (1/100)*IC_s; % Fixed annual O&M costs ($/y) - from Kaabeche et al. 2011a 65 | 66 | % WIND 67 | beta_w = 1/7; % Typical value of power law exponent for open land 68 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 69 | h_ref = 1; % Installation height of TAHMO measurement stations (m) - wind speed measured approx. at sea level 70 | h_hub = 14.5; % Tower height to hub/nacelle (m) 71 | Pw_rated = 3.5; % Rated power of each WT (kW) 72 | Pw_rated_total = n_w * Pw_rated; 73 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 74 | OM_w = (3/100)*IC_w; % Fixed annual O&M costs ($/y) 75 | t_w = 20; % Lifetime of wind turbine system (y) 76 | v_c = 2.8; % Cut-in speed (m/s) 77 | v_r = 11; % Rated wind speed (m/s) 78 | v_f = 22; % Cut-out or failure speed (m/s) 79 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 80 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 81 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 82 | 83 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 84 | % Updated parameters for powerwall - https://www.tesla.com/en_GB/powerwall 85 | SOC_min_LI = 0.1; 86 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 87 | delta = 0.075; % Self-discharge rate of battery (7.5%/month) 88 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 89 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 90 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 91 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 92 | % IC1_LI = 520; % Initial capital energy/capacity costs ($/kWh) 93 | % IC2_LI = 120; % Initial capital power costs ($/kW) - source? 94 | % IC_LI = IC1_LI * Eb_init + IC2_LI * P_max_LI; % Total initial capital costs for LI 95 | IC_LI = 300 * Eb_init; 96 | OM_LI = (1/100) * IC_LI; % from Kaabeche et al. 2011a ($/y) 97 | RC_LI = 0.9*IC_LI; % Replacement cost at end of service period/lifetime 98 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s, 1 kWh = 3.6 MJ 99 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 100 | %t_LI = 15; % Average lifetime of Li-ion battery (y) - Tesla powerwall warranty 101 | t_LI = 5475; % Average lifetime (cycles) 102 | 103 | % Diesel generator specs from Moshi et al. 2016 104 | P_DE_rated = 16; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 105 | P_DE_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 106 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard 107 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 108 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 109 | IC_DE = 12500; % Initial capital cost ($) 110 | RC_DE = 11000; % Replacement cost ($) 111 | Fixed_OM_DE = (2/100)*IC_DE; % Fixed O&M costs ($/y) 112 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 113 | SUC_DE = 0.45; % Start-up cost ($) 114 | SDC_DE = 0.23; % Shut-down cost ($) 115 | % t_DE = 14; % Average lifetime of diesel engine (y) 116 | t_DE = 15000; % Lifetime (h), from Moshi et al. 2016 117 | 118 | % Bidirectional inverter between AC and DC buses (can act as either rectifier or inverter) 119 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 120 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 121 | t_inv = 20; % Lifetime of converter 122 | P_inv_rated = 16; % Maximum rated power of inverter (kW) - chosen to be same as that of backup generator 123 | IC_inv = 2800; % ($) 124 | % Assume converter has zero maintenance costs 125 | 126 | % Start with delta_t = 1 h and then maybe discretize over smaller time intervals 127 | delta_t = 3600; % Calculation period (s) = 1 hour 128 | 129 | hour = 0; % Keeps track of the hour in the day 130 | 131 | % Normalize emissions wrt a base case where the DE is continuously run for the whole year at rated power - to meet all the load 132 | CO2 = 0.649 * sum(sum(Load)); 133 | CO = 4.063288937 * sum(sum(Load)); 134 | NOx = 18.85658039 * sum(sum(Load)); 135 | SO2 = 0.007381439 * sum(sum(Load)); 136 | VOC = 1.502443664 * sum(sum(Load)); 137 | PM = 1.338208931 * sum(sum(Load)); 138 | PM10 = 1.338208931 * sum(sum(Load)); 139 | PM25 = 1.338208931 * sum(sum(Load)); 140 | Emissions_base = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; % (kg) 141 | 142 | CO2 = 0; 143 | 144 | for t = 1:1:8760 % Simulate over one year with a time-step of 1 h 145 | 146 | Excess_demand = 0; 147 | 148 | % SOLAR 149 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 150 | T_a = temp(t); 151 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 152 | % Alternative model - Kaabeche et al. 2011b 153 | % T_c = T_a + ((T_c_NOCT - 20)/0.8)*I; % Cell temp (C) 154 | % eta_PV = eta_r * eta_pc * (1 - beta_s*(T_c - T_r)); 155 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 156 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) 157 | 158 | if (P_s(t) > Ps_rated_total) 159 | P_s(t) = Ps_rated_total; 160 | end 161 | 162 | % WIND 163 | v_ref = wind_speed(t); 164 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 165 | 166 | % From Borhanazad et al. 2014: Optimization of micro-grid system using MOPSO 167 | if (v_hub < v_c || v_hub > v_f) 168 | P_w(t) = 0; 169 | elseif (v_c <= v_hub && v_hub <= v_r) 170 | P_w(t) = n_w * Pw_rated * (A + B * v_hub + C * v_hub^2); 171 | % Alternative formula 172 | % Pw = ((v_hub^3)*P_rated - P_rated*v_cutin^3)/(v_rated^3 - v_cutin^3); 173 | else 174 | P_w(t) = n_w * Pw_rated; % Wind power output (kW) 175 | end 176 | 177 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 178 | 179 | % BATTERY 180 | % Assume battery starts out fully charged (at max safe SOC) 181 | if (t == 1) 182 | soc_LI(t) = 0.9; 183 | end 184 | 185 | if (soc_LI(t) > SOC_max_LI) 186 | soc_LI(t) = SOC_max_LI; 187 | end 188 | 189 | if (soc_LI(t) < SOC_min_LI) 190 | soc_LI(t) = SOC_min_LI; 191 | end 192 | 193 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 194 | cycles_LI = cycles_LI + 1; % Increment cycle number 195 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 196 | end 197 | 198 | day_number = ceil(t/24); 199 | if (hour >= 24) 200 | hour = 0; 201 | end 202 | hour = hour + 1; 203 | P_load = Load(day_number,hour); % (kW) 204 | 205 | if (P_RES(t) == P_load/eta_inv) 206 | continue 207 | elseif (P_RES(t) > P_load/eta_inv) % Excess supply/generation 208 | if (soc_LI(t) >= SOC_max_LI) % Battery can't be charged further 209 | P_dump(t) = P_RES(t) - P_load/eta_inv; % Send excess power to dump loads/ground 210 | else % Charge battery system 211 | if (P_RES(t) - P_load/eta_inv <= P_max_LI) 212 | P_b_LI(t) = -(P_RES(t) - P_load/eta_inv); 213 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 214 | else 215 | P_b_LI(t) = -P_max_LI; 216 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 217 | P_dump(t) = P_RES(t) - P_load/eta_inv - P_max_LI; 218 | end 219 | end 220 | else % Insufficient supply/generation 221 | Excess_demand = P_load/eta_inv - P_RES(t); 222 | if (soc_LI(t) > SOC_min_LI) % Discharge battery 223 | if (Excess_demand <= P_max_LI) 224 | P_b_LI(t) = Excess_demand; 225 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 226 | Excess_demand = 0; % All load has been met/satisfied 227 | else 228 | P_b_LI(t) = P_max_LI; 229 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 230 | Excess_demand = Excess_demand - P_max_LI; 231 | end 232 | elseif (soc_LI(t) <= SOC_min_LI || Excess_demand > 0) % Need to use backup DE to meet excess load 233 | DE_ON(t) = 1; % Turn DE on 234 | Excess_demand = Excess_demand * eta_inv; % AC 235 | if (Excess_demand <= P_DE_rated) 236 | if (Excess_demand >= P_DE_min) 237 | P_DE(t) = Excess_demand; 238 | % No dumped load 239 | else 240 | P_DE(t) = P_DE_min; 241 | P_dump(t) = (P_DE_min - Excess_demand) * eta_rec; 242 | end 243 | else 244 | P_DE(t) = P_DE_rated; 245 | P_lost(t) = Excess_demand - P_DE_rated; 246 | end 247 | 248 | if (t ~= 1 && DE_ON(t-1) == 0) % i.e. DE was offline in the last/most recent time step 249 | DE_startup = DE_startup + SUC_DE; 250 | % Ramp_actual = (Excess_Demand - P_DE(t-1))/60 % actual ramp rate (W/min) 251 | end 252 | else 253 | DE_ON(t) = 0; % Turn DE off 254 | if (t ~= 1 && DE_ON(t-1) == 1) % i.e. DE was online in the last/most recent time step 255 | DE_shutdown = DE_shutdown + SDC_DE; 256 | end 257 | end 258 | end 259 | 260 | fuel_DE = 0.08145 * P_DE_rated + 0.246 * P_DE(t); % fuel consumption (L/h) where P is in kW - source? 261 | C_fuel_DE = C_fuel_DE + 3.20 * (fuel_DE / 3.78541); % Diesel fuel cost assuming a price of $3.20/US liquid gallon (value for Tanzania from NREL ReOpt) 262 | % Alternatively, can model assume fuel consumption cost to be quadratic function of DE power output (Parisio et al. 2014 and others) 263 | % But need to find right coefficients by data fitting 264 | % CO2 = CO2 + 3.5 * fuel_DE; % Total CO2 emissions (kg) using emission factor of 3.5 kg/L of diesel - source? 265 | CO2 = CO2 + 0.649 * P_DE(t); % Usign emission coefficient of 0.649 kg/kWh - Wu et al. 2016 266 | end 267 | 268 | if (DE_ON(1) == 1) 269 | DE_startup = DE_startup + SUC_DE; 270 | end 271 | 272 | % Upon completion of for loop i.e. after iterating through all hours of the year, C_fuel_DE now gives the total fuel cost over the 1st year of MG operation 273 | % It is assumed that on average, the annual fuel cost remains constant for all subsequent years of the system's lifetime 274 | Var_OM_DE = Variable_OM_DE * sum(DE_ON); 275 | 276 | % Total initial capital/installed cost 277 | IC = IC_s + IC_w + IC_LI + IC_DE + IC_inv; 278 | 279 | % Total annual recurring costs each year 280 | C_rec = OM_s + OM_w + OM_LI + Fixed_OM_DE + Var_OM_DE + C_fuel_DE + DE_startup + DE_shutdown; 281 | 282 | % Present worth of recurring costs 283 | PW_rec = C_rec * (((1+f)/(1+i))*(((1+f)/(1+i))^t_overall - 1))/(((1+f)/(1+i)) - 1); 284 | 285 | % Battery replaced every 15 years 286 | % i_adj_LI = (((1+i)^t_LI)/(1+f)^(t_LI - 1)) - 1; % Adjusted nominal interest rate 287 | % PW_LI_rep = RC_LI * (((1+f)/(1+i_adj_LI))*(((1+f)/(1+i_adj_LI))^t_overall - 1))/(((1+f)/(1+i_adj_LI)) - 1); 288 | 289 | % BS replaced every 5475 cycles 290 | t_LI_rep = (t_LI/cycles_LI); 291 | i_adj_LI = (((1+i)^t_LI_rep)/(1+f)^(t_LI_rep - 1)) - 1; % Adjusted nominal interest rate 292 | PW_LI_rep = RC_LI * (((1+f)/(1+i_adj_LI))*(((1+f)/(1+i_adj_LI))^t_overall - 1))/(((1+f)/(1+i_adj_LI)) - 1); 293 | 294 | % % DE replaced every 14 years 295 | % i_adj_DE = (((1+i)^t_DE)/(1+f)^(t_DE - 1)) - 1; % Adjusted nominal interest rate 296 | % PW_DE_rep = RC_DE * (((1+f)/(1+i_adj_DE))*(((1+f)/(1+i_adj_DE))^t_overall - 1))/(((1+f)/(1+i_adj_DE)) - 1); 297 | 298 | % Alternatively, determine frequency of DE replacement based on actual no. of operating hours per year 299 | t_DE_rep = (t_DE/sum(DE_ON)); % No. of years after which DE needs to be replaced 300 | i_adj_DE = (((1+i)^t_DE_rep)/(1+f)^(t_DE_rep - 1)) - 1; % Adjusted nominal interest rate 301 | PW_DE_rep = RC_DE * (((1+f)/(1+i_adj_DE))*(((1+f)/(1+i_adj_DE))^t_overall - 1))/(((1+f)/(1+i_adj_DE)) - 1); 302 | 303 | % Present worth of non-recurring costs 304 | PW_nonrec = PW_LI_rep + PW_DE_rep; 305 | 306 | TNPC = IC + PW_rec + PW_nonrec; % Total (lifecycle) net present cost of system ($) 307 | TAC = TNPC * CRF; % Total annualized cost ($) 308 | LCOE = TAC/sum(sum(Load)); % Energy cost/Levelized cost of electricity ($/kWh) 309 | 310 | % Base case for LCOE same as that for emissions - entire MG is run solely on a single DE 311 | % Total annual recurring costs each year 312 | Var_OM_DE = Variable_OM_DE * 8760; 313 | fuel_DE = 8760 * 0.08145 * P_DE_rated + 0.246 * sum(sum(Load)); 314 | C_fuel_DE = 3.20 * (fuel_DE / 3.78541); 315 | DE_startup = SUC_DE; 316 | DE_shutdown = SDC_DE; 317 | C_rec = Fixed_OM_DE + Var_OM_DE + C_fuel_DE + DE_startup + DE_shutdown; 318 | 319 | % Present worth of recurring costs 320 | PW_rec = C_rec * (((1+f)/(1+i))*(((1+f)/(1+i))^t_overall - 1))/(((1+f)/(1+i)) - 1); 321 | 322 | t_DE_rep = (t_DE/8760); % No. of years after which DE needs to be replaced 323 | i_adj_DE = (((1+i)^t_DE_rep)/(1+f)^(t_DE_rep - 1)) - 1; % Adjusted nominal interest rate 324 | PW_DE_rep = RC_DE * (((1+f)/(1+i_adj_DE))*(((1+f)/(1+i_adj_DE))^t_overall - 1))/(((1+f)/(1+i_adj_DE)) - 1); 325 | 326 | % Present worth of non-recurring costs 327 | PW_nonrec = PW_DE_rep; 328 | 329 | IC = IC_DE; 330 | TNPC = IC + PW_rec + PW_nonrec; % Total (lifecycle) net present cost of system ($) 331 | TAC = TNPC * CRF; % Total annualized cost ($) 332 | LCOE_base = TAC/sum(sum(Load)); % Energy cost/Levelized cost of electricity ($/kWh) 333 | 334 | % Emissions factors - EPA database (all in g) 335 | % Alternative source: Wu et al. 2014 336 | CO = 4.063288937 * sum(P_DE); 337 | NOx = 18.85658039 * sum(P_DE); 338 | SO2 = 0.007381439 * sum(P_DE); 339 | VOC = 1.502443664 * sum(P_DE); 340 | PM = 1.338208931 * sum(P_DE); 341 | PM10 = 1.338208931 * sum(P_DE); 342 | PM25 = 1.338208931 * sum(P_DE); 343 | Emissions = CO2 + (CO + NOx + SO2 + VOC + PM + PM10 + PM25)/1000; 344 | 345 | % Reliability measure - % of load that's not not met 346 | DPSP = sum(P_lost)/sum(sum(Load)); 347 | 348 | % Excess/dump energy as a fraction of total generation 349 | E_gen = sum(P_DE * eta_rec + P_RES); % Total annual DC electrical energy output = P_gen * delta_t = P_gen (in kWh) since delta_t = 1 h 350 | Dump = sum(P_dump)/E_gen; 351 | 352 | % Renewable penetration 353 | REF = sum(P_RES)/E_gen; 354 | 355 | Costs = [LCOE/LCOE_base Emissions/Emissions_base DPSP Dump 1-REF] 356 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 357 | cost = Costs * w'; 358 | 359 | end -------------------------------------------------------------------------------- /Objective_LI_DE_v7_1h_dispatch.m: -------------------------------------------------------------------------------- 1 | function [P_RES, P_s, P_w, P_b_LI, P_DE, Loads, P_dump, soc_LI] = Objective_LI_DE_v7_1h_dispatch(x) 2 | % To compute actual dispatch used for optimal sizing 3 | 4 | % Function performs optimal dispatch to output overall weighted cost function that needs to be minimized 5 | % Variable inputs (that we minimize w.r.t) are: 6 | % no. of solar PV arrays, no. of wind turbines, initial battery capacity (in kWh) 7 | n_s = x(1); 8 | n_w = x(2); 9 | Eb_init = x(3); 10 | 11 | % Given fixed inputs: Wind speed, ambient external air temperature, solar radiation, electricity demand 12 | % Have all of this data available over a whole year with hourly resolution 13 | 14 | % LOAD ALL FIXED EXTERNAL/EXOGENOUS INPUT VARIABLES 15 | load('irradiance.mat'); % Solar insolation/irradiance (kW/m^2) 16 | load('temp.mat'); % Ambient air temperature (C) 17 | load('wind_speed.mat'); % (m/s) 18 | load('Load.mat'); % Hourly power (kW) demand profiles 19 | % Hourly energy demand profile = power demand * time interval 20 | 21 | % Initialize variables 22 | P_s = zeros(1,8760); % (kW) - DC 23 | P_w = zeros(1,8760); % (kW) - AC 24 | P_DE = zeros(1,8760); % (kW) - AC 25 | P_b_LI = zeros(1,8760); % (kW) - DC 26 | Loads = zeros(1,8760); 27 | P_RES = zeros(1,8760); % (kW) - DC 28 | P_dump = zeros(1,8760); % Excess power (RES output) sent to dump loads/ground as DC (kW) 29 | soc_LI = zeros(1,8761); % between 0 and 1 30 | DE_ON = zeros(1,8760); % Boolean variable to keep track of whether DE is online/committed during that hour 31 | % Lost load or Amount of demand response (curtailment/shifting) needed to balance MG 32 | P_lost = zeros(1,8760); % (kW) - AC 33 | 34 | % COSTS 35 | i = 0.09; % Nominal interest/discount rate (https://tradingeconomics.com/kenya/interest-rate) 36 | f = 0.057; % Inflation/escalation rate (https://tradingeconomics.com/kenya/inflation-cpi) 37 | r = (i-f)/(1+f); % Real discount/interest rate 38 | t_overall = 25; % Overall system lifetime (y) = lifetime of solar (longest surviving components) 39 | CRF = (r*(1+r)^t_overall)/((1+r)^t_overall - 1); % Capital recovery factor 40 | 41 | % Startup and shutdown costs of conventional generators 42 | DE_startup = 0; 43 | DE_shutdown = 0; 44 | 45 | % Fuel costs 46 | C_fuel_DE = 0; 47 | 48 | % Fixed system parameters 49 | % SOLAR 50 | % PV panel specs from https://www.mitsubishielectricsolar.com/images/uploads/documents/specs/MLU_spec_sheet_250W_255W.pdf 51 | % For 255 W system - Monocrystalline Si 52 | eta_r = 0.154; % Manufacturer rated efficiency 53 | T_r = 25; % Standard test conditions (reference cell temperature) 54 | I_PV_NOCT = 0.8; % Hourly solar irradiance at NOCT - Normal/nominal operating cell temp (in kW/m^2) 55 | T_c_NOCT = 45.7; % PV cell temp at NOCT (Celsius) 56 | T_a_NOCT = 20; % Ambient temp at NOCT (Celsius) 57 | Ps_rated = 255; % (W) 58 | Ps_rated_total = n_s * Ps_rated; 59 | beta_s = 0.0045; % Temp coefficient of module/generator efficiency (of Pmax) 60 | t_s = 25; % Lifetime of solar PV array (y) 61 | eta_pc = 1; % Power conditioning efficiency (= 1 or 100% since it's assumed that a perfect MPPT is used) 62 | IC_s = (Ps_rated_total/1000) * 1210; % Assuming installed PV costs of $1210/kW (source: IRENA costs report 2018, total installed costs) 63 | % likely to be a slight underestimate since this is the global weighted 64 | % average for larger utility scale projects 65 | OM_s = (1/100)*IC_s; % Fixed annual O&M costs ($/y) - from Kaabeche et al. 2011a 66 | 67 | % WIND 68 | beta_w = 1/7; % Typical value of power law exponent for open land 69 | % Use data from this spec sheet: https://farm-energy.extension.org/wp-content/uploads/2019/04/3.5kW_Spec_Sheet.pdf 70 | h_ref = 1; % Installation height of TAHMO measurement stations (m) - wind speed measured approx. at sea level 71 | h_hub = 14.5; % Tower height to hub/nacelle (m) 72 | Pw_rated = 3.5; % (kW) 73 | Pw_rated_total = n_w * Pw_rated; 74 | IC_w = Pw_rated_total * 1500; % Global weighted average total installed costs of onshore wind ($/kW) - IRENA 2018 75 | 76 | OM_w = (3/100)*IC_w; % Fixed annual O&M costs ($/y) 77 | t_w = 20; % Lifetime of wind turbine system (y) 78 | v_c = 2.8; % Cut-in or start-up wind speed (m/s) 79 | v_r = 11; % Rated wind speed (m/s) 80 | v_f = 22; % Cut-out or failure/braking speed (m/s) 81 | A = (1/(v_c^2 - v_r^2)) * (v_c*(v_c + v_r) - 4*v_c*v_r*((v_c + v_r)/(2*v_r))^3); 82 | B = (1/(v_c^2 - v_r^2)) * (4*(v_c + v_r)*((v_c + v_r)/(2*v_r))^3 - 3*(v_c + v_r)); 83 | C = (1/(v_c^2 - v_r^2)) * (2 - 4*((v_c + v_r)/(2*v_r))^3); 84 | 85 | % Li-ion battery system - from https://www.nrel.gov/docs/fy16osti/64987.pdf 86 | % Updated parameters for powerwall - https://www.tesla.com/en_GB/powerwall 87 | SOC_min_LI = 0.1; 88 | SOC_max_LI = 0.9; % DoD for LI = 80% (https://www.spiritenergy.co.uk/kb-batteries-understanding-batteries) 89 | delta = 0.075; % Self-discharge rate of battery (7.5%/month) 90 | P_max_LI = 3.68; % Max continuous real power (kW), 5 kW peak 91 | delta_hour = delta/30.5; % Hourly self-discharge rate (%/h) 92 | eta_overall = 0.90; % Battery round trip coulombic efficiency (accounts for both charge & discharge) - from Hu et al. 2017 93 | cycles_LI = 0; % Keeps track of cumulative no. of charge/discharge cycles so far 94 | cycled = 0; % Keeps track of whether the BS has already been self-discharged in the current time step 95 | % IC1_LI = 300; % Initial energy/capacity capital costs ($/kWh) - NREL 96 | % IC2_LI = 120; % Initial power capital costs ($/kW) 97 | % IC_LI = IC1_LI * Eb_init + IC2_LI * P_max_LI; % Total initial capital costs for LI 98 | IC_LI = 300 * Eb_init; % Assuming a price of $300/kWh 99 | OM_LI = (1/100) * IC_LI; % from Kaabeche et al. 2011a ($/y) 100 | RC_LI = 0.9*IC_LI; % Replacement cost at end of service period/lifetime - assumed to be 90% of IC since new installation and permitting fees aren't incurred 101 | Eb_init = Eb_init*3.6e6; % 1 W = 1 J/s 102 | E_C = Eb_init; % Actual capacity is initially at rated maximum (J) 103 | %t_LI = 15; % Average lifetime of Li-ion battery (y) - 5 years beyond Tesla powerwall warranty period 104 | t_LI = 5475; % cycles 105 | 106 | % Diesel generator specs from Moshi et al. 2016 107 | P_DE_rated = 16; % Rated maximum power of diesel generator (kW) = approx. peak load * 1.5 108 | P_DE_min = 4.8; % Lower limit on power (kW) or k_gen * P_rated (k_gen = 0.3) from Fathima et al. 109 | Ramp = (P_DE_rated*1000)/10; % Max ramp rate of DE (W/min) - NERC disturbance control standard, DG must be able to reach rated capacity within 10 min 110 | % Ramp_up = 0.006038 - 0.000003840*(P_DE_rated/10e3); % from ramp_rates.pdf (as % of nameplate capacity per minute) 111 | % Ramp_down = 0.006783 - 0.000004314*(P_DE_rated/10e3); 112 | IC_DE = 12500; % Initial capital cost for 16 kW rated DE ($) - slightly higher than replacement 113 | RC_DE = 11000; % Replacement cost ($) 114 | Fixed_OM_DE = (2/100)*IC_DE; % Fixed O&M costs ($/y) 115 | Variable_OM_DE = 0.24; % Variable O&M costs ($/h of operation online) 116 | SUC_DE = 0.45; % Start-up cost ($) 117 | SDC_DE = 0.23; % Shut-down cost ($) 118 | % t_DE = 14; % Average lifetime of diesel engine (y) - avg expected life expectancy (https://www.wpowerproducts.com/news/diesel-engine-life-expectancy/) 119 | t_DE = 15000; % Lifetime (h), from Moshi et al. 2016 120 | 121 | % Bidirectional converter between AC and DC buses (can act as either rectifier or inverter) 122 | eta_inv = 0.9; % Inverter efficiency (Ogunjuyigbe et al. 2016) 123 | eta_rec = eta_inv; % Both rectifier and inverter assumed to have same parameters (Moshi et al. 2016) 124 | t_inv = 20; % Lifetime of converter (y) - Moshi et al. 2016 125 | P_inv_rated = 12.52; % Maximum rated power of inverter (kW) 126 | IC_inv = 2800; % ($) 127 | % Assume converter has zero maintenance costs 128 | 129 | % Start with delta_t = 1 h and then maybe discretize over smaller time intervals 130 | delta_t = 3600; % Calculation period (s) = 1 hour 131 | 132 | hour = 0; % Keeps track of the hour in the day 133 | 134 | for t = 1:1:8760 % Simulate over one year with a time-step of 1 h 135 | 136 | Excess_demand = 0; 137 | 138 | % SOLAR 139 | I = irradiance(t); % Hourly solar irradiance (kW/m^2) 140 | T_a = temp(t); 141 | eta_PV = eta_r * (1 - 0.9 * beta_s * (I/I_PV_NOCT) * (T_c_NOCT - T_a_NOCT) - beta_s * (T_a - T_r)); % Tazvinga et al. 2013 142 | % Alternative model - Kaabeche et al. 2011b 143 | % T_c = T_a + ((T_c_NOCT - 20)/0.8)*I; % Cell temp (C) 144 | % eta_PV = eta_r * eta_pc * (1 - beta_s*(T_c - T_r)); 145 | A_c = 120 * 78e-3 * 156e-3; % Surface area of 1 panel rated at 255 W (m^2) 146 | P_s(t) = n_s * eta_PV * A_c * I; % Solar power output (kW) - DC 147 | 148 | if (P_s(t) > Ps_rated_total) 149 | P_s(t) = Ps_rated_total; 150 | end 151 | 152 | % WIND 153 | v_ref = wind_speed(t); 154 | v_hub = v_ref * (h_hub/h_ref)^beta_w; % Wind speed at hub calculated from measured speed at reference anemometer height 155 | 156 | if (v_hub < v_c || v_hub > v_f) 157 | P_w(t) = 0; 158 | elseif (v_c <= v_hub && v_hub <= v_r) 159 | P_w(t) = Pw_rated_total * (A + B * v_hub + C * v_hub^2); % Source? 160 | % Alternative formula - Borhanazad et al. 2014 161 | % Pw = ((v_hub^3)*P_rated - P_rated*v_cutin^3)/(v_rated^3 - v_cutin^3); 162 | % Also include commonly known formula using Cp and swept area? 163 | % But need to know variation of Cp with TSR for my specific WT model 164 | else 165 | P_w(t) = Pw_rated_total; % Wind power output (kW) - AC 166 | end 167 | 168 | % Rectify AC power from WT to DC 169 | P_RES(t) = P_w(t)*eta_rec + P_s(t); % Total renewable power output available at DC bus (kW) 170 | 171 | % BATTERY 172 | % Assume battery starts out fully charged (at max safe SOC) 173 | if (t == 1) 174 | soc_LI(t) = 0.9; 175 | end 176 | 177 | if (soc_LI(t) > SOC_max_LI) 178 | soc_LI(t) = SOC_max_LI; 179 | end 180 | 181 | if (soc_LI(t) < SOC_min_LI) 182 | soc_LI(t) = SOC_min_LI; 183 | end 184 | 185 | if (t ~= 1 && soc_LI(t) == SOC_max_LI && soc_LI(t-1) < SOC_max_LI) % Complete 1 charge-discharge cycle 186 | cycles_LI = cycles_LI + 1; % Increment cycle number 187 | E_C = Eb_init*(1 - (cycles_LI*0.055e-3)); % Capacity fading with cycling - https://www.nrel.gov/docs/fy16osti/64987.pdf 188 | end 189 | 190 | day_number = ceil(t/24); 191 | if (hour >= 24) 192 | hour = 0; 193 | end 194 | hour = hour + 1; 195 | P_load = Load(day_number,hour); % (kW) - AC 196 | Loads(t) = Load(day_number,hour); 197 | 198 | if (P_RES(t) == P_load/eta_inv) % Since RES power needs to inverted to meet AC load 199 | continue 200 | elseif (P_RES(t) > P_load/eta_inv) % Excess supply/generation 201 | if (soc_LI(t) >= SOC_max_LI) % Battery can't be charged further 202 | P_dump(t) = P_RES(t) - P_load/eta_inv; % Send excess power to dump loads/ground - DC 203 | else % Charge battery system 204 | if (P_RES(t) - P_load/eta_inv <= P_max_LI) 205 | P_b_LI(t) = -(P_RES(t) - P_load/eta_inv); % (kW) 206 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 207 | cycled = 1; 208 | else 209 | P_b_LI(t) = -P_max_LI; 210 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 211 | P_dump(t) = P_RES(t) - P_load/eta_inv - P_max_LI; 212 | cycled = 1; 213 | end 214 | end 215 | else % Insufficient supply/generation 216 | Excess_demand = P_load/eta_inv - P_RES(t); % DC 217 | if (soc_LI(t) > SOC_min_LI) % Discharge battery 218 | if (Excess_demand <= P_max_LI) 219 | P_b_LI(t) = Excess_demand; 220 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 221 | Excess_demand = 0; % All load has been met/satisfied 222 | cycled = 1; 223 | else 224 | P_b_LI(t) = P_max_LI; 225 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) - P_b_LI(t)*1000*delta_t*(eta_overall/E_C); 226 | Excess_demand = Excess_demand - P_max_LI; 227 | cycled = 1; 228 | end 229 | elseif (soc_LI(t) <= SOC_min_LI || Excess_demand > 0) % Need to use backup DE to meet excess load 230 | DE_ON(t) = 1; % Turn DE on 231 | % Power produced by DE is already AC - so can directly meet load 232 | Excess_demand = Excess_demand * eta_inv; % AC 233 | if (Excess_demand <= P_DE_rated) 234 | if (Excess_demand >= P_DE_min) 235 | P_DE(t) = Excess_demand; 236 | % No dumped load 237 | else 238 | P_DE(t) = P_DE_min; 239 | P_dump(t) = (P_DE_min - Excess_demand) * eta_rec; % (kW) - DC 240 | % If we allow excess generator output to charge battery 241 | % DE output must 1st be rectified to DC before charging battery 242 | if (soc_LI(t) < SOC_max_LI) 243 | if (P_dump(t) <= P_max_LI) 244 | if (cycled == 0) % Battery hasn't been cycled/operated yet before in this time step 245 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) + P_dump(t)*1000*delta_t*(eta_overall/E_C); 246 | else % Battery has already been cycled so don't include self-discharge again 247 | soc_LI(t+1) = soc_LI(t+1) + P_dump(t)*1000*delta_t*(eta_overall/E_C); 248 | end 249 | P_dump(t) = 0; 250 | else 251 | if (cycled == 0) % Battery hasn't been cycled/operated yet before in this time step 252 | soc_LI(t+1) = soc_LI(t)*(1-delta_hour) + P_max_LI*1000*delta_t*(eta_overall/E_C); 253 | else % Battery has already been cycled so don't include self-discharge again 254 | soc_LI(t+1) = soc_LI(t+1) + P_max_LI*1000*delta_t*(eta_overall/E_C); 255 | end 256 | P_dump(t) = P_dump(t) - P_max_LI; 257 | end 258 | end 259 | end 260 | else 261 | P_DE(t) = P_DE_rated; 262 | P_lost(t) = Excess_demand - P_DE_rated; 263 | end 264 | 265 | else 266 | DE_ON(t) = 0; % Turn DE off 267 | end 268 | end 269 | 270 | cycled = 0; % Reset 271 | end 272 | 273 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ET-MPhil 2 | 3 | If you use this code for your project - please include the following citation: 4 | 5 | Jagadeesan Nair, V. "Optimal Design & Energy Management of Islanded, Hybrid Microgrids For Remote, Isolated Off-Grid Communities with No External Power Exchange." Preprints 2022, 2022120416 (doi: 10.20944/preprints202212.0416.v1). 6 | 7 | Code for multiobjective optimization of hybrid islanded (off-grid) microgrids in sub-Saharan Africa. With renewables, battery storage, micro gas turbines and diesel generators. 8 | 9 | Compare different multiobjective optimization algorithms in MATLAB. Cost-modelling for optimal microgrid design, sizing and dispatch/energy management. 10 | -------------------------------------------------------------------------------- /SOC_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/SOC_3d.png -------------------------------------------------------------------------------- /Sizing_LI-DE_3equal123_paretosearch_Ps_Pw_200pts_DG7kW.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_3equal123_paretosearch_Ps_Pw_200pts_DG7kW.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_4equal_gamultiobj_Ps_Pw_fraction0.5_DG7kW.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_4equal_gamultiobj_Ps_Pw_fraction0.5_DG7kW.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_4equal_paretosearch_Ps_Pw_200pts_DG7kW.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_4equal_paretosearch_Ps_Pw_200pts_DG7kW.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_5equal_gamultiobj_Ps_Pw_fraction0.5.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_5equal_gamultiobj_Ps_Pw_fraction0.5.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_5equal_gamultiobj_Ps_Pw_fraction0.5_DG7kW.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_5equal_gamultiobj_Ps_Pw_fraction0.5_DG7kW.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_5equal_gamultiobj_ns_nw_fraction0.5.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_5equal_gamultiobj_ns_nw_fraction0.5.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_5equal_paretosearch_Ps_Pw_200pts.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_5equal_paretosearch_Ps_Pw_200pts.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_5equal_paretosearch_Ps_Pw_200pts_DG7kW.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_5equal_paretosearch_Ps_Pw_200pts_DG7kW.mat -------------------------------------------------------------------------------- /Sizing_LI-DE_5equal_paretosearch_ns_nw_200pts.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_LI-DE_5equal_paretosearch_ns_nw_200pts.mat -------------------------------------------------------------------------------- /Sizing_VaryParams.m: -------------------------------------------------------------------------------- 1 | %% Varying parameters in sizing optimization 2 | % Including variable weights on multiobjective 3 | % Optimizing w.r.t n_s, n_w, Eb_init 4 | 5 | %% Varying DG rated power 6 | rng default % For reproducibility of results (needed for random algorithm) 7 | options = optimoptions('particleswarm', 'UseParallel', true, ... 8 | 'UseVectorized', false); 9 | nvars = 3; 10 | lb = [0,0,0]; 11 | ub = [100,30,200]; 12 | 13 | % Use opt. x solutions later to calculate 5 individual objectives, DE hours & BS cycles! 14 | 15 | DE_rating = 0:1:20; % in kW 16 | x = zeros(size(DE_rating,2),3); 17 | fval = zeros(size(DE_rating,2),1); 18 | 19 | tic 20 | for i = 1:1:size(DE_rating,2) 21 | P_DE_rated = DE_rating(i); 22 | Objective = @(x) Objective_LI_DE_v9_1h_ind_VaryParams(x,P_DE_rated); 23 | [x(i,:),fval(i)] = particleswarm(Objective,nvars,lb,ub,options); 24 | end 25 | param_time = toc; 26 | 27 | % Normalized LCOE and emissions values for lower ratings may be artificially inflated 28 | % slightly, since these are now being considered relative to a smaller size 29 | % DG that may not satisfy all load in base case 30 | 31 | %% Varying fuel (diesel price) 32 | % Can also account for effect of carbon tax or fossil fuel subsidies 33 | % Range of global diesel prices - https://www.globalpetrolprices.com/diesel_prices/ 34 | rng default % For reproducibility of results (needed for random algorithm) 35 | options = optimoptions('particleswarm', 'UseParallel', true, ... 36 | 'UseVectorized', false); 37 | nvars = 3; 38 | lb = [0,0,0]; 39 | ub = [100,30,200]; 40 | 41 | C_DE = linspace(0.2,12,20); % in $/gal 42 | x = zeros(size(C_DE,2),3); 43 | fval = zeros(size(C_DE,2),1); 44 | 45 | tic 46 | for i = 1:1:size(C_DE,2) 47 | DE_price = C_DE(i); 48 | Objective = @(x) Objective_LI_DE_v9_1h_ind_VaryParams(x,DE_price); 49 | [x(i,:),fval(i)] = particleswarm(Objective,nvars,lb,ub,options); 50 | end 51 | param_time = toc; 52 | 53 | %% Varying nominal interest/discount rate 54 | rng default % For reproducibility of results (needed for random algorithm) 55 | options = optimoptions('particleswarm', 'UseParallel', true, ... 56 | 'UseVectorized', false); 57 | nvars = 3; 58 | lb = [0,0,0]; 59 | ub = [100,30,200]; 60 | 61 | inflation = linspace(0,0.2,20); % in (%) 62 | x = zeros(size(inflation,2),3); 63 | fval = zeros(size(inflation,2),1); 64 | 65 | tic 66 | for i = 1:1:size(inflation,2) 67 | interest_rate = inflation(i); 68 | Objective = @(x) Objective_LI_DE_v9_1h_ind_VaryParams(x,interest_rate); 69 | [x(i,:),fval(i)] = particleswarm(Objective,nvars,lb,ub,options); 70 | end 71 | param_time = toc; 72 | 73 | %% Varying inflation rate 74 | rng default % For reproducibility of results (needed for random algorithm) 75 | options = optimoptions('particleswarm', 'UseParallel', true, ... 76 | 'UseVectorized', false); 77 | nvars = 3; 78 | lb = [0,0,0]; 79 | ub = [100,30,200]; 80 | 81 | inflation = linspace(0,0.15,20); % in (%) 82 | x = zeros(size(inflation,2),3); 83 | fval = zeros(size(inflation,2),1); 84 | 85 | tic 86 | for i = 1:1:size(inflation,2) 87 | inflation_rate = inflation(i); 88 | Objective = @(x) Objective_LI_DE_v9_1h_ind_VaryParams(x,inflation_rate); 89 | [x(i,:),fval(i)] = particleswarm(Objective,nvars,lb,ub,options); 90 | end 91 | param_time = toc; 92 | 93 | %% Vary LI BS price 94 | rng default % For reproducibility of results (needed for random algorithm) 95 | options = optimoptions('particleswarm', 'UseParallel', true, ... 96 | 'UseVectorized', false); 97 | nvars = 3; 98 | lb = [0,0,0]; 99 | ub = [100,30,200]; 100 | 101 | BS_price = linspace(50,300,20); % in ($/kWh) 102 | x = zeros(size(BS_price,2),3); 103 | fval = zeros(size(BS_price,2),1); 104 | 105 | tic 106 | for i = 1:1:size(BS_price,2) 107 | BS = BS_price(i); 108 | Objective = @(x) Objective_LI_DE_v9_1h_ind_VaryParams(x,BS); 109 | [x(i,:),fval(i)] = particleswarm(Objective,nvars,lb,ub,options); 110 | end 111 | param_time = toc; 112 | 113 | %% Varying relative values of weights 114 | rng default % For reproducibility of results (needed for random algorithm) 115 | options = optimoptions('particleswarm', 'UseParallel', true, ... 116 | 'UseVectorized', false); 117 | nvars = 3; 118 | lb = [0,0,0]; 119 | ub = [100,30,200]; 120 | 121 | w3 = linspace(0,1,11); 122 | dim = size(w3,2); 123 | x = zeros(dim,3); 124 | fval = zeros(dim,1); 125 | 126 | tic 127 | for i = 1:1:dim 128 | w = w3(i); 129 | Objective = @(x) Objective_LI_DE_v9_1h_ind_VaryParams(x,w); 130 | [x(i,:),fval(i)] = particleswarm(Objective,nvars,lb,ub,options); 131 | end 132 | param_time = toc; 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /Sizing_Vary_BS_price.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_BS_price.mat -------------------------------------------------------------------------------- /Sizing_Vary_DE_Rating_0-20.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_DE_Rating_0-20.mat -------------------------------------------------------------------------------- /Sizing_Vary_DE_price.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_DE_price.mat -------------------------------------------------------------------------------- /Sizing_Vary_inflation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_inflation.mat -------------------------------------------------------------------------------- /Sizing_Vary_interest.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_interest.mat -------------------------------------------------------------------------------- /Sizing_Vary_w1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_w1.mat -------------------------------------------------------------------------------- /Sizing_Vary_w2.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_w2.mat -------------------------------------------------------------------------------- /Sizing_Vary_w3.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_w3.mat -------------------------------------------------------------------------------- /Sizing_Vary_w3_DGrated_7kW.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_w3_DGrated_7kW.mat -------------------------------------------------------------------------------- /Sizing_Vary_w4.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_w4.mat -------------------------------------------------------------------------------- /Sizing_Vary_w5.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Sizing_Vary_w5.mat -------------------------------------------------------------------------------- /Sizing_opt.m: -------------------------------------------------------------------------------- 1 | % ERROR: Conversion to double from cvx is not possible 2 | cvx_begin 3 | variable n_s integer 4 | variable n_w integer 5 | variable Eb_init 6 | cost = Objective_LI_DE_no_DR_v2([n_s, n_w, Eb_init]); 7 | minimize cost 8 | subject to 9 | x_s >= 1e-4, x_w >= 1e-4, Eb_init >= 1e-4 10 | cvx_end -------------------------------------------------------------------------------- /Sizing_opt_v2.m: -------------------------------------------------------------------------------- 1 | % Sizing optimization using MATLAB's inbuilt toolboxes 2 | 3 | %% Using fminsearch - https://uk.mathworks.com/help/matlab/ref/fminsearch.html 4 | % % But need to constrain variables to be non-negative 5 | % x0 = [1, 1, 10]; % Initial guess for n_s, n_w, Eb_init 6 | % x = fminsearch(@Objective_LI_DE_no_DR,x0) 7 | 8 | %% Using fmincon (https://uk.mathworks.com/help/optim/ug/example-nonlinear-constrained-minimization.html) 9 | % Solve a Constrained Nonlinear Problem, Solver-Based - fmincon(https://uk.mathworks.com/help/optim/ug/fmincon.html) 10 | 11 | % options = optimoptions(@fmincon,... 12 | % 'Display','iter','Algorithm','interior-point','StepTolerance',1e-12,'ConstraintTolerance',1e-12,... 13 | % 'FunctionTolerance',1e-12,'MaxIterations',10000, 'MaxFunctionEvaluations',10000); 14 | 15 | options = optimoptions(@fmincon,... 16 | 'Display','iter','Algorithm','interior-point'); 17 | [x,fval,exitflag,output] = fmincon(@Objective_LI_DE_v2_1h,[0 0 0],... 18 | [],[],[],[],[],[],@positive,options) 19 | 20 | % Works well to give a reasonable result at least when using 5 equal weights 21 | % But takes a large no. of iterations to converge, might be a local minimum rather than a global one! 22 | 23 | %% GlobalSearch (https://uk.mathworks.com/help/gads/globalsearch.html) 24 | % No longer need to specify constraints on inputs explicitly since it's now 25 | % a bounded constrained optimization (positive constraint is enforced by lower bound) 26 | % Maybe remove upper bound constraint - don't need to explicitly specify this? 27 | 28 | rng default % For reproducibility 29 | ms = MultiStart('UseParallel',true); 30 | gs = GlobalSearch(ms); 31 | options = optimoptions(@fmincon, 'Display','iter','Algorithm','active-set',... 32 | 'MaxIterations',2000,'MaxFunctionEvaluations',2000,'UseParallel',true); 33 | %'PlotFcn',{@gsplotbestf,@gsplotfunccount}); 34 | % Can't plot with GS or MS while using parallel processing 35 | problem = createOptimProblem('fmincon','objective',@Objective_LI_DE_v2_1h,'x0',[50 3.5 50],... 36 | 'lb',[0,0,0],'ub',[100,30,200],'options',options); 37 | tic 38 | [x, fval] = run(gs,problem) 39 | gs_time = toc; % Time taken for optimization 40 | 41 | %% Multiple starting point search (https://uk.mathworks.com/help/gads/multistart.html) 42 | rng default % For reproducibility 43 | options = optimoptions(@fmincon,'Display','iter',... 44 | 'Algorithm','active-set','MaxIterations',2000,'MaxFunctionEvaluations',2000); 45 | problem = createOptimProblem('fmincon','objective',... 46 | @Objective_LI_DE_v2_1h,'x0',[50 3.5 50],... 47 | 'lb',[0,0,0],'ub',[100,30,200],'options',options); 48 | ms = MultiStart('UseParallel',true); 49 | tic 50 | [x,f] = run(ms,problem,85) 51 | ms_time = toc; 52 | 53 | %% Direct pattern search (https://uk.mathworks.com/help/gads/patternsearch.html) 54 | % Pattern search using several different initial/start points 55 | rng default % For reproducibility 56 | lb = [0,0,0]; 57 | ub = [100,30,200]; 58 | A = []; 59 | b = []; 60 | Aeq = []; 61 | beq = []; 62 | 63 | x = zeros(85,3); 64 | fval = zeros(85,1); 65 | exitflag = zeros(85,1); 66 | options = optimoptions('patternsearch','UseParallel',true,'UseCompletePoll',true,... 67 | 'UseVectorized',false); 68 | 69 | %PlotFcn',{@psplotbestf,psplotbestx,psplotmeshsize,psplotfuncount} 70 | 71 | tic 72 | for i = 1:1:85 73 | x0 = lb + rand(size(lb)).*(ub - lb); 74 | [x(i,:), fval(i), exitflag(i)] = patternsearch(@Objective_LI_DE_v2_1h,x0,A,b,Aeq,beq,lb,ub,options); 75 | end 76 | 77 | [min_obj, index] = min(fval) 78 | x_opt = x(index,:) 79 | ps_time = toc; 80 | 81 | %% Genetic algorithm (GA) 82 | rng default % For reproducibility 83 | lb = [0,0,0]; 84 | ub = [100,30,200]; 85 | fitness_function = @Objective_LI_DE_v2_1h; 86 | nvars = 3; % number of variables 87 | options = optimoptions('ga','UseParallel', true, 'UseVectorized', false,... 88 | 'PlotFcn','gaplotgenealogy'); 89 | %@gaplotbestf,@gaplotbestindiv,@gaplotrange, 90 | tic 91 | [x,fval] = ga(fitness_function,nvars,[],[],[],[],lb,ub,[],options) 92 | ga_time = toc; 93 | 94 | %% Plotting objective 95 | plotobjective(@Objective_LI_DE_v2_1h,[0 30; 0 10; 0 100]); 96 | 97 | %% Genetic algorithm (GA) - vectorized 98 | rng default % For reproducibility 99 | lb = [0,0,0]; 100 | ub = [100,20,200]; 101 | fitness_function = @Objective_LI_DE_v2_1h_vectorized; 102 | nvars = 3; % number of variables 103 | options = optimoptions('ga','UseParallel', true, 'UseVectorized', true); 104 | tic 105 | [x,fval] = ga(fitness_function,nvars,[],[],[],[],lb,ub,[],options) 106 | ga_time = toc; 107 | 108 | % But not easy to implement in this case due to the manner in which the 109 | % objective function is written, preallocate arrays for all the powers etc. 110 | %% PSO 111 | rng default % For reproducibility of results (needed for random algorithm) 112 | options = optimoptions('particleswarm', 'UseParallel', true, ... 113 | 'UseVectorized', false,'PlotFcn','pswplotbestf'); 114 | nvars = 3; 115 | lb = [0,0,0]; 116 | ub = [100,30,200]; 117 | tic 118 | [x,fval,exitflag] = particleswarm(@Objective_LI_DE_v2_1h,nvars,lb,ub,options) 119 | pso_time = toc; 120 | 121 | %% Surrogate optimization 122 | rng default 123 | lb = [0,0,0]; 124 | ub = [100,30,200]; 125 | options = optimoptions('surrogateopt','UseParallel',true,'MaxFunctionEvaluations',... 126 | 2000,'PlotFcn','surrogateoptplot'); 127 | tic 128 | [x,fval] = surrogateopt(@Objective_LI_DE_v2_1h,lb,ub,options); 129 | sur_time = toc; 130 | 131 | %% Simulated annealing 132 | rng default; 133 | lb = [0,0,0]; 134 | ub = [100,30,200]; 135 | 136 | x0 = [50 3.5 50]; % initial point 137 | options = optimoptions('simulannealbnd','PlotFcns',... 138 | {@saplotbestf,@saplotf,@saplotstopping}); 139 | tic 140 | [x,~,exitFlag,output] = simulannealbnd(@Objective_LI_DE_v2_1h,x0,lb,ub,options) 141 | sa_time = toc; 142 | 143 | %% PSO - but optimizing wrt rated powers instead 144 | rng default % For reproducibility of results (needed for random algorithm) 145 | options = optimoptions('particleswarm', 'UseParallel', true, ... 146 | 'UseVectorized', false,'PlotFcn','pswplotbestf'); 147 | nvars = 3; 148 | lb = [0,0,0]; 149 | ub = [25,25,200]; 150 | tic 151 | [x,fval,exitflag] = particleswarm(@Objective_LI_DE_v8_1h_optPrated,nvars,lb,ub,options) 152 | pso_time = toc; 153 | 154 | %% Pareto set using gamultiobj 155 | rng default; 156 | lb = [0,0,0]; 157 | ub = [100,10,200]; % for n_s, n_w, Eb_init 158 | tic 159 | options = optimoptions('gamultiobj','UseParallel',true,'UseVectorized',false,... 160 | 'ParetoFraction',0.50); 161 | [x_p,fval] = gamultiobj(@sizing_pareto,3,[],[],[],[],lb,ub,options); 162 | gamultiobj_time = toc; 163 | 164 | %% Pareto set with rated total powers as inputs instead of n_s/n_w 165 | rng default; 166 | options = optimoptions('gamultiobj','UseParallel',true,... 167 | 'UseVectorized',false,'ParetoFraction',0.50); 168 | lb = [0,0,0]; 169 | ub = [25,25,200]; 170 | tic 171 | [x_p,fval] = gamultiobj(@sizing_pareto,3,[],[],[],[],lb,ub,[],options); 172 | gamultiobj_time = toc; 173 | 174 | %% Pareto set/front using paretosearch (pattern search algorithm) 175 | rng default; 176 | options = optimoptions('paretosearch','UseParallel',true,... 177 | 'UseVectorized',false,'ParetoSetSize',200); 178 | lb = [0,0,0]; 179 | ub = [100,10,200]; % for rated P_s, P_w, Eb_init 180 | tic 181 | [x_p,fval] = paretosearch(@sizing_pareto,3,[],[],[],[],lb,ub,[],options); 182 | paretosearch_time = toc; 183 | 184 | %% Pareto set with rated total powers as inputs instead of n_s/n_w 185 | rng default; 186 | options = optimoptions('paretosearch','UseParallel',true,... 187 | 'UseVectorized',false,'ParetoSetSize',200); 188 | lb = [0,0,0]; 189 | ub = [25,25,200]; 190 | tic 191 | [x_p,fval] = paretosearch(@sizing_pareto,3,[],[],[],[],lb,ub,[],options); 192 | paretosearch_time = toc; 193 | 194 | %% 195 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 196 | cost = fval * w'; 197 | 198 | %% 3-D pareto set plot in control variable (inputs) space 199 | % 3D scatter plot 200 | % Plotting optimal values of n_s, n_w and Eb_init 201 | scatter3(x_p(:,1),x_p(:,2),x_p(:,3),10,'b','filled') 202 | xlabel('No. of solar PV arrays'); 203 | ylabel('No. of wind turbines'); 204 | zlabel('Battery capacity (kWh)'); 205 | 206 | %% Interpolated surface plot 207 | figure(1) 208 | x = x_p(:,1); 209 | y = x_p(:,2); 210 | z = x_p(:,3); 211 | F = scatteredInterpolant(x,y,z,'natural','none'); 212 | sgr = linspace(min(x),max(x)); 213 | ygr = linspace(min(y),max(y)); 214 | [XX,YY] = meshgrid(sgr,ygr); 215 | ZZ = F(XX,YY); 216 | surf(XX,YY,ZZ,'LineStyle','none') 217 | hold on 218 | scatter3(x,y,z,5,'k','filled') 219 | %scatter3(x,y,z,'k.') 220 | 221 | %% Griddata 222 | figure(2) 223 | x = x_p(:,1); 224 | y = x_p(:,2); 225 | z = x_p(:,3); 226 | sgr = linspace(min(x),max(x)); 227 | ygr = linspace(min(y),max(y)); 228 | [XX,YY] = meshgrid(sgr,ygr); 229 | ZZ = griddata(x,y,z,XX,YY,'natural'); 230 | %mesh(xq,yq,zq); 231 | surf(XX,YY,ZZ,'LineStyle','none'); 232 | hold on 233 | plot3(x,y,z,'k.') 234 | 235 | %% Rotated views 236 | figure 237 | subplot(2,2,1) 238 | surf(XX,YY,ZZ,'LineStyle','none') 239 | hold on 240 | scatter3(x,y,z,'k.'); 241 | hold off 242 | subplot(2,2,2) 243 | surf(XX,YY,ZZ,'LineStyle','none') 244 | hold on 245 | scatter3(x,y,z,'k.'); 246 | hold off 247 | view(-148,8) 248 | subplot(2,2,3) 249 | surf(XX,YY,ZZ,'LineStyle','none') 250 | hold on 251 | scatter3(x,y,z,'k.'); 252 | hold off 253 | view(-180,8) 254 | subplot(2,2,4) 255 | surf(XX,YY,ZZ,'LineStyle','none') 256 | hold on 257 | scatter3(x,y,z,'k.'); 258 | hold off 259 | view(-300,8) 260 | 261 | %% Rotated separate figures 262 | font = 15; 263 | figure(1) 264 | surf(XX,YY,ZZ,'LineStyle','none') 265 | hold on 266 | scatter3(x,y,z,'k.'); 267 | hold off 268 | xlabel('No. of solar PV arrays'); 269 | ylabel('No. of wind turbines'); 270 | zlabel('Battery capacity (kWh)'); 271 | set(gca,'FontSize',font); 272 | figure(2) 273 | surf(XX,YY,ZZ,'LineStyle','none') 274 | hold on 275 | scatter3(x,y,z,'k.'); 276 | hold off 277 | view(-148,8) 278 | xlabel('No. of solar PV arrays'); 279 | ylabel('No. of wind turbines'); 280 | zlabel('Battery capacity (kWh)'); 281 | set(gca,'FontSize',font); 282 | figure(3) 283 | surf(XX,YY,ZZ,'LineStyle','none') 284 | hold on 285 | scatter3(x,y,z,'k.'); 286 | hold off 287 | view(-180,8) 288 | xlabel('No. of solar PV arrays'); 289 | ylabel('No. of wind turbines'); 290 | zlabel('Battery capacity (kWh)'); 291 | figure(4) 292 | surf(XX,YY,ZZ,'LineStyle','none') 293 | hold on 294 | scatter3(x,y,z,'k.'); 295 | hold off 296 | view(-300,8) 297 | xlabel('No. of solar PV arrays'); 298 | ylabel('No. of wind turbines'); 299 | zlabel('Battery capacity (kWh)'); 300 | set(gca,'FontSize',font); 301 | 302 | %% 303 | xlabel('PV capacity (kW)'); 304 | ylabel('WT capacity (kW)'); 305 | zlabel('BS capacity (kWh)'); 306 | 307 | %% Rotated separate figures 308 | figure(1) 309 | surf(XX,YY,ZZ,'LineStyle','none') 310 | hold on 311 | scatter3(x,y,z,'k.'); 312 | hold off 313 | xlabel('PV capacity (kW)'); 314 | ylabel('WT capacity (kW)'); 315 | zlabel('BS capacity (kWh)'); 316 | figure(2) 317 | surf(XX,YY,ZZ,'LineStyle','none') 318 | hold on 319 | scatter3(x,y,z,'k.'); 320 | hold off 321 | view(-148,8) 322 | xlabel('PV capacity (kW)'); 323 | ylabel('WT capacity (kW)'); 324 | zlabel('BS capacity (kWh)'); 325 | figure(3) 326 | surf(XX,YY,ZZ,'LineStyle','none') 327 | hold on 328 | scatter3(x,y,z,'k.'); 329 | hold off 330 | view(-180,8) 331 | xlabel('PV capacity (kW)'); 332 | ylabel('WT capacity (kW)'); 333 | zlabel('BS capacity (kWh)'); 334 | figure(4) 335 | surf(XX,YY,ZZ,'LineStyle','none') 336 | hold on 337 | scatter3(x,y,z,'k.'); 338 | hold off 339 | view(-300,8) 340 | xlabel('PV capacity (kW)'); 341 | ylabel('WT capacity (kW)'); 342 | zlabel('BS capacity (kWh)'); 343 | 344 | %% 2D Pareto front curves for inputs 345 | n_s = x_p(:,1); 346 | n_w = x_p(:,2); 347 | Eb_init = x_p(:,3); 348 | 349 | figure(1) 350 | scatter(n_s,n_w,10,'b','filled'); 351 | xlabel('PV capacity (kW)'); 352 | ylabel('WT capacity (kW)'); 353 | 354 | figure(2) 355 | scatter(n_s,Eb_init,10,'b','filled'); 356 | xlabel('PV capacity (kW)'); 357 | ylabel('Battery capacity (kWh)'); 358 | 359 | figure(3) 360 | scatter(n_w,Eb_init,10,'b','filled'); 361 | xlabel('WT capacity (kW)'); 362 | ylabel('Battery capacity (kWh)'); 363 | 364 | %% Pareto set for objectives 365 | LCOE = fval(:,1); 366 | Emissions = fval(:,2); 367 | DPSP = fval(:,3); 368 | Dump = fval(:,4); 369 | %REF = ones(size(fval,1),1) - fval(:,5); 370 | 371 | scatter(Dump,Emissions,5,'b','filled') 372 | xlabel('Dump energy ratio'); 373 | ylabel('Normalized emissions'); 374 | 375 | %% fsolve to obtain pareto front of inputs 376 | 377 | Cost = @ (x) Objective_LI_DE_v2_1h(x) - 0.1367; 378 | OPTIONS = optimoptions('fsolve','Algorithm','Levenberg-Marquardt',... 379 | 'StepTolerance',1e-10); 380 | [X] = fsolve(Cost,[10 3 100],OPTIONS); 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | -------------------------------------------------------------------------------- /Sizing_result_gen.m: -------------------------------------------------------------------------------- 1 | %% Plotting out objective function - using Prated 2 | % For various values of inputs - to show local minima 3 | % Assuming 5 equal weights 4 | 5 | Ps_rated_total = 0:1:25; 6 | Pw_rated_total = 0:1:25; 7 | Eb_init = 0:1:200; 8 | w = [0.2 0.2 0.2 0.2 0.2]; % Weights of different cost terms 9 | x = size(Ps_rated_total,2); 10 | y = size(Pw_rated_total,2); 11 | z = size(Eb_init,2); 12 | 13 | Objectives = zeros(x*y*z,5); 14 | Costs = zeros(x*y*z,1); 15 | 16 | tic 17 | 18 | for i = 1:1:x 19 | for j = 1:1:y 20 | for k = 1:1:z 21 | for l = 1:1:x*y*z 22 | input = [Ps_rated_total(i), Pw_rated_total(j), Eb_init(k)]; 23 | Objectives(l,:) = Objective_LI_DE_v6_1h_indPrated(input); 24 | Costs(l) = Objectives(l,:) * w'; 25 | end 26 | end 27 | 28 | end 29 | end 30 | 31 | plotobj_time = toc; 32 | 33 | %% Using n_s, n_w -------------------------------------------------------------------------------- /Solar.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Solar.m -------------------------------------------------------------------------------- /VarySOC_base_1d.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/VarySOC_base_1d.mat -------------------------------------------------------------------------------- /VarySOC_base_3d.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/VarySOC_base_3d.mat -------------------------------------------------------------------------------- /VarySOC_peakyLoad.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/VarySOC_peakyLoad.mat -------------------------------------------------------------------------------- /Wind.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/Wind.m -------------------------------------------------------------------------------- /irradiance.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/irradiance.mat -------------------------------------------------------------------------------- /irradiance_low.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/irradiance_low.mat -------------------------------------------------------------------------------- /load_peaky.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/load_peaky.mat -------------------------------------------------------------------------------- /load_shift_curtail.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/load_shift_curtail.mat -------------------------------------------------------------------------------- /load_shift_v2.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/load_shift_v2.mat -------------------------------------------------------------------------------- /positive.m: -------------------------------------------------------------------------------- 1 | function [c,ceq] = positive(x) 2 | 3 | c = -eye(3) * x'; 4 | ceq = [ ]; 5 | -------------------------------------------------------------------------------- /sizing_pareto.m: -------------------------------------------------------------------------------- 1 | function f = sizing_pareto(x) 2 | 3 | Costs = Objective_LI_DE_v6_1h_indPrated(x); 4 | f(1) = Costs(1); 5 | f(2) = Costs(2); 6 | f(3) = Costs(3); 7 | %f(4) = Costs(4); 8 | %f(5) = Costs(5); 9 | 10 | end -------------------------------------------------------------------------------- /temp.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/temp.mat -------------------------------------------------------------------------------- /test_simulation.m: -------------------------------------------------------------------------------- 1 | %% Iterative optimization with feedback 2 | % Following algorithm of De Paola et al. 3 | % Can also import custom code as a module into Simulink? 4 | 5 | %% (1) Iterative scheme (Flexible demand coordination) 6 | % Initialization phase (1st iteration) 7 | l = 1; % Iteration counter 8 | conv = 0; % Power consumption profiles converged or not? 9 | N = 100; % Number of load agents (individual demands) i.e. price-responsive/flexible appliances 10 | T = 24; % Time interval considered 11 | t = 1:1:T; % Simulation run over 1 day with time discretization step = 1 h (w/ t = 1 being 1st hour starting at 00:00) 12 | P_r = 12e3*ones(1,N); % Assume rated (max) power (in W) = 12 kW for whole population 13 | l_tot = 10000; % Guess for total number of iterations 14 | 15 | % Availability window 16 | 17 | % Energy requirements for loads are Gaussian normal dist w/ mean = 30 kWh & SD = 1.5 kWh 18 | E_r = 1.5e3*randn(1,N) + 30e3; 19 | 20 | % Preallocate array of power profiles for all agents over all times (t) & iteration counts (l) --> Computationally faster 21 | % Or keep concatenating to the multidimensional array? 22 | % But number of iterations needed for convergence not known? 23 | 24 | % Feasible power consumption profiles - Enforce by adding extra constraints to the optimization problem 25 | u = ones(N,T,l_tot); % Power profiles for all agents at all times 26 | % Do as a feasibility problem in CVX - but need to get a set of points and 27 | % not just a single one 28 | 29 | % For 1st iteration l=1 30 | for j = 1:N 31 | u(j,:,1) = 5e3*ones(1,T); % Assume initial power consumption profile to be constant at all times (for all agents) 32 | end 33 | 34 | % Assume hourly profile of inflexible demand equal to historical data (0-24h) 35 | % D_i remains fixed at all iterations 36 | % Used historical demand data from the UK as starting example 37 | D_i = [31445;31899;31945;31016;30557;32145;37534;43849;47450;48672;48749;48634;48429;47812;47360;47501;48785;49621;49773;49531;49179;45668;40585;35240]'; 38 | 39 | % Aggregate demand = sum of flexible and inflexible demands 40 | D = ones(l_tot,T); 41 | D(1,:) = D_i + sum(u(:,1,1)); 42 | 43 | %% Power scheduling update for (1) 44 | while conv == 0 45 | conv = 1; 46 | for j=1:1:N 47 | l = l+1; 48 | D(l,:) = D(l-1,:); 49 | u(j,:,l) = u(j,:,l-1); 50 | 51 | for t1=1:1:T 52 | for t2=1:1:T 53 | if (t1 ~= t2) && (D(l-1,t1) < D(l-1,t2)) && (u(j,t1,l-1) < P_r(j)) && (u(j,t2,l-1) > 0) 54 | % Shift delta of power consumed from times t2 to t1 55 | delta = min([P_r(j) - u(j,t1,l-1), u(j,t2,l-1),(D(l-1,t2)-D(l-1,t1))/2]); 56 | u(j,t1,l) = u(j,t1,l-1) + delta; 57 | D(l,t1) = D(l-1,t1) + delta; 58 | u(j,t2,l) = u(j,t2,l-1) - delta; 59 | D(l,t2) = D(l-1,t2) + delta; 60 | conv = 0; 61 | end 62 | end 63 | end 64 | end 65 | end 66 | 67 | %% One-shot scheme (Flexible demand coordination) 68 | while conv == 0 69 | conv = 1; 70 | for j=1:1:N 71 | l = l+1; 72 | D(l,:) = D(l-1,:); 73 | u(j,:,l) = u(j,:,l-1); 74 | 75 | for t1=1:1:T 76 | for t2=1:1:T 77 | if (t1 ~= t2) && (D(l-1,t1) < D(l-1,t2)) && (u(j,t1,l-1) < P_r(j)) && (u(j,t2,l-1) > 0) 78 | % Shift delta of power consumed from times t2 to t1 79 | delta = min([P_r(j) - u(j,t1,l-1), u(j,t2,l-1),(D(l-1,t2)-D(l-1,t1))/2]); 80 | u(j,t1,l) = u(j,t1,l-1) + delta; 81 | D(l,t1) = D(l-1,t1) + delta; 82 | u(j,t2,l) = u(j,t2,l-1) - delta; 83 | D(l,t2) = D(l-1,t2) + delta; 84 | conv = 0; 85 | end 86 | end 87 | end 88 | end 89 | end 90 | 91 | %% Final results 92 | D_nash = D(l,:); % Final aggregate demand profile (converged) 93 | u_nash = u(:,:,l); 94 | 95 | figure(1) 96 | plot(t,D(1,:)); 97 | hold on 98 | plot(t,D_nash); 99 | legend('Initial aggregate demand', 'Final aggregate demand') 100 | -------------------------------------------------------------------------------- /wind_speed.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/wind_speed.mat -------------------------------------------------------------------------------- /wind_speed_low.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vineetjnair9/microgrid_optimization/6134d4b797899d061ec07e2a0ae0691338a763e6/wind_speed_low.mat --------------------------------------------------------------------------------