Skip to content

Instantly share code, notes, and snippets.

@toofishes
Last active November 20, 2020 00:37
Show Gist options
  • Save toofishes/f50fce0e051f1e0c685544f3cf5a21a2 to your computer and use it in GitHub Desktop.
Save toofishes/f50fce0e051f1e0c685544f3cf5a21a2 to your computer and use it in GitHub Desktop.
OpenEVSE test program to gauge accuracy of calculating energy usage
#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