Fix virtual capacity calculation and add tests (#360)
This commit is contained in:
parent
9d45d5a869
commit
46411cc602
2 changed files with 56 additions and 36 deletions
|
|
@ -8,6 +8,8 @@ import (
|
|||
"github.com/andig/evcc/util"
|
||||
)
|
||||
|
||||
const chargeEfficiency = 0.9 // assume charge 90% efficiency
|
||||
|
||||
// SocEstimator provides vehicle soc and charge duration
|
||||
// Vehicle SoC can be estimated to provide more granularity
|
||||
type SocEstimator struct {
|
||||
|
|
@ -40,8 +42,8 @@ func NewSocEstimator(log *util.Logger, vehicle api.Vehicle, estimate bool) *SocE
|
|||
func (s *SocEstimator) Reset() {
|
||||
s.prevSoC = 0
|
||||
s.prevChargedEnergy = 0
|
||||
s.capacity = float64(s.vehicle.Capacity()) * 1e3 // cache to simplify debugging
|
||||
s.virtualCapacity = s.capacity / 0.9 // assume charge 90% efficiency
|
||||
s.capacity = float64(s.vehicle.Capacity()) * 1e3 // cache to simplify debugging
|
||||
s.virtualCapacity = s.capacity / chargeEfficiency // initial capacity taking efficiency into account
|
||||
s.energyPerSocStep = s.virtualCapacity / 100
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +98,7 @@ func (s *SocEstimator) SoC(chargedEnergy float64) (float64, error) {
|
|||
// calculate gradient, wh per soc %
|
||||
if socDelta > 1 && energyDelta > 0 && s.prevSoC > 0 {
|
||||
s.energyPerSocStep = energyDelta / socDelta
|
||||
s.virtualCapacity = s.energyPerSocStep * 100 / 1e3
|
||||
s.virtualCapacity = s.energyPerSocStep * 100
|
||||
s.log.TRACE.Printf("soc gradient updated: energyPerSocStep: %0.0fWh, virtualCapacity: %0.1fkWh", s.energyPerSocStep, s.virtualCapacity)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
func TestRemainingChargeDuration(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
vehicle := mock.NewMockVehicle(ctrl)
|
||||
//9 kWh userBatCap => 10 kWh virtualBatCap
|
||||
//9 kWh userBatCap => 10 kWh virtualBatCap
|
||||
vehicle.EXPECT().Capacity().Return(int64(9))
|
||||
|
||||
ce := NewSocEstimator(util.NewLogger("foo"), vehicle, false)
|
||||
|
|
@ -29,42 +29,45 @@ func TestRemainingChargeDuration(t *testing.T) {
|
|||
func TestSoCEstimation(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
vehicle := mock.NewMockVehicle(ctrl)
|
||||
//9 kWh userBatCap => 10 kWh virtualBatCap
|
||||
vehicle.EXPECT().Capacity().Return(int64(9))
|
||||
|
||||
// 9 kWh user battery capacity is converted to initial value of 10 kWh virtual capacity
|
||||
var capacity int64 = 9
|
||||
vehicle.EXPECT().Capacity().Return(capacity)
|
||||
|
||||
ce := NewSocEstimator(util.NewLogger("foo"), vehicle, true)
|
||||
ce.socCharge = 20.0
|
||||
|
||||
tc := []struct {
|
||||
chargedEnergy float64
|
||||
vehicleSoC float64
|
||||
estimatedSoC float64
|
||||
chargedEnergy float64
|
||||
vehicleSoC float64
|
||||
estimatedSoC float64
|
||||
virtualCapacity float64
|
||||
}{
|
||||
{10, 20.0, 20.0},
|
||||
{0, 20.0, 20.0},
|
||||
{123, 20.0, 21.23},
|
||||
{1000, 20.0, 30.0},
|
||||
{1100, 31.0, 31.0},
|
||||
{1200, 32.0, 32.0},
|
||||
{1900, 39.0, 39.0},
|
||||
{2000, 40.0, 40.0},
|
||||
{4000, 50.0, 50.0},
|
||||
{6000, 60.0, 60.0},
|
||||
{6500, 65.0, 65.0},
|
||||
{7000, 65.0, 70.0},
|
||||
{7100, 71.0, 71.0},
|
||||
{7300, 72.0, 72.0},
|
||||
{7400, 73.0, 73.0},
|
||||
{7700, 75.0, 75.0},
|
||||
{8200, 80.0, 80.0},
|
||||
{0, 25.0, 25.0},
|
||||
{2500, 25.0, 50.0},
|
||||
{0, 50.0, 50.0}, // -10000
|
||||
{4990, 50.0, 99.9},
|
||||
{5000, 50.0, 100.0},
|
||||
{5001, 50.0, 100.0},
|
||||
{0, 0.0, 0.0},
|
||||
{1000, 0.0, 10.0},
|
||||
{10, 20.0, 20.0, 10000},
|
||||
{0, 20.0, 20.0, 10000},
|
||||
{123, 20.0, 21.23, 10000},
|
||||
{1000, 20.0, 30.0, 10000},
|
||||
{1100, 31.0, 31.0, 10000},
|
||||
{1200, 32.0, 32.0, 10000},
|
||||
{1900, 39.0, 39.0, 10000},
|
||||
{2000, 40.0, 40.0, 10000},
|
||||
{4000, 50.0, 50.0, 20000}, // 2kWh add 10% -> 20kWh battery
|
||||
{6000, 60.0, 60.0, 20000}, // 2kWh add 10% -> 20kWh battery
|
||||
{6500, 65.0, 65.0, 10000},
|
||||
{7000, 65.0, 70.0, 10000},
|
||||
{7100, 71.0, 71.0, 10000},
|
||||
{7300, 72.0, 72.0, 10000},
|
||||
{7400, 73.0, 73.0, 10000},
|
||||
{7700, 75.0, 75.0, 15000}, // 0.3kWh add 2% -> 15kWh battery
|
||||
{8200, 80.0, 80.0, 10000},
|
||||
{0, 25.0, 25.0, 10000},
|
||||
{2500, 25.0, 50.0, 10000},
|
||||
{0, 50.0, 50.0, 10000}, // -10000
|
||||
{4990, 50.0, 99.9, 10000},
|
||||
{5000, 50.0, 100.0, 10000},
|
||||
{5001, 50.0, 100.0, 10000},
|
||||
{0, 0.0, 0.0, 10000},
|
||||
{1000, 0.0, 10.0, 10000},
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
|
|
@ -75,10 +78,25 @@ func TestSoCEstimation(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Logf("%+v", ce)
|
||||
|
||||
// validate soc estimate
|
||||
if tc.estimatedSoC != soc {
|
||||
t.Errorf("expected: %g, got: %g", tc.estimatedSoC, soc)
|
||||
t.Errorf("expected estimated soc: %g, got: %g", tc.estimatedSoC, soc)
|
||||
}
|
||||
|
||||
// validate capacity estimate
|
||||
if tc.virtualCapacity != ce.virtualCapacity {
|
||||
t.Errorf("expected virtual capacity: %v, got: %v", tc.virtualCapacity, ce.virtualCapacity)
|
||||
}
|
||||
|
||||
// validate duration estimate
|
||||
chargePower := 1e3
|
||||
targetSoC := 100
|
||||
remainingHours := (float64(targetSoC) - soc) / 100 * tc.virtualCapacity / chargePower
|
||||
remainingDuration := time.Duration(float64(time.Hour) * remainingHours).Round(time.Second)
|
||||
|
||||
if rm := ce.RemainingChargeDuration(chargePower, targetSoC); rm != remainingDuration {
|
||||
t.Errorf("expected estimated duration: %v, got: %v", remainingDuration, rm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue