update Code

This commit is contained in:
Siwat Sirichai 2019-08-09 09:17:05 +07:00
parent 3c47103b39
commit a641fad56c
119 changed files with 10997 additions and 5 deletions

View file

@ -0,0 +1,120 @@
/*
* Flow Meter
*/
#include "Arduino.h"
#include "FlowMeter.h" // https://github.com/sekdiy/FlowMeter
#include <math.h>
FlowMeter::FlowMeter(unsigned int pin, FlowSensorProperties prop) :
_pin(pin), //!< store pin number
_properties(prop) //!< store sensor properties
{
pinMode(pin, INPUT_PULLUP); //!< initialize interrupt pin as input with pullup
}
double FlowMeter::getCurrentFlowrate() {
return this->_currentFlowrate; //!< in l/min
}
double FlowMeter::getCurrentVolume() {
return this->_currentVolume; //!< in l
}
double FlowMeter::getTotalFlowrate() {
return this->_totalVolume / (this->_totalDuration / 1000.0f) * 60.0f; //!< in l/min
}
double FlowMeter::getTotalVolume() {
return this->_totalVolume; //!< in l
}
void FlowMeter::tick(unsigned long duration) {
/* sampling and normalisation */
double seconds = duration / 1000.0f; //!< normalised duration (in s, i.e. per 1000ms)
cli(); //!< going to change interrupt variable(s)
double frequency = this->_currentPulses / seconds; //!< normalised frequency (in 1/s)
this->_currentPulses = 0; //!< reset pulse counter after successfull sampling
sei(); //!< done changing interrupt variable(s)
/* determine current correction factor (from sensor properties) */
unsigned int decile = floor(10.0f * frequency / (this->_properties.capacity * this->_properties.kFactor)); //!< decile of current flow relative to sensor capacity
unsigned int ceiling = 9; //!< highest possible decile index
this->_currentCorrection = this->_properties.kFactor / this->_properties.mFactor[min(decile, ceiling)]; //!< combine constant k-factor and m-factor for decile
/* update current calculations: */
this->_currentFlowrate = frequency / this->_currentCorrection; //!< get flow rate (in l/min) from normalised frequency and combined correction factor
this->_currentVolume = this->_currentFlowrate / (60.0f/seconds); //!< get volume (in l) from normalised flow rate and normalised time
/* update statistics: */
this->_currentDuration = duration; //!< store current tick duration (convenience, in ms)
this->_currentFrequency = frequency; //!< store current pulses per second (convenience, in 1/s)
this->_totalDuration += duration; //!< accumulate total duration (in ms)
this->_totalVolume += this->_currentVolume; //!< accumulate total volume (in l)
this->_totalCorrection += this->_currentCorrection * duration; //!< accumulate corrections over time
}
void FlowMeter::count() {
this->_currentPulses++; //!< this should be called from an interrupt service routine
}
void FlowMeter::reset() {
cli(); //!< going to change interrupt variable(s)
this->_currentPulses = 0; //!< reset pulse counter
sei(); //!< done changing interrupt variable(s)
this->_currentFrequency = 0.0f;
this->_currentDuration = 0.0f;
this->_currentFlowrate = 0.0f;
this->_currentVolume = 0.0f;
this->_currentCorrection = 0.0f;
}
unsigned int FlowMeter::getPin() {
return this->_pin;
}
unsigned long FlowMeter::getCurrentDuration() {
return this->_currentDuration; //!< in ms
}
double FlowMeter::getCurrentFrequency() {
return this->_currentFrequency; //!< in 1/s
}
double FlowMeter::getCurrentError() {
/// error (in %) = error * 100
/// error = correction rate - 1
/// correction rate = k-factor / correction
return (this->_properties.kFactor / this->_currentCorrection - 1) * 100; //!< in %
}
unsigned long FlowMeter::getTotalDuration() {
return this->_totalDuration; //!< in ms
}
double FlowMeter::getTotalError() {
/// average error (in %) = average error * 100
/// average error = average correction rate - 1
/// average correction rate = k-factor / corrections over time * total time
return (this->_properties.kFactor / this->_totalCorrection * this->_totalDuration - 1) * 100;
}
FlowMeter* FlowMeter::setTotalDuration(unsigned long totalDuration) {
this->_totalDuration = totalDuration;
return this;
}
FlowMeter* FlowMeter::setTotalVolume(double totalVolume) {
this->_totalVolume = totalVolume;
return this;
}
FlowMeter* FlowMeter::setTotalCorrection(double totalCorrection) {
this->_totalCorrection = totalCorrection;
return this;
}
FlowSensorProperties UncalibratedSensor = {60.0f, 5.0f, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
FlowSensorProperties FS300A = {60.0f, 5.5f, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
FlowSensorProperties FS400A = {60.0f, 4.8f, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};

View file

@ -0,0 +1,171 @@
/**
* Flow Meter
*
* An Arduino flow meter library that provides calibrated liquid flow and volume measurement with flow sensors.
*
* @author sekdiy (https://github.com/sekdiy/FlowMeter)
* @date 14.07.2015 Initial release.
* @version See git comments for changes.
*/
#ifndef FLOWMETER_H
#define FLOWMETER_H
#include "Arduino.h"
/**
* FlowSensorProperties
*
* Structure that holds essential information about a flow sensor.
* Stores general sensor properties and calibration points.
*
* See file G34_Flow_rate_to_frequency.jpg for reference.
*/
typedef struct {
double capacity; //!< capacity, upper limit of flow rate (in l/min)
double kFactor; //!< "k-factor" (in (pulses/s) / (l/min)), e.g.: 1 pulse/s = kFactor * l/min
double mFactor[10]; //!< multiplicative correction factor near unity, "meter factor" (per decile of flow)
} FlowSensorProperties;
extern FlowSensorProperties UncalibratedSensor; //!< default sensor
extern FlowSensorProperties FS300A; //!< see documentation about FS300A/SEN02141B
extern FlowSensorProperties FS400A; //!< see documentation about FS400A/USN-HS10TA
/**
* FlowMeter
*/
class FlowMeter {
public:
/**
* Initializes a new flow meter object.
*
* @param pin The pin that the flow sensor is connected to (has to be interrupt capable, default: INT0).
* @param prop The properties of the actual flow sensor being used (default: UncalibratedSensor).
*/
FlowMeter(unsigned int pin = 2, FlowSensorProperties prop = UncalibratedSensor);
double getCurrentFlowrate(); //!< Returns the current flow rate since last reset (in l/min).
double getCurrentVolume(); //!< Returns the current volume since last reset (in l).
double getTotalFlowrate(); //!< Returns the (linear) average flow rate in this flow meter instance (in l/min).
double getTotalVolume(); //!< Returns the total volume flown trough this flow meter instance (in l).
/**
* The tick method updates all internal calculations at the end of a measurement period.
*
* We're calculating flow and volume data over time.
* The actual pulses have to be sampled using the count method (i.e. via an interrupt service routine).
*
* Flow sensor formulae:
*
* Let K: pulses per second per unit of measure (i.e. (1/s)/(l/min)),
* f: pulse frequency (1/s),
* Q: flow rate (l/min),
* p: sensor pulses (no dimension/unit),
* t: time since last measurements (s).
*
* K = f / Q | units: (1/s) / (l/min) = (1/s) / (l/min)
* <=> | Substitute p / t for f in order to allow for different measurement intervals
* K = (p / t) / Q | units: ((1/s)/(l/min)) = (1/s) / (l/min)
* <=> | Solve for Q:
* Q = (p / t) / K | untis: l/min = 1/s / (1/s / (l/min))
* <=> | Volume in l:
* V = Q / 60 | units: l = (l/min) / (min)
*
* The property K is sometimes stated in pulses per liter or pulses per gallon.
* In these cases the unit of measure has to be converted accordingly (e.g. from gal/s to l/min).
* See file G34_Flow_rate_to_frequency.jpg for reference.
*
* @param duration The tick duration (in ms).
*/
void tick(unsigned long duration = 1000);
void count(); //!< Increments the internal pulse counter. Serves as an interrupt callback routine.
void reset(); //!< Prepares the flow meter for a fresh measurement. Resets all current values, but not the totals.
/*
* setters enabling continued metering across power cycles
*/
FlowMeter* setTotalDuration(unsigned long totalDuration); //!< Sets the total (overall) duration (i.e. after power up).
FlowMeter* setTotalVolume(double totalVolume); //!< Sets the total (overall) volume (i.e. after power up).
FlowMeter* setTotalCorrection(double totalCorrection); //!< Sets the total (overall) correction factor (i.e. after power up).
/*
* convenience methods and calibration helpers
*/
unsigned int getPin(); //!< Returns the Arduino pin number that the flow sensor is connected to.
unsigned long getCurrentDuration(); //!< Returns the duration of the current tick (in ms).
double getCurrentFrequency(); //!< Returns the pulse rate in the current tick (in 1/s).
double getCurrentError(); //!< Returns the error resulting from the current measurement (in %).
unsigned long getTotalDuration(); //!< Returns the total run time of this flow meter instance (in ms).
double getTotalError(); //!< Returns the (linear) average error of this flow meter instance (in %).
protected:
unsigned int _pin; //!< connection pin (has to be interrupt capable!)
FlowSensorProperties _properties; //!< sensor properties (including calibration data)
unsigned long _currentDuration; //!< current tick duration (convenience, in ms)
double _currentFrequency; //!< current pulses per second (convenience, in 1/s)
double _currentFlowrate = 0.0f; //!< current flow rate (in l/tick), e.g.: 1 l / min = 1 pulse / s / (pulses / s / l / min)
double _currentVolume = 0.0f; //!< current volume (in l), e.g.: 1 l = 1 (l / min) / (60 * s)
double _currentCorrection; //!< currently applied correction factor
unsigned long _totalDuration = 0.0f; //!< total measured duration since begin of measurement (in ms)
double _totalVolume = 0.0f; //!< total volume since begin of measurement (in l)
double _totalCorrection = 0.0f; //!< accumulated correction factors
volatile unsigned long _currentPulses = 0; //!< pulses within current sample period
};
/**
* FlowSensorCalibration
*
* Convenience class for manipulating sensor properties.
*/
class FlowSensorCalibration {
public:
FlowSensorCalibration() {};
FlowSensorCalibration(FlowSensorProperties properties): _properties(properties) {};
FlowSensorCalibration* setProperties(FlowSensorProperties properties) {
this->_properties = properties;
return this;
};
FlowSensorCalibration* setCapacity(double capacity) {
this->_properties.capacity = capacity;
return this;
}
FlowSensorCalibration* setKFactor(double kFactor) {
this->_properties.kFactor = kFactor;
return this;
}
FlowSensorCalibration* setMeterFactorPerDecile(unsigned int decile, unsigned int mFactor) {
this->_properties.mFactor[decile] = mFactor;
return this;
}
FlowSensorProperties getProperties() {
return this->_properties;
}
double getCapacity() {
return this->_properties.capacity;
}
double getKFactor() {
return this->_properties.kFactor;
}
unsigned int getMeterFactorPerDecile(unsigned int decile) {
return this->_properties.mFactor[decile];
}
protected:
FlowSensorProperties _properties;
};
#endif // FLOWMETER_H