HCesp/NTC_10K.cpp

136 lines
3.8 KiB
C++

#include "Arduino.h"
#include "HermitCrab.h"
#include "NTC_10K.h"
#include "Config.h"
const float resistance[] = {
3360850.37, // -40°C
1973470.32, // -35°C
1179560.43, // -30°C
718858.73, // -25°C
445267.47, // -20°C
281046.96, // -15°C
180321.36, // -10°C
117081.11, // -5°C
77147.90, // 0°C
51471.97, // 5°C
34838.43, // 10°C
23847.63, // 15°C
16594.38, // 20°C
12307.39, // 21°C
11739.87, // 22°C
11203.64, // 23°C
10696.86, // 24°C
10217.84, // 25°C
9527.52, // 26°C
9076.66, // 27°C
8656.02, // 28°C
8263.81, // 29°C
7897.84, // 30°C
5868.86, // 35°C
4383.72, // 40°C
3315.12, // 45°C
2527.73, // 50°C
1942.15, // 55°C
1505.11, // 60°C
1174.71, // 65°C
926.23, // 70°C
735.99, // 75°C
588.91, // 80°C
474.43, // 85°C
384.48, // 90°C
313.88, // 95°C
258.87, // 100°C
215.64, // 105°C
181.10, // 110°C
153.01, // 115°C
129.77, // 120°C
110.27, // 125°C
94.03, // 130°C
80.13, // 135°C
68.18, // 140°C
57.99, // 145°C
49.30 // 150°C
};
const int16_t temp_C[] = {
-40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100,
105, 110, 115, 120, 125, 130, 135, 140, 145, 150 };
NTC_10K ntc;
void NTC_10K::setup(bool bNegativePolarity) {
m_bNegativePolarity = bNegativePolarity;
_vRef = 3.3f;
_RESO = 4095;
m_nTemp = -9999;
m_fTemp = -9999.0;
m_fLastTemp = 0.0f;
pinMode(PIN_NTC, INPUT); // Set PIN_NTC as input
analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095)
analogSetAttenuation(ADC_11db); // Set attenuation for full-scale 3.3V
}
/**
* @brief Reads NTC sensor, calculates temperature via interpolation,
* and applies an Exponential Moving Average (EMA) filter.
* * History:
* - 2026-04-16: Refactored from Simple Moving Average (SMA) to EMA with float buffer.
* - 2026-04-16: Optimized interpolation to reduce CPU cycles.
* - 2026-04-16: Implemented aggressive alpha (0.01) to mitigate 5°C PWM noise.
* - 2026-04-16: Upgraded lastTemp to float (m_fLastTemp) for total precision.
*/
void NTC_10K::readSensor() {
float Vin;
float currentInstantTemp; // High-precision intermediate
// 1. Hardware Acquisition
int adcValue = constrain(analogRead(PIN_NTC), 1, 4094);
// 2. Voltage and Resistance Calculation
Vin = (float)adcValue * _vRef / _RESO;
float r;
if (m_bNegativePolarity) {
r = (Vin / (_vRef - Vin)) * rRef;
} else {
r = ((_vRef - Vin) / Vin) * rRef;
}
// 3. Table Lookup
int i = 0;
int tableSize = sizeof(resistance) / sizeof(resistance[0]);
while (i < tableSize - 1 && resistance[i] > r) {
i++;
}
// 4. Interpolation Logic (Precise Float Math)
if (i == 0 || i == tableSize - 1) {
// Use last known good float value if out of bounds
currentInstantTemp = (m_fLastTemp != 0.0f) ? m_fLastTemp : 0.0f;
}
else {
// Faster Slope Calculation: y = y0 + m * (r - r0)
float m = (temp_C[i] - temp_C[i - 1]) / (resistance[i] - resistance[i - 1]);
currentInstantTemp = temp_C[i - 1] + m * (r - resistance[i - 1]);
}
// 5. Exponential Moving Average (EMA) Filtering
if (m_fTemp < -5000.0f) {
m_fTemp = currentInstantTemp;
} else {
// 0.01f Alpha: The 5°C PWM noise now only moves the buffer by 0.05°C per hit.
const float alpha = 0.05f;
m_fTemp = (currentInstantTemp * alpha) + (m_fTemp * (1.0f - alpha));
}
// 6. Update Outputs
m_fLastTemp = currentInstantTemp; // Store precise float for next loop
m_nTemp = (int16_t)roundf(m_fTemp * 10.0f); // Final integer output (e.g., 25.34 -> 253)
}