Skip to content

Commit

Permalink
Merge pull request #12 from jiangyi1985/master
Browse files Browse the repository at this point in the history
Concentration to AQI calculation for US and China.
  • Loading branch information
brentru authored Dec 23, 2024
2 parents 14f4fb9 + ba2dca4 commit bad1074
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 8 deletions.
157 changes: 156 additions & 1 deletion Adafruit_PM25AQI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*/

#include "Adafruit_PM25AQI.h"
#include <math.h>

/*!
* @brief Instantiates a new PM25AQI class
Expand Down Expand Up @@ -126,7 +127,7 @@ bool Adafruit_PM25AQI::read(PM25_AQI_Data *data) {
}

// Validate start byte is correct if using Adafruit PM sensors
if ((!is_pm1006 && buffer[0] != 0x42)) {
if ((!is_pm1006 && (buffer[0] != 0x42 || buffer[1] != 0x4d))) {
return false;
}

Expand Down Expand Up @@ -168,6 +169,160 @@ bool Adafruit_PM25AQI::read(PM25_AQI_Data *data) {
return false;
}

// convert concentration to AQI
data->aqi_pm25_us = pm25_aqi_us(data->pm25_env);
data->aqi_pm25_china = pm25_aqi_china(data->pm25_env);
data->aqi_pm100_us = pm100_aqi_us(data->pm100_env);
data->aqi_pm100_china = pm100_aqi_china(data->pm100_env);

// success!
return true;
}

/*!
* @brief Get AQI of PM2.5 in US standard
* @param concentration
* the environmental concentration of pm2.5 in ug/m3
* @return AQI number. 0 to 500 for valid calculation. 99999 for out of range.
*/
uint16_t Adafruit_PM25AQI::pm25_aqi_us(float concentration) {
float c;
float AQI;
c = (floor(10 * concentration)) / 10;
if (c < 0)
AQI = 0;
else if (c >= 0 && c < 12.1f) {
AQI = linear(50, 0, 12, 0, c);
} else if (c >= 12.1f && c < 35.5f) {
AQI = linear(100, 51, 35.4f, 12.1f, c);
} else if (c >= 35.5f && c < 55.5f) {
AQI = linear(150, 101, 55.4f, 35.5f, c);
} else if (c >= 55.5f && c < 150.5f) {
AQI = linear(200, 151, 150.4f, 55.5f, c);
} else if (c >= 150.5f && c < 250.5f) {
AQI = linear(300, 201, 250.4f, 150.5f, c);
} else if (c >= 250.5f && c < 350.5f) {
AQI = linear(400, 301, 350.4f, 250.5f, c);
} else if (c >= 350.5f && c < 500.5f) {
AQI = linear(500, 401, 500.4f, 350.5f, c);
} else {
AQI = 99999; //
}
return round(AQI);
}

/*!
* @brief Get AQI of PM10 in US standard
* @param concentration
* the environmental concentration of pm10 in ug/m3
* @return AQI number. 0 to 500 for valid calculation. 99999 for out of range.
*/
uint16_t Adafruit_PM25AQI::pm100_aqi_us(float concentration) {
float c;
float AQI;
c = concentration;
if (c < 0)
AQI = 0;
else if (c < 55) {
AQI = linear(50, 0, 55, 0, c);
} else if (c < 155) {
AQI = linear(100, 51, 155, 55, c);
} else if (c < 255) {
AQI = linear(150, 101, 255, 155, c);
} else if (c < 355) {
AQI = linear(200, 151, 355, 255, c);
} else if (c < 425) {
AQI = linear(300, 201, 425, 355, c);
} else if (c < 505) {
AQI = linear(400, 301, 505, 425, c);
} else if (c < 605) {
AQI = linear(500, 401, 605, 505, c);
} else {
AQI = 99999; //
}
return round(AQI);
}

/*!
* @brief Get AQI of PM2.5 in China standard
* @param concentration
* the environmental concentration of pm2.5 in ug/m3
* @return AQI number. 0 to 500 for valid calculation. 99999 for out of range.
*/
uint16_t Adafruit_PM25AQI::pm25_aqi_china(float concentration) {
float c;
float AQI;
c = concentration;
if (c < 0)
AQI = 0;
else if (c <= 35) {
AQI = linear(50, 0, 35, 0, c);
} else if (c <= 75) {
AQI = linear(100, 51, 75, 35, c);
} else if (c <= 115) {
AQI = linear(150, 101, 115, 75, c);
} else if (c <= 150) {
AQI = linear(200, 151, 150, 115, c);
} else if (c <= 250) {
AQI = linear(300, 201, 250, 150, c);
} else if (c <= 350) {
AQI = linear(400, 301, 350, 250, c);
} else if (c <= 500) {
AQI = linear(500, 401, 500, 350, c);
} else {
AQI = 99999; //
}
return round(AQI);
}

/*!
* @brief Get AQI of PM10 in China standard
* @param concentration
* the environmental concentration of pm10 in ug/m3
* @return AQI number. 0 to 500 for valid calculation. 99999 for out of range.
*/
uint16_t Adafruit_PM25AQI::pm100_aqi_china(float concentration) {
float c;
float AQI;
c = concentration;
if (c < 0)
AQI = 0;
else if (c <= 50) {
AQI = linear(50, 0, 50, 0, c);
} else if (c <= 150) {
AQI = linear(100, 51, 150, 50, c);
} else if (c <= 250) {
AQI = linear(150, 101, 250, 150, c);
} else if (c <= 350) {
AQI = linear(200, 151, 350, 250, c);
} else if (c <= 420) {
AQI = linear(300, 201, 420, 350, c);
} else if (c <= 500) {
AQI = linear(400, 301, 500, 420, c);
} else if (c <= 600) {
AQI = linear(500, 401, 600, 500, c);
} else {
AQI = 99999; //
}
return round(AQI);
}

/*!
* @brief Linearly map a concentration value to its AQI level
* @param aqi_high max aqi of the calculating range
* @param aqi_low min aqi of the calculating range
* @param conc_high max concentration value (ug/m3) of the calculating range
* @param conc_low min concentration value (ug/m3) of the calculating range
* @param concentration
* the concentration value to be calculated
* @return Calculated AQI value
*/
float Adafruit_PM25AQI::linear(uint16_t aqi_high, uint16_t aqi_low,
float conc_high, float conc_low,
float concentration) {
float f;
f = ((concentration - conc_low) / (conc_high - conc_low)) *
(aqi_high - aqi_low) +
aqi_low;
return f;
}
19 changes: 17 additions & 2 deletions Adafruit_PM25AQI.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,16 @@ typedef struct PMSAQIdata {
particles_25um, ///< 2.5um Particle Count
particles_50um, ///< 5.0um Particle Count
particles_100um; ///< 10.0um Particle Count
uint16_t unused; ///< Unused
uint16_t checksum; ///< Packet checksum
uint16_t unused; ///< Unused (version + error code)

uint16_t checksum; ///< Packet checksum

// AQI conversion results:
uint8_t aqi_pm25_us; ///< pm2.5 AQI of United States
uint8_t aqi_pm100_us; ///< pm10 AQI of United States
uint8_t aqi_pm25_china; ///< pm2.5 AQI of China
uint8_t aqi_pm100_china; ///< pm10 AQI of China

} PM25_AQI_Data;

/*!
Expand All @@ -56,6 +64,13 @@ class Adafruit_PM25AQI {
bool begin_UART(Stream *theStream);
bool read(PM25_AQI_Data *data);

uint16_t pm25_aqi_us(float concentration);
uint16_t pm25_aqi_china(float concentration);
uint16_t pm100_aqi_us(float concentration);
uint16_t pm100_aqi_china(float concentration);
float linear(uint16_t aqi_high, uint16_t aqi_low, float conc_high,
float conc_low, float concentration);

private:
Adafruit_I2CDevice *i2c_dev = NULL;
Stream *serial_dev = NULL;
Expand Down
15 changes: 10 additions & 5 deletions examples/PM25_test/PM25_test.ino
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,19 @@ void loop() {

if (! aqi.read(&data)) {
Serial.println("Could not read from AQI");

delay(500); // try again in a bit!
return;
}
Serial.println("AQI reading success");

Serial.println();
Serial.println(F("---------------------------------------"));
Serial.println(F("Concentration Units (standard)"));
Serial.println(F("---------------------------------------"));
Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_standard);
Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_standard);
Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_standard);
Serial.println(F("Concentration Units (environmental)"));
Serial.println(F("---------------------------------------"));
Serial.println(F("Concentration Units (environmental)"));
Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_env);
Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_env);
Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_env);
Expand All @@ -67,7 +66,13 @@ void loop() {
Serial.print(F("Particles > 5.0um / 0.1L air:")); Serial.println(data.particles_50um);
Serial.print(F("Particles > 10 um / 0.1L air:")); Serial.println(data.particles_100um);
Serial.println(F("---------------------------------------"));

Serial.println(F("AQI"));
Serial.print(F("PM2.5 AQI US: ")); Serial.print(data.aqi_pm25_us);
Serial.print(F("\tPM10 AQI US: ")); Serial.println(data.aqi_pm100_us);
// Serial.print(F("PM2.5 AQI China: ")); Serial.print(data.aqi_pm25_china);
// Serial.print(F("\tPM10 AQI China: ")); Serial.println(data.aqi_pm100_china);
Serial.println(F("---------------------------------------"));
Serial.println();

delay(1000);
}
}

0 comments on commit bad1074

Please sign in to comment.