Last active
November 20, 2020 00:37
-
-
Save toofishes/f50fce0e051f1e0c685544f3cf5a21a2 to your computer and use it in GitHub Desktop.
OpenEVSE test program to gauge accuracy of calculating energy usage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdint> | |
#include <cstdio> | |
#include <iostream> | |
#include <iomanip> | |
#define KWH_CALC_INTERVAL_MS (250UL) | |
unsigned long fakeMs = 234235; | |
unsigned long millis() | |
{ | |
return fakeMs; | |
} | |
class J1772EVSEController { | |
int32_t m_ChargingCurrent; | |
uint32_t m_Voltage; // mV | |
public: | |
void SetMA(int32_t ma) { m_ChargingCurrent = ma; } | |
int32_t GetChargingCurrent() { return m_ChargingCurrent; } | |
void SetMV(uint32_t mv) { m_Voltage = mv; } | |
int32_t GetVoltage() { return m_Voltage; } | |
}; | |
J1772EVSEController g_EvseController; | |
class EnergyMeter { | |
unsigned long m_lastUpdateMs; | |
uint32_t m_wattHoursTot; // accumulated across all charging sessions | |
uint32_t m_wattSeconds; // current charging session | |
public: | |
void calcUsage(); | |
void calcUsageNew(); | |
void calcUsageDouble(); | |
void SetLastUpdateMs(unsigned long ms) { m_lastUpdateMs = ms; }; | |
uint32_t GetWattSeconds() { return m_wattSeconds; }; | |
}; | |
void EnergyMeter::calcUsage() | |
{ | |
unsigned long curms = millis(); | |
unsigned long dms = curms - m_lastUpdateMs; | |
if (dms > KWH_CALC_INTERVAL_MS) { | |
uint32_t ma = g_EvseController.GetChargingCurrent(); | |
uint32_t mv = g_EvseController.GetVoltage(); | |
#ifdef THREEPHASE | |
m_wattSeconds += ((mv/1000UL) * (ma/1000UL) * dms * 3) / 1000UL; | |
#else // !THREEPHASE | |
m_wattSeconds += ((mv/1000UL) * (ma/1000UL) * dms) / 1000UL; | |
#endif // THREEPHASE | |
m_lastUpdateMs = curms; | |
} | |
} | |
void EnergyMeter::calcUsageNew() | |
{ | |
unsigned long curms = millis(); | |
unsigned long dms = curms - m_lastUpdateMs; | |
if (dms > KWH_CALC_INTERVAL_MS) { | |
uint32_t ma = g_EvseController.GetChargingCurrent(); | |
uint32_t mv = g_EvseController.GetVoltage(); | |
uint32_t wms = ((mv/16) * (ma/4) / 15625) * dms; | |
#ifdef THREEPHASE | |
wms *= 3; | |
#endif // THREEPHASE | |
m_wattSeconds += wms / 1000; | |
m_lastUpdateMs = curms; | |
} | |
} | |
void EnergyMeter::calcUsageDouble() | |
{ | |
unsigned long curms = millis(); | |
unsigned long dms = curms - m_lastUpdateMs; | |
if (dms > KWH_CALC_INTERVAL_MS) { | |
uint32_t ma = g_EvseController.GetChargingCurrent(); | |
uint32_t mv = g_EvseController.GetVoltage(); | |
double ws = ((mv/1000.0) * (ma/1000.0) * dms) / 1000.0; | |
#ifdef THREEPHASE | |
ws *= 3.0; | |
#endif // THREEPHASE | |
m_wattSeconds += ws; | |
m_lastUpdateMs = curms; | |
} | |
} | |
static void test(int32_t mv, int32_t ma, unsigned long elapsed) { | |
printf("%.3f Volts, %.3f Amps, %ld ms elapsed\n", mv / 1000.0, ma / 1000.0, elapsed); | |
g_EvseController.SetMV(mv); | |
g_EvseController.SetMA(ma); | |
EnergyMeter emDouble = EnergyMeter(); | |
emDouble.SetLastUpdateMs(fakeMs - elapsed); | |
emDouble.calcUsageDouble(); | |
std::cout << "Using FP: " << emDouble.GetWattSeconds() << " Ws\n"; | |
EnergyMeter emOld = EnergyMeter(); | |
emOld.SetLastUpdateMs(fakeMs - elapsed); | |
emOld.calcUsage(); | |
std::cout << "Original: " << emOld.GetWattSeconds() << " Ws\t"; | |
std::cout << "Error: " << 100.0 - (emOld.GetWattSeconds() * 1.0 / emDouble.GetWattSeconds() * 100.0) << "%\t" | |
<< emDouble.GetWattSeconds() - emOld.GetWattSeconds() << " Ws\n"; | |
EnergyMeter emNew = EnergyMeter(); | |
emNew.SetLastUpdateMs(fakeMs - elapsed); | |
emNew.calcUsageNew(); | |
std::cout << "New: " << emNew.GetWattSeconds() << " Ws\t"; | |
std::cout << "Error: " << 100.0 - (emNew.GetWattSeconds() * 1.0 / emDouble.GetWattSeconds() * 100.0) << "%\t" | |
<< emDouble.GetWattSeconds() - emNew.GetWattSeconds() << " Ws\n"; | |
std::cout << '\n'; | |
} | |
int main(void) { | |
int32_t mv, ma; | |
unsigned long elapsed = 999; // fake that 999 ms have elapsed | |
std::cout << std::fixed << std::setprecision(3); | |
std::cout << "Slowest standard charge rate possible, realistic worst case scenario for old code\n"; | |
mv = 114999; // 114.999 volts | |
ma = 5999; // 5.999 amps | |
test(mv, ma, elapsed); | |
std::cout << "A fairly typical US Level 1 setup on a 15 amp circuit\n"; | |
mv = 119900; // 119.9 volts | |
ma = 11900; // 11.9 amps | |
test(mv, ma, elapsed); | |
std::cout << "A typical EU setup on a 32 amp circuit\n"; | |
mv = 229900; // 229.9 volts | |
ma = 31900; // 31.9 amps | |
test(mv, ma, elapsed); | |
std::cout << "Higher powered US Level 2 dedicated 40 amp circuit\n"; | |
mv = 239900; // 239.9 volts | |
ma = 39900; // 39.9 amps | |
test(mv, ma, elapsed); | |
std::cout << "The highest values this code should ever see\n"; | |
mv = 249900; // 249.9 volts | |
ma = 79900; // 79.9 amps | |
test(mv, ma, elapsed); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment