@@ -80,7 +80,7 @@ def fit_boc(model):
80
80
datasheet.
81
81
"""
82
82
params = {
83
- "soc " : 50 ,
83
+ "soc_percent " : 50 ,
84
84
}
85
85
model .update (params )
86
86
return model
@@ -117,27 +117,36 @@ def boc(model, dispatch):
117
117
- SOC. [%]
118
118
- TODO: other? (i.e.: Energy/capacity)
119
119
"""
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 )
122
122
factor = offset_to_hours (dispatch .index .freq )
123
123
124
124
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
+
128
135
for power in dispatch :
129
136
if power > 0 :
130
- power = min (power , model ["max_power_w " ])
137
+ power = min (power , model ["dc_max_power_w " ])
131
138
energy = power * factor
132
139
available = current_energy - min_energy
133
140
energy = min (energy , available )
141
+ power = energy / factor * discharge_efficiency
134
142
else :
135
- power = max (power , - model ["max_power_w " ])
143
+ power = max (power , - model ["dc_max_power_w " ])
136
144
energy = power * factor
137
145
available = current_energy - max_energy
138
146
energy = max (energy , available )
147
+ power = energy / factor / charge_efficiency
139
148
current_energy -= energy
140
- soc = current_energy / model ["energy_wh " ] * 100
149
+ soc = current_energy / model ["dc_energy_wh " ] * 100
141
150
power = energy / factor
142
151
states .append ((power , soc ))
143
152
@@ -169,20 +178,27 @@ def fit_sam(datasheet):
169
178
calculates the model parameters that match the provided information from a
170
179
datasheet.
171
180
"""
172
- # TODO: validate/normalize datasheet struct
173
181
chemistry = {
174
182
"LFP" : "LFPGraphite" ,
175
183
}
176
184
model = sam_default (chemistry [datasheet ["chemistry" ]])
177
185
sam_sizing (
178
186
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 " ],
182
190
)
183
191
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 )
184
194
export = model .export ()
185
195
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
+ })
186
202
return export
187
203
188
204
@@ -220,8 +236,11 @@ def sam(model, power):
220
236
battery = sam_new ()
221
237
battery .ParamsCell .assign (model .get ("ParamsCell" , {}))
222
238
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
225
244
battery .Controls .replace (
226
245
{
227
246
"control_mode" : 1 ,
@@ -233,13 +252,19 @@ def sam(model, power):
233
252
battery .StateCell .assign (model .get ("StateCell" , {}))
234
253
battery .StatePack .assign (model .get ("StatePack" , {}))
235
254
255
+ battery_dispatch = power .copy ()
256
+ battery_dispatch .loc [power < 0 ] *= model ["discharge_efficiency" ]
257
+ battery_dispatch .loc [power > 0 ] /= model ["charge_efficiency" ]
258
+
236
259
states = []
237
260
for p in power :
238
261
battery .Controls .input_power = p / 1000
239
262
battery .execute (0 )
240
263
states .append ((battery .StatePack .P * 1000 , battery .StatePack .SOC ))
241
264
242
265
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" ]
243
268
export = battery .export ()
244
269
del export ["Controls" ]
245
270
0 commit comments