Add moving average for battery values in OBPSensorTask
This commit is contained in:
parent
05f08e1699
commit
7958810e7d
|
@ -12,7 +12,8 @@
|
||||||
#include "N2kMessages.h"
|
#include "N2kMessages.h"
|
||||||
#include "NMEA0183.h"
|
#include "NMEA0183.h"
|
||||||
#include "ObpNmea0183.h"
|
#include "ObpNmea0183.h"
|
||||||
#include "OBP60ExtensionPort.h"
|
#include "OBP60ExtensionPort.h"
|
||||||
|
#include "movingAvg.h" // Lib for moving average building
|
||||||
|
|
||||||
// Timer Interrupts for hardware functions
|
// Timer Interrupts for hardware functions
|
||||||
void underVoltageDetection();
|
void underVoltageDetection();
|
||||||
|
@ -79,6 +80,15 @@ void sensorTask(void *param){
|
||||||
bool AS5600_ready = false; // AS5600 initialized and ready to use
|
bool AS5600_ready = false; // AS5600 initialized and ready to use
|
||||||
bool INA226_1_ready = false; // INA226_1 initialized and ready to use
|
bool INA226_1_ready = false; // INA226_1 initialized and ready to use
|
||||||
|
|
||||||
|
// Create integer arrays for average building
|
||||||
|
int avgsize = 300;
|
||||||
|
constexpr int arrayBatV{300};
|
||||||
|
constexpr int arrayBatC{300};
|
||||||
|
movingAvg batV(arrayBatV);
|
||||||
|
movingAvg batC(arrayBatC);
|
||||||
|
batV.begin();
|
||||||
|
batC.begin();
|
||||||
|
|
||||||
// Start timer interrupts
|
// Start timer interrupts
|
||||||
bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean();
|
bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean();
|
||||||
if(uvoltage == true){
|
if(uvoltage == true){
|
||||||
|
@ -210,7 +220,7 @@ void sensorTask(void *param){
|
||||||
String shunt1 = api->getConfig()->getConfigItem(api->getConfig()->shunt1, true)->asString();
|
String shunt1 = api->getConfig()->getConfigItem(api->getConfig()->shunt1, true)->asString();
|
||||||
|
|
||||||
float shuntResistor = 1.0; // Default value for shunt resistor
|
float shuntResistor = 1.0; // Default value for shunt resistor
|
||||||
float current = 10.0; // Default value for max. current
|
float maxCurrent = 10.0; // Default value for max. current
|
||||||
float corrFactor = 1; // Correction factor for fix calibration
|
float corrFactor = 1; // Correction factor for fix calibration
|
||||||
|
|
||||||
if(String(powsensor1) == "INA226"){
|
if(String(powsensor1) == "INA226"){
|
||||||
|
@ -220,14 +230,19 @@ void sensorTask(void *param){
|
||||||
else{
|
else{
|
||||||
api->getLogger()->logDebug(GwLog::LOG,"Modul 1 INA226 found");
|
api->getLogger()->logDebug(GwLog::LOG,"Modul 1 INA226 found");
|
||||||
shuntResistor = SHUNT_VOLTAGE / float(shunt1.toInt()); // Calculate shunt resisitor for max. shunt voltage 75mV
|
shuntResistor = SHUNT_VOLTAGE / float(shunt1.toInt()); // Calculate shunt resisitor for max. shunt voltage 75mV
|
||||||
current = float(shunt1.toInt());
|
maxCurrent = float(shunt1.toInt());
|
||||||
api->getLogger()->logDebug(GwLog::LOG,"Calibation INA226, Imax:%3.0fA Rs:%7.5fOhm Us:%5.3f", current, shuntResistor, SHUNT_VOLTAGE);
|
api->getLogger()->logDebug(GwLog::LOG,"Calibation INA226, Imax:%3.0fA Rs:%7.5fOhm Us:%5.3f", maxCurrent, shuntResistor, SHUNT_VOLTAGE);
|
||||||
// ina226_1.setMaxCurrentShunt(current, shuntResistor);
|
// ina226_1.setMaxCurrentShunt(maxCurrent, shuntResistor);
|
||||||
ina226_1.setMaxCurrentShunt(10, 0.01); // Calibration with fix values (because the original values outer range)
|
ina226_1.setMaxCurrentShunt(10, 0.01); // Calibration with fix values (because the original values outer range)
|
||||||
corrFactor = (current / 10) * (0.001 / shuntResistor) / (current / 100); // correction factor for fix calibration
|
corrFactor = (maxCurrent / 10) * (0.001 / shuntResistor) / (maxCurrent / 100); // Correction factor for fix calibration
|
||||||
sensors.batteryVoltage = ina226_1.getBusVoltage();
|
sensors.batteryVoltage = ina226_1.getBusVoltage();
|
||||||
sensors.batteryCurrent = ina226_1.getCurrent() * corrFactor;
|
sensors.batteryCurrent = ina226_1.getCurrent() * corrFactor;
|
||||||
sensors.batteryPower = ina226_1.getPower() * corrFactor;
|
sensors.batteryPower = ina226_1.getPower() * corrFactor;
|
||||||
|
// Fill average arrays with start values
|
||||||
|
for (int i=1; i<=avgsize+1; ++i) {
|
||||||
|
batV.reading(int(sensors.batteryVoltage * 100));
|
||||||
|
batC.reading(int(sensors.batteryCurrent * 10));
|
||||||
|
}
|
||||||
INA226_1_ready = true;
|
INA226_1_ready = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,12 +409,30 @@ void sensorTask(void *param){
|
||||||
if(String(powsensor1) == "INA226" && INA226_1_ready == true){
|
if(String(powsensor1) == "INA226" && INA226_1_ready == true){
|
||||||
sensors.batteryVoltage = ina226_1.getBusVoltage();
|
sensors.batteryVoltage = ina226_1.getBusVoltage();
|
||||||
sensors.batteryCurrent = ina226_1.getCurrent() * corrFactor;
|
sensors.batteryCurrent = ina226_1.getCurrent() * corrFactor;
|
||||||
sensors.batteryPower = ina226_1.getPower() * corrFactor;
|
// Eliminates bit jitter by zero current values
|
||||||
|
float factor = maxCurrent / 100;
|
||||||
|
if(sensors.batteryCurrent >= (-0.015 * factor) && sensors.batteryCurrent <= (0.015 * factor)){
|
||||||
|
sensors.batteryCurrent = 0;
|
||||||
|
}
|
||||||
|
// Save actual values in average arrays as integer values
|
||||||
|
batV.reading(int(sensors.batteryVoltage * 100));
|
||||||
|
batC.reading(int(sensors.batteryCurrent * 10));
|
||||||
|
// Calculate the average values for different time lines from integer values
|
||||||
|
sensors.batteryVoltage10 = batV.getAvg(10) / 100.0;
|
||||||
|
sensors.batteryVoltage60 = batV.getAvg(60) / 100.0;
|
||||||
|
sensors.batteryVoltage300 = batV.getAvg(300) / 100.0;
|
||||||
|
sensors.batteryCurrent10 = batC.getAvg(10) / 10.0;
|
||||||
|
sensors.batteryCurrent60 = batC.getAvg(60) / 10.0;
|
||||||
|
sensors.batteryCurrent300 = batC.getAvg(300) / 10.0;
|
||||||
|
sensors.batteryPower10 = sensors.batteryVoltage10 * sensors.batteryCurrent10;
|
||||||
|
sensors.batteryPower60 = sensors.batteryVoltage60 * sensors.batteryCurrent60;
|
||||||
|
sensors.batteryPower300 = sensors.batteryVoltage300 * sensors.batteryCurrent300;
|
||||||
|
// sensors.batteryPower = ina226_1.getPower() * corrFactor; // Real value
|
||||||
|
sensors.batteryPower = sensors.batteryVoltage * sensors.batteryCurrent; // Calculated power value (more stable)
|
||||||
}
|
}
|
||||||
// Send battery data to NMEA200 bus
|
// Send battery live data to NMEA200 bus
|
||||||
if(!isnan(sensors.batteryVoltage) && !isnan(sensors.batteryCurrent)){
|
if(!isnan(sensors.batteryVoltage) && !isnan(sensors.batteryCurrent)){
|
||||||
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, sensors.batteryCurrent, N2kDoubleNA, 1);
|
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, sensors.batteryCurrent, N2kDoubleNA, 1);
|
||||||
// SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, sensors.batteryCurrent, sensors.batteryPower, 1);
|
|
||||||
api->sendN2kMessage(N2kMsg);
|
api->sendN2kMessage(N2kMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
class PageBattery : public Page
|
class PageBattery : public Page
|
||||||
{
|
{
|
||||||
bool keylock = false; // Keylock
|
bool keylock = false; // Keylock
|
||||||
|
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PageBattery(CommonData &comon){
|
PageBattery(CommonData &comon){
|
||||||
|
@ -13,7 +14,15 @@ class PageBattery : public Page
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int handleKey(int key){
|
virtual int handleKey(int key){
|
||||||
if(key == 11){ // Code for keylock
|
// Change average
|
||||||
|
if(key == 1){
|
||||||
|
average ++;
|
||||||
|
average = average % 4; // Modulo 4
|
||||||
|
return 0; // Commit the key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code for keylock
|
||||||
|
if(key == 11){
|
||||||
keylock = !keylock; // Toggle keylock
|
keylock = !keylock; // Toggle keylock
|
||||||
return 0; // Commit the key
|
return 0; // Commit the key
|
||||||
}
|
}
|
||||||
|
@ -23,7 +32,7 @@ class PageBattery : public Page
|
||||||
virtual void displayPage(CommonData &commonData, PageData &pageData){
|
virtual void displayPage(CommonData &commonData, PageData &pageData){
|
||||||
GwConfigHandler *config = commonData.config;
|
GwConfigHandler *config = commonData.config;
|
||||||
GwLog *logger=commonData.logger;
|
GwLog *logger=commonData.logger;
|
||||||
|
|
||||||
// Old values for hold function
|
// Old values for hold function
|
||||||
double value1 = 0;
|
double value1 = 0;
|
||||||
static String svalue1old = "";
|
static String svalue1old = "";
|
||||||
|
@ -47,13 +56,27 @@ class PageBattery : public Page
|
||||||
// Get voltage value
|
// Get voltage value
|
||||||
String name1 = "BatVolt"; // Value name
|
String name1 = "BatVolt"; // Value name
|
||||||
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
|
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
|
||||||
value1 = commonData.data.batteryVoltage; // Value as double in SI unit
|
// Switch average values
|
||||||
|
switch (average) {
|
||||||
|
case 0:
|
||||||
|
value1 = commonData.data.batteryVoltage; // Real data
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value1 = commonData.data.batteryVoltage10; // Average 10s
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value1 = commonData.data.batteryVoltage60; // Average 60s
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
value1 = commonData.data.batteryVoltage300; // Average 300s
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value1 = commonData.data.batteryVoltage; // Default
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(simulation == false){
|
if(simulation == true){
|
||||||
value1 = 0; // No sensor data
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
value1 = 12 + float(random(0, 5)) / 10; // Simulation data
|
value1 = 12 + float(random(0, 5)) / 10; // Simulation data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,13 +86,26 @@ class PageBattery : public Page
|
||||||
// Get current value
|
// Get current value
|
||||||
String name2 = "BatCurr"; // Value name
|
String name2 = "BatCurr"; // Value name
|
||||||
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
|
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
|
||||||
value2 = commonData.data.batteryCurrent; // Value as double in SI unit
|
switch (average) {
|
||||||
|
case 0:
|
||||||
|
value2 = commonData.data.batteryCurrent; // Real data
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value2 = commonData.data.batteryCurrent10; // Average 10s
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value2 = commonData.data.batteryCurrent60; // Average 60s
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
value2 = commonData.data.batteryCurrent300; // Average 300s
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value2 = commonData.data.batteryCurrent; // Default
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(simulation == false){
|
if(simulation == true){
|
||||||
value2 = 0; // No sensor data
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
value2 = 8 + float(random(0, 10)) / 10; // Simulation data
|
value2 = 8 + float(random(0, 10)) / 10; // Simulation data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,13 +115,26 @@ class PageBattery : public Page
|
||||||
// Get power value
|
// Get power value
|
||||||
String name3 = "BatPow"; // Value name
|
String name3 = "BatPow"; // Value name
|
||||||
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
|
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
|
||||||
value3 = commonData.data.batteryPower; // Value as double in SI unit
|
switch (average) {
|
||||||
|
case 0:
|
||||||
|
value3 = commonData.data.batteryPower; // Real data
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value3 = commonData.data.batteryPower10; // Average 10s
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value3 = commonData.data.batteryPower60; // Average 60s
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
value3 = commonData.data.batteryPower300; // Average 300s
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value3 = commonData.data.batteryPower; // Default
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(simulation == false){
|
if(simulation == true){
|
||||||
value3 = 0; // No sensor data
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
value3 = value1 * value2; // Simulation data
|
value3 = value1 * value2; // Simulation data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +148,7 @@ class PageBattery : public Page
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging boat values
|
// Logging boat values
|
||||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery, %s: %f, %s: %f, %s: %f", name1, value1, name2, value2, name3, value3);
|
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery, %s: %f, %s: %f, %s: %f, Avg: %d", name1, value1, name2, value2, name3, value3, average);
|
||||||
|
|
||||||
// Draw page
|
// Draw page
|
||||||
//***********************************************************
|
//***********************************************************
|
||||||
|
@ -120,6 +169,52 @@ class PageBattery : public Page
|
||||||
}
|
}
|
||||||
// Clear display by call in obp60task.cpp in main loop
|
// Clear display by call in obp60task.cpp in main loop
|
||||||
|
|
||||||
|
// Show average settings
|
||||||
|
display.setTextColor(textcolor);
|
||||||
|
display.setFont(&Ubuntu_Bold8pt7b);
|
||||||
|
switch (average) {
|
||||||
|
case 0:
|
||||||
|
display.setCursor(60, 90);
|
||||||
|
display.print("Avg: 1s");
|
||||||
|
display.setCursor(60, 180);
|
||||||
|
display.print("Avg: 1s");
|
||||||
|
display.setCursor(60, 270);
|
||||||
|
display.print("Avg: 1s");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
display.setCursor(60, 90);
|
||||||
|
display.print("Avg: 10s");
|
||||||
|
display.setCursor(60, 180);
|
||||||
|
display.print("Avg: 10s");
|
||||||
|
display.setCursor(60, 270);
|
||||||
|
display.print("Avg: 10s");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
display.setCursor(60, 90);
|
||||||
|
display.print("Avg: 60s");
|
||||||
|
display.setCursor(60, 180);
|
||||||
|
display.print("Avg: 60s");
|
||||||
|
display.setCursor(60, 270);
|
||||||
|
display.print("Avg: 60s");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
display.setCursor(60, 90);
|
||||||
|
display.print("Avg: 300s");
|
||||||
|
display.setCursor(60, 180);
|
||||||
|
display.print("Avg: 300s");
|
||||||
|
display.setCursor(60, 270);
|
||||||
|
display.print("Avg: 300s");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
display.setCursor(60, 90);
|
||||||
|
display.print("Avg: 1s");
|
||||||
|
display.setCursor(60, 180);
|
||||||
|
display.print("Avg: 1s");
|
||||||
|
display.setCursor(60, 270);
|
||||||
|
display.print("Avg: 1s");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// ############### Value 1 ################
|
// ############### Value 1 ################
|
||||||
|
|
||||||
// Show name
|
// Show name
|
||||||
|
@ -134,13 +229,17 @@ class PageBattery : public Page
|
||||||
display.setCursor(20, 90);
|
display.setCursor(20, 90);
|
||||||
display.print(unit1); // Unit
|
display.print(unit1); // Unit
|
||||||
|
|
||||||
|
|
||||||
// Show value
|
// Show value
|
||||||
display.setFont(&DSEG7Classic_BoldItalic30pt7b);
|
display.setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||||
display.setCursor(180, 90);
|
display.setCursor(180, 90);
|
||||||
|
|
||||||
// Show bus data
|
// Show bus data
|
||||||
display.print(value1,2); // Real value as formated string
|
if(String(powsensor1) != "off"){
|
||||||
|
display.print(value1,2); // Real value as formated string
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
display.print("---"); // No sensor data (sensor is off)
|
||||||
|
}
|
||||||
|
|
||||||
// ############### Horizontal Line ################
|
// ############### Horizontal Line ################
|
||||||
|
|
||||||
|
@ -166,7 +265,12 @@ class PageBattery : public Page
|
||||||
display.setCursor(180, 180);
|
display.setCursor(180, 180);
|
||||||
|
|
||||||
// Show bus data
|
// Show bus data
|
||||||
display.print(value2,1); // Real value as formated string
|
if(String(powsensor1) != "off"){
|
||||||
|
display.print(value2,1); // Real value as formated string
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
display.print("---"); // No sensor data (sensor is off)
|
||||||
|
}
|
||||||
|
|
||||||
// ############### Horizontal Line ################
|
// ############### Horizontal Line ################
|
||||||
|
|
||||||
|
@ -192,7 +296,12 @@ class PageBattery : public Page
|
||||||
display.setCursor(180, 270);
|
display.setCursor(180, 270);
|
||||||
|
|
||||||
// Show bus data
|
// Show bus data
|
||||||
display.print(value3,1); // Real value as formated string
|
if(String(powsensor1) != "off"){
|
||||||
|
display.print(value3,1); // Real value as formated string
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
display.print("---"); // No sensor data (sensor is off)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ############### Key Layout ################
|
// ############### Key Layout ################
|
||||||
|
@ -200,8 +309,10 @@ class PageBattery : public Page
|
||||||
// Key Layout
|
// Key Layout
|
||||||
display.setTextColor(textcolor);
|
display.setTextColor(textcolor);
|
||||||
display.setFont(&Ubuntu_Bold8pt7b);
|
display.setFont(&Ubuntu_Bold8pt7b);
|
||||||
display.setCursor(130, 290);
|
|
||||||
if(keylock == false){
|
if(keylock == false){
|
||||||
|
display.setCursor(10, 290);
|
||||||
|
display.print("[AVG]");
|
||||||
|
display.setCursor(130, 290);
|
||||||
display.print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
|
display.print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
|
||||||
if(String(backlightMode) == "Control by Key"){ // Key for illumination
|
if(String(backlightMode) == "Control by Key"){ // Key for illumination
|
||||||
display.setCursor(343, 290);
|
display.setCursor(343, 290);
|
||||||
|
@ -209,6 +320,7 @@ class PageBattery : public Page
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
display.setCursor(130, 290);
|
||||||
display.print(" [ Keylock active ]");
|
display.print(" [ Keylock active ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,15 @@ typedef struct{
|
||||||
double batteryVoltage = 0;
|
double batteryVoltage = 0;
|
||||||
double batteryCurrent = 0;
|
double batteryCurrent = 0;
|
||||||
double batteryPower = 0;
|
double batteryPower = 0;
|
||||||
|
double batteryVoltage10 = 0;
|
||||||
|
double batteryCurrent10 = 0;
|
||||||
|
double batteryPower10 = 0;
|
||||||
|
double batteryVoltage60 = 0;
|
||||||
|
double batteryCurrent60 = 0;
|
||||||
|
double batteryPower60 = 0;
|
||||||
|
double batteryVoltage300 = 0;
|
||||||
|
double batteryCurrent300 = 0;
|
||||||
|
double batteryPower300 = 0;
|
||||||
double solarVoltage = 0;
|
double solarVoltage = 0;
|
||||||
double solarCurrent = 0;
|
double solarCurrent = 0;
|
||||||
double solarPower = 0;
|
double solarPower = 0;
|
||||||
|
|
|
@ -351,7 +351,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "shunt3",
|
"name": "shunt3",
|
||||||
"label": "Gen. Sensor",
|
"label": "Gen. Shunt",
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"default": "10",
|
"default": "10",
|
||||||
"description": "Shunt current value [10A|50A|100A|200A|300A|400A|500A]",
|
"description": "Shunt current value [10A|50A|100A|200A|300A|400A|500A]",
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Arduino Moving Average Library
|
||||||
|
// https://github.com/JChristensen/movingAvg
|
||||||
|
// Copyright (C) 2018 by Jack Christensen and licensed under
|
||||||
|
// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
|
#include <movingAvg.h>
|
||||||
|
|
||||||
|
// initialize - allocate the interval array
|
||||||
|
void movingAvg::begin()
|
||||||
|
{
|
||||||
|
m_readings = new int[m_interval];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a new reading and return the new moving average
|
||||||
|
int movingAvg::reading(int newReading)
|
||||||
|
{
|
||||||
|
// add each new data point to the sum until the m_readings array is filled
|
||||||
|
if (m_nbrReadings < m_interval) {
|
||||||
|
++m_nbrReadings;
|
||||||
|
m_sum += newReading;
|
||||||
|
}
|
||||||
|
// once the array is filled, subtract the oldest data point and add the new one
|
||||||
|
else {
|
||||||
|
m_sum = m_sum - m_readings[m_next] + newReading;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_readings[m_next] = newReading;
|
||||||
|
if (++m_next >= m_interval) m_next = 0;
|
||||||
|
return (m_sum + m_nbrReadings / 2) / m_nbrReadings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just return the current moving average
|
||||||
|
int movingAvg::getAvg()
|
||||||
|
{
|
||||||
|
return (m_sum + m_nbrReadings / 2) / m_nbrReadings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the average for a subset of the data, the most recent nPoints readings.
|
||||||
|
// for invalid values of nPoints, return zero.
|
||||||
|
int movingAvg::getAvg(int nPoints)
|
||||||
|
{
|
||||||
|
if (nPoints < 1 || nPoints > m_interval || nPoints > m_nbrReadings) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
long sum{0};
|
||||||
|
int i = m_next;
|
||||||
|
for (int n=0; n<nPoints; ++n) {
|
||||||
|
if (i == 0) {
|
||||||
|
i = m_interval - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
sum += m_readings[i];
|
||||||
|
}
|
||||||
|
return (sum + nPoints / 2) / nPoints;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the moving average over again
|
||||||
|
void movingAvg::reset()
|
||||||
|
{
|
||||||
|
m_nbrReadings = 0;
|
||||||
|
m_sum = 0;
|
||||||
|
m_next = 0;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Arduino Moving Average Library
|
||||||
|
// https://github.com/JChristensen/movingAvg
|
||||||
|
// Copyright (C) 2018 by Jack Christensen and licensed under
|
||||||
|
// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
|
#ifndef MOVINGAVG_H_INCLUDED
|
||||||
|
#define MOVINGAVG_H_INCLUDED
|
||||||
|
|
||||||
|
class movingAvg
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
movingAvg(int interval)
|
||||||
|
: m_interval{interval}, m_nbrReadings{0}, m_sum{0}, m_next{0} {}
|
||||||
|
void begin();
|
||||||
|
int reading(int newReading);
|
||||||
|
int getAvg();
|
||||||
|
int getAvg(int nPoints);
|
||||||
|
int getCount() {return m_nbrReadings;}
|
||||||
|
void reset();
|
||||||
|
int* getReadings() {return m_readings;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_interval; // number of data points for the moving average
|
||||||
|
int m_nbrReadings; // number of readings
|
||||||
|
long m_sum; // sum of the m_readings array
|
||||||
|
int m_next; // index to the next reading
|
||||||
|
int* m_readings; // pointer to the dynamically allocated interval array
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -20,7 +20,7 @@ DECLARE_INITFUNCTION(OBP60Init);
|
||||||
|
|
||||||
// OBP60 Task
|
// OBP60 Task
|
||||||
void OBP60Task(GwApi *param);
|
void OBP60Task(GwApi *param);
|
||||||
DECLARE_USERTASK_PARAM(OBP60Task, 20000) // Need 20k RAM as stack size
|
DECLARE_USERTASK_PARAM(OBP60Task, 10000) // Need 25k RAM as stack size
|
||||||
DECLARE_CAPABILITY(obp60,true);
|
DECLARE_CAPABILITY(obp60,true);
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue