From 4b2a5f55400d67aa0d33a289f1adc625c43b4c08 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sun, 21 Jul 2024 07:13:34 +0700 Subject: [PATCH] Add PM2.5 correction formula, #182 --- src/AgOledDisplay.cpp | 16 ++++++++++++---- src/AgValue.cpp | 18 ++++++++++++++++++ src/PMS/PMS.cpp | 35 +++++++++++++++++++++++++++++++++++ src/PMS/PMS.h | 1 + src/PMS/PMS5003.cpp | 11 +++++++++++ src/PMS/PMS5003.h | 1 + src/PMS/PMS5003T.cpp | 11 +++++++++++ src/PMS/PMS5003T.h | 1 + 8 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/AgOledDisplay.cpp b/src/AgOledDisplay.cpp index 22d25b2..abd0a04 100644 --- a/src/AgOledDisplay.cpp +++ b/src/AgOledDisplay.cpp @@ -10,7 +10,7 @@ * @param hasStatus */ void OledDisplay::showTempHum(bool hasStatus) { - char buf[10]; + char buf[16]; if (value.Temperature > -1001) { if (config.isTemperatureUnitInF()) { float tempF = (value.Temperature * 9) / 5 + 32; @@ -307,10 +307,14 @@ void OledDisplay::showDashboard(const char *status) { DISP()->drawStr(48, 27, "PM2.5"); /** Draw PM2.5 value */ + int pm25 = value.pm25_1; + if (config.hasSensorSHT) { + pm25 = ag->pms5003.pm25Compensated(pm25, value.Humidity); + } DISP()->setFont(u8g2_font_t0_22b_tf); if (config.isPmStandardInUSAQI()) { if (value.pm25_1 >= 0) { - sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(value.pm25_1)); + sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(pm25)); } else { sprintf(strBuf, "%s", "-"); } @@ -319,7 +323,7 @@ void OledDisplay::showDashboard(const char *status) { DISP()->drawUTF8(48, 61, "AQI"); } else { if (value.pm25_1 >= 0) { - sprintf(strBuf, "%d", value.pm25_1); + sprintf(strBuf, "%d", pm25); } else { sprintf(strBuf, "%s", "-"); } @@ -358,8 +362,12 @@ void OledDisplay::showDashboard(const char *status) { ag->display.setText(strBuf); /** Set PM */ + int pm25 = value.pm25_1; + if(config.hasSensorSHT) { + pm25 = (int)ag->pms5003.pm25Compensated(pm25, value.Humidity); + } ag->display.setCursor(0, 12); - snprintf(strBuf, sizeof(strBuf), "PM2.5:%d", value.pm25_1); + snprintf(strBuf, sizeof(strBuf), "PM2.5:%d", pm25); ag->display.setText(strBuf); /** Set temperature and humidity */ diff --git a/src/AgValue.cpp b/src/AgValue.cpp index bd729ea..1cc029b 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -50,6 +50,13 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } + if (config->hasSensorSHT && config->hasSensorPMS1) { + int pm25 = ag->pms5003.pm25Compensated(this->pm25_1, this->Humidity); + if (pm25 >= 0) { + root["pm02Compensated"] = pm25; + } + } + } else { if (config->hasSensorPMS1 && config->hasSensorPMS2) { root["pm01"] = ag->round2((this->pm01_1 + this->pm01_2) / 2.0); @@ -66,6 +73,11 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["rhumCompensated"] = (int)ag->pms5003t_2.humidityCompensated( (this->hum_1 + this->hum_2) / 2.0f); } + + int pm25 = (ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1) + + ag->pms5003t_2.pm25Compensated(this->pm25_2, this->temp_2)) / + 2; + root["pm02Compensated"] = pm25; } if (fwMode == FW_MODE_O_1PS || fwMode == FW_MODE_O_1PST) { @@ -82,6 +94,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["rhumCompensated"] = (int)ag->pms5003t_1.humidityCompensated(this->hum_1); } + root["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); } if (config->hasSensorPMS2) { root["pm01"] = this->pm01_2; @@ -96,6 +109,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["rhumCompensated"] = (int)ag->pms5003t_2.humidityCompensated(this->hum_2); } + root["pm02Compensated"] = ag->pms5003t_2.pm25Compensated(this->pm25_2, this->temp_2); } } else { if (fwMode == FW_MODE_O_1P) { @@ -112,6 +126,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["rhumCompensated"] = (int)ag->pms5003t_1.humidityCompensated(this->hum_1); } + root["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); } else if (config->hasSensorPMS2) { root["pm01"] = this->pm01_2; root["pm02"] = this->pm25_2; @@ -125,6 +140,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["rhumCompensated"] = (int)ag->pms5003t_1.humidityCompensated(this->hum_2); } + root["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); } } else { if (config->hasSensorPMS1) { @@ -140,6 +156,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["channels"]["1"]["rhumCompensated"] = (int)ag->pms5003t_1.humidityCompensated(this->hum_1); } + root["channels"]["1"]["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); } if (config->hasSensorPMS2) { root["channels"]["2"]["pm01"] = this->pm01_2; @@ -154,6 +171,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["channels"]["2"]["rhumCompensated"] = (int)ag->pms5003t_1.humidityCompensated(this->hum_2); } + root["channels"]["2"]["pm02Compensated"] = ag->pms5003t_2.pm25Compensated(this->pm25_2, this->temp_2); } } } diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index e9a1527..0a091fd 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -270,6 +270,41 @@ int PMSBase::pm25ToAQI(int pm02) { return 500; } +/** + * @brief Correction PM2.5 + * + * @param pm25 Raw PM2.5 value + * @param humidity Humidity value (%) + * @return float + */ +int PMSBase::pm25Compensated(int pm25, float humidity) { + float value; + if (humidity < 0) { + humidity = 0; + } + if (humidity > 100) { + humidity = 100; + } + + if(pm25 < 30) { + value = (pm25 * 0.524f) - (humidity * 0.0862f) + 5.75f; + } else if(pm25 < 50) { + value = (0.786f * (pm25 / 20 - 3 / 2) + 0.524f * (1 - (pm25 / 20 - 3 / 2))) * pm25 - (0.0862f * humidity) + 5.75f; + } else if(pm25 < 210) { + value = (0.786f * pm25) - (0.0862f * humidity) + 5.75f; + } else if(pm25 < 260) { + value = (0.69f * (pm25/50 - 21/5) + 0.786f * (1 - (pm25/50 - 21/5))) * pm25 - (0.0862f * humidity * (1 - (pm25/50 - 21/5))) + (2.966f * (pm25/50 -21/5)) + (5.75f * (1 - (pm25/50 - 21/5))) + (8.84f * (1.e-4) * pm25* (pm25/50 - 21/5)); + } else { + value = 2.966f + (0.69f * pm25) + (8.84f * (1.e-4) * pm25); + } + + if(value < 0) { + value = 0; + } + + return (int)value; +} + /** * @brief Convert two byte value to uint16_t value * diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index 4fa086a..c748d6b 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -28,6 +28,7 @@ public: uint16_t getHum(void); int pm25ToAQI(int pm02); + int pm25Compensated(int pm25, float humidity); private: Stream *stream; diff --git a/src/PMS/PMS5003.cpp b/src/PMS/PMS5003.cpp index 0e7c68b..4134855 100644 --- a/src/PMS/PMS5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -118,6 +118,17 @@ int PMS5003::getPm03ParticleCount(void) { return pms.getCount0_3(); } */ int PMS5003::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); } +/** + * @brief Correct PM2.5 + * + * @param pm25 PM2.5 raw value + * @param humidity Humidity value + * @return float + */ +int PMS5003::pm25Compensated(int pm25, float humidity) { + return pms.pm25Compensated(pm25, humidity); +} + /** * @brief Check device initialized or not * diff --git a/src/PMS/PMS5003.h b/src/PMS/PMS5003.h index cd66b07..b5be03c 100644 --- a/src/PMS/PMS5003.h +++ b/src/PMS/PMS5003.h @@ -24,6 +24,7 @@ public: int getPm10Ae(void); int getPm03ParticleCount(void); int convertPm25ToUsAqi(int pm25); + int pm25Compensated(int pm25, float humidity); private: bool _isBegin = false; diff --git a/src/PMS/PMS5003T.cpp b/src/PMS/PMS5003T.cpp index f0f9a1d..7cf6e3b 100644 --- a/src/PMS/PMS5003T.cpp +++ b/src/PMS/PMS5003T.cpp @@ -161,6 +161,17 @@ float PMS5003T::getRelativeHumidity(void) { return pms.getHum()/10.0f; } +/** + * @brief Correct PM2.5 + * + * @param pm25 PM2.5 raw value + * @param humidity Humidity value + * @return float + */ +float PMS5003T::pm25Compensated(int pm25, float humidity) { + return pms.pm25Compensated(pm25, humidity); +} + /** * @brief Check device initialized or not * diff --git a/src/PMS/PMS5003T.h b/src/PMS/PMS5003T.h index 2c99b7e..48b8333 100644 --- a/src/PMS/PMS5003T.h +++ b/src/PMS/PMS5003T.h @@ -29,6 +29,7 @@ public: int convertPm25ToUsAqi(int pm25); float getTemperature(void); float getRelativeHumidity(void); + float pm25Compensated(int pm25, float humidity); private: bool _isBegin = false;