Skip to content

Commit ad91563

Browse files
authored
chore: increase socSteps to 200 for more granularity (#5)
* chore: increase socSteps to 200 for more granularity * feat: adjust MPC logic to discharge battery for load
1 parent e7d315d commit ad91563

1 file changed

Lines changed: 41 additions & 10 deletions

File tree

‎mpc/mpc.go‎

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (mpc *MPCController) Optimize(forecast []TimeSlot) []ControlDecision {
7373
// Use dynamic programming for optimization
7474
// State: SOC level, Time: hour
7575
// We'll discretize SOC into steps for tractability
76-
socSteps := 20
76+
socSteps := 200
7777
socStep := (mpc.Config.BatteryMaxSOC - mpc.Config.BatteryMinSOC) / float64(socSteps)
7878

7979
// DP table: [time][soc_index] -> (best_profit, best_decision)
@@ -171,9 +171,9 @@ func (mpc *MPCController) generateFeasibleDecisions(currentSOC float64, slot Tim
171171
{0, 0}, // Idle
172172
}
173173

174-
// Add charge options
175-
for i := 1; i <= 5; i++ {
176-
charge := float64(i) * mpc.Config.BatteryMaxCharge / 5.0
174+
// Add charge options (more granular for better arbitrage opportunities)
175+
for i := 1; i <= 10; i++ {
176+
charge := float64(i) * mpc.Config.BatteryMaxCharge / 10.0
177177
if mpc.canCharge(currentSOC, charge) {
178178
batteryActions = append(batteryActions, struct {
179179
charge float64
@@ -182,9 +182,9 @@ func (mpc *MPCController) generateFeasibleDecisions(currentSOC float64, slot Tim
182182
}
183183
}
184184

185-
// Add discharge options
186-
for i := 1; i <= 5; i++ {
187-
discharge := float64(i) * mpc.Config.BatteryMaxDischarge / 5.0
185+
// Add discharge options (more granular for better arbitrage opportunities)
186+
for i := 1; i <= 10; i++ {
187+
discharge := float64(i) * mpc.Config.BatteryMaxDischarge / 10.0
188188
if mpc.canDischarge(currentSOC, discharge) {
189189
batteryActions = append(batteryActions, struct {
190190
charge float64
@@ -229,15 +229,46 @@ func (mpc *MPCController) generateFeasibleDecisions(currentSOC float64, slot Tim
229229
}
230230

231231
// calculateProfit computes the profit for a decision
232+
// This accounts for:
233+
// 1. Charging battery when prices are low (cost reflected in GridImport)
234+
// 2. Discharging battery to support load when prices are high (savings reflected in reduced GridImport)
235+
// 3. Exporting excess power when export prices are favorable
232236
func (mpc *MPCController) calculateProfit(dec ControlDecision, slot TimeSlot) float64 {
237+
// Revenue from exporting to grid
233238
revenue := dec.GridExport * slot.ExportPrice
234-
cost := dec.GridImport * slot.ImportPrice
235239

236-
// Battery degradation cost
240+
// Cost of importing from grid (includes charging battery from grid when prices are low)
241+
importCost := dec.GridImport * slot.ImportPrice
242+
243+
// Calculate the value of battery operations for arbitrage
244+
// When we discharge battery to support load, we avoid importing at current price
245+
// When we charge battery from grid, we pay current price but can use it later at higher prices
246+
247+
// Actual energy delivered from battery (accounting for efficiency)
248+
batteryDischargeEnergy := dec.BatteryDischarge // kWh delivered
249+
250+
// The discharge value: we avoid importing power at the current price
251+
// This is beneficial when import price is high
252+
dischargeValue := batteryDischargeEnergy * mpc.Config.BatteryEfficiency * slot.ImportPrice
253+
254+
// The charge cost: we store energy for future use
255+
// This is beneficial when import price is low (to use when prices are high)
256+
// The cost is already included in importCost, but we account for storage losses
257+
chargeLoss := dec.BatteryCharge * (1 - mpc.Config.BatteryEfficiency) * slot.ImportPrice
258+
259+
// Battery degradation cost (wear and tear from cycling)
237260
batteryThroughput := dec.BatteryCharge + dec.BatteryDischarge
238261
degradationCost := batteryThroughput * mpc.Config.BatteryDegradationCost
239262

240-
return revenue - cost - degradationCost
263+
// Net profit calculation:
264+
// + Revenue from exports
265+
// - Cost of imports (includes grid charging of battery)
266+
// + Value from discharging battery (avoids expensive imports)
267+
// - Cost of charging losses
268+
// - Battery degradation
269+
profit := revenue - importCost + dischargeValue - chargeLoss - degradationCost
270+
271+
return profit
241272
}
242273

243274
// Helper functions

0 commit comments

Comments
 (0)