Skip to content

Commit

Permalink
sns: experiment with delayed analog readings
Browse files Browse the repository at this point in the history
ref. #2625
incorrect average calculation in the loop, sum and divide for the result
spend time in tick() instead of waiting in either pre() or value()
  • Loading branch information
mcspr committed Nov 7, 2024
1 parent 0976bdb commit a1ffa9f
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 60 deletions.
86 changes: 55 additions & 31 deletions code/espurna/sensors/AnalogSensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ class AnalogSensor : public BaseAnalogSensor {
public:
static constexpr int RawBits { 10 };

static constexpr double RawMax { (1 << RawBits) - 1 };
static constexpr double RawMin { 0.0 };
static constexpr double RawMax { (1 << RawBits) - 1 };

static constexpr size_t SamplesMin { 1 };
static constexpr size_t SamplesMax { 16 };

using Delay = espurna::duration::critical::Microseconds;
using Microseconds = espurna::duration::critical::Microseconds;

static constexpr auto DelayMin = Delay{ 200 };
static constexpr auto DelayMax = Delay::max();
static constexpr auto DelayMin = Microseconds{ 200 };
static constexpr auto DelayMax = Microseconds::max();

unsigned char id() const override {
return SENSOR_ANALOG_ID;
Expand All @@ -39,12 +39,12 @@ class AnalogSensor : public BaseAnalogSensor {
return 1;
}

void setDelay(Delay delay) {
void setDelay(Microseconds delay) {
_delay = std::clamp(delay, DelayMin, DelayMax);
}

void setDelay(uint16_t delay) {
setDelay(Delay{delay});
setDelay(Microseconds{delay});
}

void setSamples(size_t samples) {
Expand All @@ -59,13 +59,17 @@ class AnalogSensor : public BaseAnalogSensor {
_offset = offset;
}

void setPin(uint8_t pin) {
_pin = pin;
}

// ---------------------------------------------------------------------

size_t getSamples() const {
return _samples;
}

espurna::duration::Microseconds getDelay() const {
Microseconds getDelay() const {
return _delay;
}

Expand All @@ -84,6 +88,7 @@ class AnalogSensor : public BaseAnalogSensor {
// Initialization method, must be idempotent
void begin() override {
_ready = true;
_last = TimeSource::now() + _delay;
}

// Descriptive name of the sensor
Expand All @@ -108,37 +113,46 @@ class AnalogSensor : public BaseAnalogSensor {
// Current value for slot # index
double value(unsigned char index) override {
if (index == 0) {
return this->analogRead();
return _sampledValue();
}

return 0;
}

double analogRead() const {
return _withFactor(_rawRead());
void tick() override {
_readNext(_pin);
}

protected:
static unsigned int _rawRead(uint8_t pin, size_t samples, Delay delay) {
// TODO: system_adc_read_fast()? current implementation is using system_adc_read()
// (which is even more sampling on top of ours)
unsigned int last { 0 };
unsigned int result { 0 };
for (size_t sample = 0; sample < samples; ++sample) {
const auto value = ::analogRead(pin);
result = result + value - last;
last = value;
if (sample > 0) {
espurna::time::critical::delay(delay);
yield();
}
}
double _sampledValue() const {
return _value;
}

return result;
void _sampledValue(double value) {
_value = value;
}

unsigned int _rawRead() const {
return _rawRead(0, _samples, _delay);
void _readNext(uint8_t pin) {
if (_sample >= _samples) {
return;
}

const auto now = TimeSource::now();
if (now - _last < _delay) {
return;
}

++_sample;
_last = now;
_sum += ::analogRead(pin);

if (_sample >= _samples) {
const double sum = _sum;
const double samples = _samples;
_sampledValue(sum / samples);
_sum = 0;
_sample = 0;
}
}

double _withFactor(double value) const {
Expand All @@ -153,22 +167,32 @@ class AnalogSensor : public BaseAnalogSensor {
return _withFactor(RawMax);
}

Delay _delay { DelayMin };
using TimeSource = espurna::time::CpuClock;
TimeSource::time_point _last{};
Microseconds _delay { DelayMin };

size_t _samples { SamplesMin };
size_t _sample { 0 };

uint32_t _sum { 0 };

double _value { 0.0 };

double _factor { 1.0 };
double _offset { 0.0 };

uint8_t _pin { A0 };
};

#ifndef __cpp_inline_variables
constexpr int AnalogSensor::RawBits;

constexpr double AnalogSensor::RawMax;
constexpr double AnalogSensor::RawMin;
constexpr double AnalogSensor::RawMax;

constexpr size_t AnalogSensor::SamplesMin;
constexpr size_t AnalogSensor::SamplesMax;

constexpr AnalogSensor::Delay AnalogSensor::DelayMin;
constexpr AnalogSensor::Delay AnalogSensor::DelayMax;
constexpr AnalogSensor::Microseconds AnalogSensor::DelayMin;
constexpr AnalogSensor::Microseconds AnalogSensor::DelayMax;
#endif
38 changes: 19 additions & 19 deletions code/espurna/sensors/LDRSensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,30 +135,28 @@ class LDRSensor : public AnalogSensor {
return MAGNITUDE_NONE;
}

// Current value for slot # index
double value(unsigned char index) {
// Pre-read hook (usually to populate registers with up-to-date data)
void pre() override {
const auto read = _sampledValue();
float ratio = ((float)1024/(float)read) - 1;

unsigned long photocell_resistor = 0;
if (_photocell_on_ground) {
photocell_resistor = _resistor / ratio;
} else {
photocell_resistor = _resistor * ratio;
}

double current_lux = 0;
_lux = _mult_value / (float)pow(photocell_resistor, _pow_value);
}

// Current value for slot # index
double value(unsigned char index) override {
if (index == 0) {

unsigned long photocell_resistor = 0;

// sampled reading
double read = AnalogSensor::analogRead();

float ratio = ((float)1024/(float)read) - 1;
if (_photocell_on_ground) {
photocell_resistor = _resistor / ratio;
} else {
photocell_resistor = _resistor * ratio;
}

current_lux = _mult_value / (float)pow(photocell_resistor, _pow_value);
return _lux;
}

return current_lux;

return 0;
}

protected:
Expand All @@ -169,6 +167,8 @@ class LDRSensor : public AnalogSensor {
float _mult_value = 0;
float _pow_value = 0;

double _lux = 0;

};

#endif // SENSOR_SUPPORT && LDR_SUPPORT
2 changes: 1 addition & 1 deletion code/espurna/sensors/MICS2710Sensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class MICS2710Sensor : public AnalogSensor {
double _getResistance() const {

// get voltage (1 == reference) from analog pin
double voltage = AnalogSensor::analogRead() / 1024.0;
double voltage = _value / 1024.0;

// schematic: 3v3 - Rs - P - Rl - GND
// V(P) = 3v3 * Rl / (Rs + Rl)
Expand Down
2 changes: 1 addition & 1 deletion code/espurna/sensors/MICS5525Sensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class MICS5525Sensor : public AnalogSensor {
double _getResistance() const {

// get voltage (1 == reference) from analog pin
double voltage = AnalogSensor::analogRead() / 1024.0;
double voltage = _value / 1024.0;

// schematic: 3v3 - Rs - P - Rl - GND
// V(P) = 3v3 * Rl / (Rs + Rl)
Expand Down
16 changes: 8 additions & 8 deletions code/espurna/sensors/NTCSensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,13 @@ class NTCSensor : public AnalogSensor {
return espurna::sensor::Unit::None;
}

// Pre-read hook (usually to populate registers with up-to-date data)
void pre() override {
// Previous version happened to use AnalogSensor readings with factor and offset applied
// In case it was useful, this should also support the scaling in calculations for T
// Actual ADC voltage is 0.0...1.0, convert back from 12bit scale
// Actual ADC voltage is 0.0...1.0, convert back from pre-scaled reading
// Depending on where NTC is connected, get current resistance
const double voltage = static_cast<double>(_rawRead()) / AnalogSensor::RawMax;
const double voltage = _sampledValue() / AnalogSensor::RawMax;

_error = SENSOR_ERROR_OK;
if (_input_voltage < voltage) {
Expand All @@ -112,30 +113,29 @@ class NTCSensor : public AnalogSensor {
(resistance_down && (voltage > 0.0))
? ((_resistance_down * (_input_voltage - voltage)) / voltage)
: (resistance_down)
? std::numeric_limits<decltype(_rawRead())>::max()
? std::numeric_limits<decltype(::analogRead(A0))>::max()
: ((_resistance_up * voltage) / (_input_voltage - voltage));

// 1/T = 1/T0 + 1/B * ln(R/R0)
_value = 1.0 / ((1.0 / _T0) + (fs_log(resistance / _R0) / _beta));
_temperature = 1.0 / ((1.0 / _T0) + (fs_log(resistance / _R0) / _beta));
}

// Current value for slot # index
double value(unsigned char index) override {
if (index == 0) {
return _value;
return _temperature;
}

return 0.0;
return 0;
}

protected:
double _value = 0;

unsigned long _beta = NTC_BETA;
unsigned long _resistance_up = NTC_R_UP;
unsigned long _resistance_down = NTC_R_DOWN;
unsigned long _R0 = NTC_R0;
double _T0 = NTC_T0;
double _input_voltage = NTC_INPUT_VOLTAGE;
double _temperature { 0 };

};

0 comments on commit a1ffa9f

Please sign in to comment.