Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: "Open circuit voltage" and "Battery internal resistance" #1466

Draft
wants to merge 2 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions include/BatteryGuard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once
#include <Arduino.h>
#include <frozen/string.h>
#include <TaskSchedulerDeclarations.h>
#include "Statistic.h"


class BatteryGuardClass {
public:
BatteryGuardClass() = default;
~BatteryGuardClass() = default;

void init(Scheduler& scheduler);
void updateSettings(void);
void updateBatteryValues(float const nowVoltage, float const nowCurrent, uint32_t const millisStamp);
std::optional<float> getOpenCircuitVoltage(void);
std::optional<float> getInternalResistance(void) const;

private:
enum class Text : uint8_t {
Q_NODATA = 0,
Q_EXCELLENT = 1,
Q_GOOD = 2,
Q_BAD = 3,
T_HEAD = 4
};

void loop(void);
bool calculateOpenCircuitVoltage(float const nowVoltage, float const nowCurrent);
bool calculateInternalResistance(float const nowVoltage, float const nowCurrent);
void printOpenCircuitVoltageInformationBlock(void);
frozen::string const& getText(Text tNr);

// Returns true if battery data is not older as 30 seconds
bool isDataValid() { return (millis() - _battMillis) < 30*1000; }

// the following values ​​are used to calculate the "Open circuit voltage"
float _battVoltage = 0.0f; // actual battery voltage [V]
float _battCurrent = 0.0f; // actual battery current [A]
uint32_t _battMillis = 0; // measurement time stamp [millis()]
WeightedAVG<uint32_t> _battPeriod {20}; // measurement period [ms]
WeightedAVG<float> _battVoltageAVG {5}; // average battery voltage [V]
WeightedAVG<float> _openCircuitVoltageAVG {5}; // average battery open circuit voltage [V]
float _resistanceFromConfig = 0.0f; // configured battery resistance [Ohm]
size_t _notAvailableCounter = 0; // voltage or current were not available counter

// the following values ​​are used to calculate the "Battery internal resistance"
WeightedAVG<float> _resistanceFromCalcAVG {10}; // calculated battery resistance [Ohm]
bool _firstOfTwoAvailable = false; // true after to got the first of two values
bool _minMaxAvailable = false; // true if minimum and maximum values are available
std::pair<float,float> _pFirstVolt = {0.0f,0.0f}; // first of two voltages and related current [V,A]
std::pair<float,float> _pMaxVolt = {0.0f,0.0f}; // maximum voltage and related current [V,A]
std::pair<float,float> _pMinVolt = {0.0f,0.0f}; // minimum voltage and related current [V,A]
uint32_t _lastMinMaxMillis = 0; // last millis from the first min/max values [millis()]
float const _minDiffVoltage = 0.05f; // minimum required difference [V]
// unclear if this value will also fit to other battery provider

Task _loopTask; // Task
bool _verboseLogging = false; // Logging On/Off
bool _useBatteryGuard = false; // "Battery guard" On/Off
};

extern BatteryGuardClass BatteryGuard;
3 changes: 3 additions & 0 deletions include/BatteryStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ class VictronSmartShuntStats : public BatteryStats {
bool _alarmLowSOC;
bool _alarmLowTemperature;
bool _alarmHighTemperature;

std::optional<float> _oBatteryResistor = std::nullopt;
std::optional<float> _oOpenCircuitVoltage = std::nullopt;
};

class MqttBatteryStats : public BatteryStats {
Expand Down
56 changes: 56 additions & 0 deletions include/Statistic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

/*
* Weighted average and statistics class (initialising value defines the weighted average 10 = 10%)
*/
template <typename T>
class WeightedAVG {
public:
explicit WeightedAVG(size_t factor)
: _countMax(factor)
, _count(0), _countNum(0), _avgV(0), _minV(0), _maxV(0), _lastV(0) {}

// Add a value to the statistics
void addNumber(const T& num) {
if (_count == 0){
_count++;
_avgV = num;
_minV = num;
_maxV = num;
_countNum = 1;
} else {
if (_count < _countMax)
_count++;
_avgV = (_avgV * (_count - 1) + num) / _count;
if (num < _minV) { _minV = num; }
if (num > _maxV) { _maxV = num; }
if (_countNum < 10000) { _countNum++; }
}
_lastV = num;
}

// Reset the statistic data
void reset(void) { _count = 0; _avgV = 0; _minV = 0; _maxV = 0; _lastV = 0; _countNum = 0; }
// Reset the statistic data and initialize with first value
void reset(const T& num) { _count = 0; addNumber(num); }
// Returns the weighted average
T getAverage() const { return _avgV; }
// Returns the minimum value
T getMin() const { return _minV; }
// Returns the maximum value
T getMax() const { return _maxV; }
// Returns the last added value
T getLast() const { return _lastV; }
// Returns the amount of added values. Limited to 10000
size_t getCounts() const { return _countNum; }

private:
size_t _countMax; // weighting factor (10 => 1/10 => 10%)
size_t _count; // counter (0 - _countMax)
size_t _countNum; // counts the amount of added values (0 - 10000)
T _avgV; // average value
T _minV; // minimum value
T _maxV; // maximum value
T _lastV; // last value
};

Loading