From 4b2a5f55400d67aa0d33a289f1adc625c43b4c08 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sun, 21 Jul 2024 07:13:34 +0700 Subject: [PATCH 1/2] 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; From f3a9c722b254dfcd9a910034c736765bb14cd84b Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Fri, 16 Aug 2024 06:39:52 +0700 Subject: [PATCH 2/2] Change `pm25Compensated` to `compensated` --- src/AgOledDisplay.cpp | 4 ++-- src/AgValue.cpp | 18 +++++++++--------- src/PMS/PMS.cpp | 4 ++-- src/PMS/PMS.h | 2 +- src/PMS/PMS5003.cpp | 4 ++-- src/PMS/PMS5003.h | 2 +- src/PMS/PMS5003T.cpp | 4 ++-- src/PMS/PMS5003T.h | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/AgOledDisplay.cpp b/src/AgOledDisplay.cpp index adf2ab5..8b07ada 100644 --- a/src/AgOledDisplay.cpp +++ b/src/AgOledDisplay.cpp @@ -306,7 +306,7 @@ void OledDisplay::showDashboard(const char *status) { /** Draw PM2.5 value */ int pm25 = value.pm25_1; if (config.hasSensorSHT) { - pm25 = ag->pms5003.pm25Compensated(pm25, value.Humidity); + pm25 = ag->pms5003.compensated(pm25, value.Humidity); } DISP()->setFont(u8g2_font_t0_22b_tf); if (config.isPmStandardInUSAQI()) { @@ -366,7 +366,7 @@ void OledDisplay::showDashboard(const char *status) { /** Set PM */ int pm25 = value.pm25_1; if(config.hasSensorSHT) { - pm25 = (int)ag->pms5003.pm25Compensated(pm25, value.Humidity); + pm25 = (int)ag->pms5003.compensated(pm25, value.Humidity); } ag->display.setCursor(0, 12); if (utils::isValidPMS(value.pm25_1)) { diff --git a/src/AgValue.cpp b/src/AgValue.cpp index 0f39922..015a788 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -51,7 +51,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } if (config->hasSensorSHT && config->hasSensorPMS1) { - int pm25 = ag->pms5003.pm25Compensated(this->pm25_1, this->Humidity); + int pm25 = ag->pms5003.compensated(this->pm25_1, this->Humidity); if (pm25 >= 0) { root["pm02Compensated"] = pm25; } @@ -92,8 +92,8 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } - int pm25 = (ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1) + - ag->pms5003t_2.pm25Compensated(this->pm25_2, this->temp_2)) / + int pm25 = (ag->pms5003t_1.compensated(this->pm25_1, this->temp_1) + + ag->pms5003t_2.compensated(this->pm25_2, this->temp_2)) / 2; root["pm02Compensated"] = pm25; } @@ -133,7 +133,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); + root["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1); } if (config->hasSensorPMS2) { if(utils::isValidPMS(this->pm01_2)) { @@ -170,7 +170,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_2.pm25Compensated(this->pm25_2, this->temp_2); + root["pm02Compensated"] = ag->pms5003t_2.compensated(this->pm25_2, this->temp_2); } } else { if (fwMode == FW_MODE_O_1P) { @@ -207,7 +207,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); + root["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1); } else if (config->hasSensorPMS2) { if(utils::isValidPMS(this->pm01_2)) { root["pm01"] = this->pm01_2; @@ -241,7 +241,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); + root["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1); } } else { float val; @@ -278,7 +278,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["channels"]["1"]["pm02Compensated"] = ag->pms5003t_1.pm25Compensated(this->pm25_1, this->temp_1); + root["channels"]["1"]["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1); } if (config->hasSensorPMS2) { float val; @@ -314,7 +314,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["channels"]["2"]["pm02Compensated"] = ag->pms5003t_2.pm25Compensated(this->pm25_2, this->temp_2); + root["channels"]["2"]["pm02Compensated"] = ag->pms5003t_2.compensated(this->pm25_2, this->temp_2); } } } diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index 0a091fd..fb32767 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -275,9 +275,9 @@ int PMSBase::pm25ToAQI(int pm02) { * * @param pm25 Raw PM2.5 value * @param humidity Humidity value (%) - * @return float + * @return int */ -int PMSBase::pm25Compensated(int pm25, float humidity) { +int PMSBase::compensated(int pm25, float humidity) { float value; if (humidity < 0) { humidity = 0; diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index c748d6b..43e61b0 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -28,7 +28,7 @@ public: uint16_t getHum(void); int pm25ToAQI(int pm02); - int pm25Compensated(int pm25, float humidity); + int compensated(int pm25, float humidity); private: Stream *stream; diff --git a/src/PMS/PMS5003.cpp b/src/PMS/PMS5003.cpp index 09a9e8d..8a49550 100644 --- a/src/PMS/PMS5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -128,8 +128,8 @@ int PMS5003::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); } * @param humidity Humidity value * @return float */ -int PMS5003::pm25Compensated(int pm25, float humidity) { - return pms.pm25Compensated(pm25, humidity); +int PMS5003::compensated(int pm25, float humidity) { + return pms.compensated(pm25, humidity); } /** diff --git a/src/PMS/PMS5003.h b/src/PMS/PMS5003.h index b5be03c..aa6fcd9 100644 --- a/src/PMS/PMS5003.h +++ b/src/PMS/PMS5003.h @@ -24,7 +24,7 @@ public: int getPm10Ae(void); int getPm03ParticleCount(void); int convertPm25ToUsAqi(int pm25); - int pm25Compensated(int pm25, float humidity); + int compensated(int pm25, float humidity); private: bool _isBegin = false; diff --git a/src/PMS/PMS5003T.cpp b/src/PMS/PMS5003T.cpp index e754c6e..97cc9c7 100644 --- a/src/PMS/PMS5003T.cpp +++ b/src/PMS/PMS5003T.cpp @@ -171,8 +171,8 @@ float PMS5003T::getRelativeHumidity(void) { * @param humidity Humidity value * @return float */ -float PMS5003T::pm25Compensated(int pm25, float humidity) { - return pms.pm25Compensated(pm25, humidity); +float PMS5003T::compensated(int pm25, float humidity) { + return pms.compensated(pm25, humidity); } /** diff --git a/src/PMS/PMS5003T.h b/src/PMS/PMS5003T.h index 48b8333..3d2d567 100644 --- a/src/PMS/PMS5003T.h +++ b/src/PMS/PMS5003T.h @@ -29,7 +29,7 @@ public: int convertPm25ToUsAqi(int pm25); float getTemperature(void); float getRelativeHumidity(void); - float pm25Compensated(int pm25, float humidity); + float compensated(int pm25, float humidity); private: bool _isBegin = false;