mirror of
https://github.com/jdejaegh/python-irceline.git
synced 2025-06-26 19:35:40 +02:00
BelAQI index
This commit is contained in:
parent
2c09eec3e1
commit
fb365cd331
3 changed files with 122 additions and 1 deletions
54
src/open_irceline/belaqi.py
Normal file
54
src/open_irceline/belaqi.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
"""
|
||||
Compute the BelAQI index from concentrations of PM10, PM2.5, O3 and NO2, based on
|
||||
https://www.irceline.be/en/air-quality/measurements/belaqi-air-quality-index/information
|
||||
|
||||
> to calculate the actual (hour per hour varying) sub-indexes and the global index, the concentration scales of Table 4
|
||||
> are applied to the latest hourly mean O3 and NO2 concentrations and the running 24-hourly mean PM2.5 and PM10
|
||||
> concentrations.
|
||||
"""
|
||||
from src.open_irceline.data import BelAqiIndex
|
||||
|
||||
|
||||
def belaqi_index(pm10: float, pm25: float, o3: float, no2: float) -> BelAqiIndex:
|
||||
"""
|
||||
Computes the BelAQI index based on the components
|
||||
Raise ValueError if a component is < 0
|
||||
:param pm10: PM10 daily mean (or running 24-hourly mean for real-time) (µg/m³)
|
||||
:param pm25: PM2.5 daily mean (or running 24-hourly mean for real-time) (µg/m³)
|
||||
:param o3: O3 max 1-hourly mean per day (or latest hourly mean for real-time) (µg/m³)
|
||||
:param no2: NO2 max 1-hourly mean per day (or latest hourly mean for real-time) (µg/m³)
|
||||
:return: BelAQI index from 1 to 10 (Value of BelAqiIndex enum)
|
||||
"""
|
||||
|
||||
if pm10 < 0 or pm25 < 0 or o3 < 0 or no2 < 0:
|
||||
raise ValueError("All the components should have a positive value")
|
||||
|
||||
elif pm10 > 100 or pm25 > 70 or o3 > 320 or no2 > 300:
|
||||
return BelAqiIndex.HORRIBLE
|
||||
|
||||
elif pm10 > 80 or pm25 > 60 or o3 > 280 or no2 > 250:
|
||||
return BelAqiIndex.VERY_BAD
|
||||
|
||||
elif pm10 > 70 or pm25 > 50 or o3 > 240 or no2 > 200:
|
||||
return BelAqiIndex.BAD
|
||||
|
||||
elif pm10 > 60 or pm25 > 40 or o3 > 180 or no2 > 180:
|
||||
return BelAqiIndex.VERY_POOR
|
||||
|
||||
elif pm10 > 50 or pm25 > 35 or o3 > 160 or no2 > 150:
|
||||
return BelAqiIndex.POOR
|
||||
|
||||
elif pm10 > 40 or pm25 > 25 or o3 > 120 or no2 > 120:
|
||||
return BelAqiIndex.MODERATE
|
||||
|
||||
elif pm10 > 30 or pm25 > 15 or o3 > 70 or no2 > 70:
|
||||
return BelAqiIndex.FAIRLY_GOOD
|
||||
|
||||
elif pm10 > 20 or pm25 > 10 or o3 > 50 or no2 > 50:
|
||||
return BelAqiIndex.GOOD
|
||||
|
||||
elif pm10 > 10 or pm25 > 5 or o3 > 25 or no2 > 20:
|
||||
return BelAqiIndex.VERY_GOOD
|
||||
|
||||
elif pm10 >= 0 or pm25 >= 0 or o3 >= 0 or no2 >= 0:
|
||||
return BelAqiIndex.EXCELLENT
|
|
@ -1,5 +1,5 @@
|
|||
from datetime import datetime, date
|
||||
from enum import StrEnum
|
||||
from enum import StrEnum, Enum
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
|
@ -41,3 +41,16 @@ class FeatureValue(TypedDict):
|
|||
# Timestamp at which the value was computed
|
||||
timestamp: datetime | date
|
||||
value: int | float | None
|
||||
|
||||
|
||||
class BelAqiIndex(Enum):
|
||||
EXCELLENT = 1
|
||||
VERY_GOOD = 2
|
||||
GOOD = 3
|
||||
FAIRLY_GOOD = 4
|
||||
MODERATE = 5
|
||||
POOR = 6
|
||||
VERY_POOR = 7
|
||||
BAD = 8
|
||||
VERY_BAD = 9
|
||||
HORRIBLE = 10
|
||||
|
|
54
tests/test_belaqi.py
Normal file
54
tests/test_belaqi.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
from src.open_irceline.belaqi import belaqi_index
|
||||
from src.open_irceline.data import BelAqiIndex
|
||||
|
||||
|
||||
def test_belaqi_index():
|
||||
# Excellent
|
||||
assert belaqi_index(5, 2, 10, 10) == BelAqiIndex.EXCELLENT
|
||||
assert belaqi_index(0, 0, 0, 0) == BelAqiIndex.EXCELLENT
|
||||
assert belaqi_index(10, 5, 25, 20) == BelAqiIndex.EXCELLENT
|
||||
|
||||
# Very good
|
||||
assert belaqi_index(15, 8, 40, 35) == BelAqiIndex.VERY_GOOD
|
||||
assert belaqi_index(11, 6, 26, 21) == BelAqiIndex.VERY_GOOD
|
||||
assert belaqi_index(20, 10, 50, 50) == BelAqiIndex.VERY_GOOD
|
||||
|
||||
# Good
|
||||
assert belaqi_index(25, 12, 60, 60) == BelAqiIndex.GOOD
|
||||
assert belaqi_index(21, 11, 51, 51) == BelAqiIndex.GOOD
|
||||
assert belaqi_index(30, 15, 70, 70) == BelAqiIndex.GOOD
|
||||
|
||||
# Fairly good
|
||||
assert belaqi_index(35, 20, 100, 90) == BelAqiIndex.FAIRLY_GOOD
|
||||
assert belaqi_index(31, 16, 71, 71) == BelAqiIndex.FAIRLY_GOOD
|
||||
assert belaqi_index(40, 25, 120, 120) == BelAqiIndex.FAIRLY_GOOD
|
||||
|
||||
# Moderate
|
||||
assert belaqi_index(45, 30, 140, 130) == BelAqiIndex.MODERATE
|
||||
assert belaqi_index(41, 26, 121, 121) == BelAqiIndex.MODERATE
|
||||
assert belaqi_index(50, 35, 160, 150) == BelAqiIndex.MODERATE
|
||||
|
||||
# Poor
|
||||
assert belaqi_index(55, 38, 170, 160) == BelAqiIndex.POOR
|
||||
assert belaqi_index(51, 36, 161, 151) == BelAqiIndex.POOR
|
||||
assert belaqi_index(60, 40, 180, 180) == BelAqiIndex.POOR
|
||||
|
||||
# Very poor
|
||||
assert belaqi_index(65, 45, 200, 190) == BelAqiIndex.VERY_POOR
|
||||
assert belaqi_index(61, 41, 181, 181) == BelAqiIndex.VERY_POOR
|
||||
assert belaqi_index(70, 50, 240, 200) == BelAqiIndex.VERY_POOR
|
||||
|
||||
# Bad
|
||||
assert belaqi_index(75, 55, 260, 220) == BelAqiIndex.BAD
|
||||
assert belaqi_index(71, 51, 241, 201) == BelAqiIndex.BAD
|
||||
assert belaqi_index(80, 60, 280, 250) == BelAqiIndex.BAD
|
||||
|
||||
# Very bad
|
||||
assert belaqi_index(85, 65, 300, 270) == BelAqiIndex.VERY_BAD
|
||||
assert belaqi_index(81, 61, 281, 251) == BelAqiIndex.VERY_BAD
|
||||
assert belaqi_index(100, 70, 320, 300) == BelAqiIndex.VERY_BAD
|
||||
|
||||
# Horrible
|
||||
assert belaqi_index(110, 75, 330, 310) == BelAqiIndex.HORRIBLE
|
||||
assert belaqi_index(101, 71, 321, 301) == BelAqiIndex.HORRIBLE
|
||||
assert belaqi_index(150, 100, 400, 400) == BelAqiIndex.HORRIBLE
|
Loading…
Add table
Reference in a new issue