@@ -80,7 +80,7 @@ def fit_boc(model):
8080 datasheet.
8181 """
8282 params = {
83- "soc " : 50 ,
83+ "soc_percent " : 50 ,
8484 }
8585 model .update (params )
8686 return model
@@ -117,27 +117,36 @@ def boc(model, dispatch):
117117 - SOC. [%]
118118 - TODO: other? (i.e.: Energy/capacity)
119119 """
120- min_soc = 10
121- max_soc = 90
120+ min_soc = model . get ( "min_soc_percent" , 10 )
121+ max_soc = model . get ( "max_soc_percent" , 90 )
122122 factor = offset_to_hours (dispatch .index .freq )
123123
124124 states = []
125- current_energy = model ["energy_wh" ] * model ["soc" ] / 100
126- max_energy = model ["energy_wh" ] * max_soc / 100
127- min_energy = model ["energy_wh" ] * min_soc / 100
125+ current_energy = model ["dc_energy_wh" ] * model ["soc_percent" ] / 100
126+ max_energy = model ["dc_energy_wh" ] * max_soc / 100
127+ min_energy = model ["dc_energy_wh" ] * min_soc / 100
128+
129+ dispatch = power .copy ()
130+ discharge_efficiency = model .get ("discharge_efficiency" , 1.0 )
131+ charge_efficiency = model .get ("charge_efficiency" , 1.0 )
132+ dispatch .loc [power < 0 ] *= discharge_efficiency
133+ dispatch .loc [power > 0 ] /= charge_efficiency
134+
128135 for power in dispatch :
129136 if power > 0 :
130- power = min (power , model ["max_power_w " ])
137+ power = min (power , model ["dc_max_power_w " ])
131138 energy = power * factor
132139 available = current_energy - min_energy
133140 energy = min (energy , available )
141+ power = energy / factor * discharge_efficiency
134142 else :
135- power = max (power , - model ["max_power_w " ])
143+ power = max (power , - model ["dc_max_power_w " ])
136144 energy = power * factor
137145 available = current_energy - max_energy
138146 energy = max (energy , available )
147+ power = energy / factor / charge_efficiency
139148 current_energy -= energy
140- soc = current_energy / model ["energy_wh " ] * 100
149+ soc = current_energy / model ["dc_energy_wh " ] * 100
141150 power = energy / factor
142151 states .append ((power , soc ))
143152
@@ -169,20 +178,27 @@ def fit_sam(datasheet):
169178 calculates the model parameters that match the provided information from a
170179 datasheet.
171180 """
172- # TODO: validate/normalize datasheet struct
173181 chemistry = {
174182 "LFP" : "LFPGraphite" ,
175183 }
176184 model = sam_default (chemistry [datasheet ["chemistry" ]])
177185 sam_sizing (
178186 model = model ,
179- desired_power = datasheet ["max_power_w " ] / 1000 ,
180- desired_capacity = datasheet ["energy_wh " ] / 1000 ,
181- desired_voltage = datasheet ["voltage " ],
187+ desired_power = datasheet ["dc_max_power_w " ] / 1000 ,
188+ desired_capacity = datasheet ["dc_energy_wh " ] / 1000 ,
189+ desired_voltage = datasheet ["dc_nominal_voltage " ],
182190 )
183191 model .ParamsCell .initial_SOC = 50
192+ model .ParamsCell .minimum_SOC = datasheet .get ("min_soc_percent" , 10 )
193+ model .ParamsCell .maximum_SOC = datasheet .get ("max_soc_percent" , 90 )
184194 export = model .export ()
185195 del export ["Controls" ]
196+ # TODO: can we use SAM's `calculate_battery_size` to assign these values
197+ # with `batt_dc_ac_efficiency` and `inverter_eff` respectively?
198+ export .update ({
199+ "charge_efficiency" : datasheet .get ("charge_efficiency" , 0.96 ),
200+ "discharge_efficiency" : datasheet .get ("discharge_efficiency" , 0.96 ),
201+ })
186202 return export
187203
188204
@@ -220,8 +236,11 @@ def sam(model, power):
220236 battery = sam_new ()
221237 battery .ParamsCell .assign (model .get ("ParamsCell" , {}))
222238 battery .ParamsPack .assign (model .get ("ParamsPack" , {}))
223- battery .ParamsCell .minimum_SOC = 10
224- battery .ParamsCell .maximum_SOC = 90
239+ # TODO: min/max SOC should be configurable for each simulation (i.e.: we
240+ # could simulate more conservative cycles than what the battery allows
241+ # (but we probably should not allow more aggressive cycles
242+ #battery.ParamsCell.minimum_SOC = 10
243+ #battery.ParamsCell.maximum_SOC = 90
225244 battery .Controls .replace (
226245 {
227246 "control_mode" : 1 ,
@@ -233,13 +252,19 @@ def sam(model, power):
233252 battery .StateCell .assign (model .get ("StateCell" , {}))
234253 battery .StatePack .assign (model .get ("StatePack" , {}))
235254
255+ battery_dispatch = power .copy ()
256+ battery_dispatch .loc [power < 0 ] *= model ["discharge_efficiency" ]
257+ battery_dispatch .loc [power > 0 ] /= model ["charge_efficiency" ]
258+
236259 states = []
237260 for p in power :
238261 battery .Controls .input_power = p / 1000
239262 battery .execute (0 )
240263 states .append ((battery .StatePack .P * 1000 , battery .StatePack .SOC ))
241264
242265 results = DataFrame (states , index = power .index , columns = ["Power" , "SOC" ])
266+ results .loc [results ["Power" ] < 0 , "Power" ] /= model ["charge_efficiency" ]
267+ results .loc [results ["Power" ] > 0 , "Power" ] *= model ["discharge_efficiency" ]
243268 export = battery .export ()
244269 del export ["Controls" ]
245270
0 commit comments