forked from bareboat-necessities/bbn_esp32_sensors_hub
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCQRobotTDS.h
126 lines (107 loc) · 4.41 KB
/
CQRobotTDS.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#ifndef CQROBOT_H
#define CQROBOT_H
/*
The ideal TDS level for drinking water is 300–500 ppm, while 500 ppm
is the maximum recommended by the EPA. Water with a TDS level above 1,000 ppm
is not considered safe to drink, and levels above 2,000 ppm may
require a filtration system.
*/
#define CQROBOT_SCOUNT 30
class CQRobotTDS {
public:
CQRobotTDS(int pin = G8, float aref = 3.3, float adcRange = 4096.0);
~CQRobotTDS();
float update(); // read and calculate
float update(float temp); // read and calculate
void setTemperature(float temp); // set the temperature and execute temperature compensation
void setAdcRange(float range); // 1024 for 10bit ADC; 4096 for 12bit ADC
float getTdsValue();
private:
int pin;
float aref; // default 3.3V on ESP32
float adcRange;
float temperature;
float tdsValue;
int analogBuffer[CQROBOT_SCOUNT]; // store the analog value in the array, read from ADC
int analogBufferTemp[CQROBOT_SCOUNT];
int analogBufferIndex = 0;
int copyIndex = 0;
float averageVoltage = 0;
int getMedianNum(int bArray[], int iFilterLen);
};
CQRobotTDS::CQRobotTDS(int pin, float aref, float adcRange)
: pin(pin), aref(aref), adcRange(adcRange) {
}
CQRobotTDS::~CQRobotTDS() {
}
float CQRobotTDS::update(float temp) {
// read and calculate
setTemperature(temp);
return update();
}
// readVoltage is used to improve the linearity of the ESP32 ADC
// see: https://github.com/G6EJD/ESP32-ADC-Accuracy-Improvement-function
double readVoltage(byte pin) {
double reading = analogRead(pin); // Reference voltage is 3v3 so maximum reading is 3v3 = 4095 in range 0 to 4095
if (reading < 1 || reading > 4095) return 0;
// return -0.000000000009824 * pow(reading,3) + 0.000000016557283 * pow(reading,2) + 0.000854596860691 * reading + 0.065440348345433;
return (-0.000000000000016 * pow(reading, 4) + 0.000000000118171 * pow(reading, 3) - 0.000000301211691 * pow(reading, 2) + 0.001109019271794 * reading + 0.034143524634089) * 1000;
} // Added an improved polynomial, use either, comment out as required
float CQRobotTDS::update() {
// read and calculate
static unsigned long analogSampleTimepoint = millis();
if (millis() - analogSampleTimepoint > 40U) {
// every 40 milliseconds, read the analog value from the ADC
analogSampleTimepoint = millis();
this->analogBuffer[this->analogBufferIndex] = readVoltage(this->pin); // read the analog value and store into the buffer
this->analogBufferIndex++;
if (this->analogBufferIndex == CQROBOT_SCOUNT) {
this->analogBufferIndex = 0;
}
}
static unsigned long printTimepoint = millis();
if (millis() - printTimepoint > 800U) {
printTimepoint = millis();
for (copyIndex = 0; copyIndex < CQROBOT_SCOUNT; copyIndex++) {
this->analogBufferTemp[copyIndex] = this->analogBuffer[copyIndex];
}
averageVoltage = getMedianNum(analogBufferTemp, CQROBOT_SCOUNT) * this->aref / this->adcRange; // read the analog value more stable by the median filtering algorithm, and convert to voltage value
float compensationCoefficient = 1.0 + 0.02 * (this->temperature - 25.0); // temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
float compensationVoltage = averageVoltage / compensationCoefficient; // temperature compensation
tdsValue = (133.42 * compensationVoltage * compensationVoltage * compensationVoltage - 255.86 * compensationVoltage * compensationVoltage + 857.39 * compensationVoltage) * 0.5; //convert voltage value to tds value
}
return tdsValue;
}
void CQRobotTDS::setTemperature(float temp) {
// set the temperature and execute temperature compensation
this->temperature = temp;
}
void CQRobotTDS::setAdcRange(float range) {
// 1024 for 10bit ADC; 4096 for 12bit ADC
this->adcRange = range;
}
float CQRobotTDS::getTdsValue() {
return tdsValue;
}
int CQRobotTDS::getMedianNum(int bArray[], int iFilterLen) {
int bTab[iFilterLen];
for (byte i = 0; i < iFilterLen; i++) {
bTab[i] = bArray[i];
}
int i, j, bTemp;
for (j = 0; j < iFilterLen - 1; j++) {
for (i = 0; i < iFilterLen - j - 1; i++) {
if (bTab[i] > bTab[i + 1]) {
bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
if ((iFilterLen & 1) > 0)
bTemp = bTab[(iFilterLen - 1) / 2];
else
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
return bTemp;
}
#endif