-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathMQ-135.py
166 lines (125 loc) · 5.1 KB
/
MQ-135.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/python
"""
@name: MQ-135.py - MQ-135 GAS SENSOR
@disclaimer: Copyright 2017, KRIPT4
@lastrelease: Dic 27 2017 16:50
"""
"""
MQ135 gas sensor | ADS1115 (Analog-to-Digital Converter for Raspberry Pi)
Datasheet can be found here: https://www.olimex.com/Products/Components/Sensors/SNS-MQ135/resources/SNS-MQ135.pdf
Application
They are used in air quality control equipments for buildings/offices, are suitable for detecting of NH3, NOx, alcohol, Benzene, smoke, CO2, etc
Original creator of this library: https://github.com/GeorgK/MQ135
"""
import sys
import math
import operator
t = 22 # assume current temperature. Recommended to measure with DHT22
h = 65 # assume current humidity. Recommended to measure with DHT22
"""
First version of an RaspBerryPi Library for the MQ135 gas sensor
TODO: Review the correction factor calculation. This currently relies on
the datasheet but the information there seems to be wrong.
"""
# The load resistance on the board
RLOAD = 10.0
# Calibration resistance at atmospheric CO2 level
RZERO = 76.63
# Parameters for calculating ppm of CO2 from sensor resistance
PARA = 116.6020682
PARB = 2.769034857
# Parameters to model temperature and humidity dependence
CORA = 0.00035
CORB = 0.02718
CORC = 1.39538
CORD = 0.0018
CORE = -0.003333333
CORF = -0.001923077
CORG = 1.130128205
# Atmospheric CO2 level for calibration purposes
ATMOCO2 = 397.13
"""
@brief Get the correction factor to correct for temperature and humidity
@param[in] t The ambient air temperature
@param[in] h The relative humidity
@return The calculated correction factor
"""
def getCorrectionFactor(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG):
# Linearization of the temperature dependency curve under and above 20 degree C
# below 20degC: fact = a * t * t - b * t - (h - 33) * d
# above 20degC: fact = a * t + b * h + c
# this assumes a linear dependency on humidity
if t < 20:
return CORA * t * t - CORB * t + CORC - (h-33.)*CORD
else:
return CORE * t + CORF * h + CORG
"""
@brief Get the resistance of the sensor, ie. the measurement value
@return The sensor resistance in kOhm
"""
def getResistance(value_pin,RLOAD):
return ((1023./value_pin) - 1.)*RLOAD
"""
@brief Get the resistance of the sensor, ie. the measurement value corrected
for temp/hum
@param[in] t The ambient air temperature
@param[in] h The relative humidity
@return The corrected sensor resistance kOhm
"""
def getCorrectedResistance(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG,value_pin,RLOAD):
return getResistance(value_pin,RLOAD) / getCorrectionFactor(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG)
"""
@brief Get the ppm of CO2 sensed (assuming only CO2 in the air)
@return The ppm of CO2 in the air
"""
def getPPM(PARA,RZERO,PARB,value_pin,RLOAD):
return PARA * math.pow((getResistance(value_pin,RLOAD)/RZERO), -PARB)
"""
@brief Get the ppm of CO2 sensed (assuming only CO2 in the air), corrected
for temp/hum
@param[in] t The ambient air temperature
@param[in] h The relative humidity
@return The ppm of CO2 in the air
"""
def getCorrectedPPM(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG,value_pin,RLOAD,PARA,RZERO,PARB):
return PARA * math.pow((getCorrectedResistance(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG,value_pin,RLOAD)/RZERO), -PARB)
"""
@brief Get the resistance RZero of the sensor for calibration purposes
@return The sensor resistance RZero in kOhm
"""
def getRZero(value_pin,RLOAD,ATMOCO2,PARA,PARB):
return getResistance(value_pin,RLOAD) * math.pow((ATMOCO2/PARA), (1./PARB))
"""
@brief Get the corrected resistance RZero of the sensor for calibration
purposes
@param[in] t The ambient air temperature
@param[in] h The relative humidity
@return The corrected sensor resistance RZero in kOhm
"""
def getCorrectedRZero(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG,value_pin,RLOAD,ATMOCO2,PARA,PARB):
return getCorrectedResistance(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG,value_pin,RLOAD) * math.pow((ATMOCO2/PARA), (1./PARB))
"""
Re-maps a number from one range to another. That is, a value of fromLow would get mapped to toLow,
a value of fromHigh to toHigh, values in-between to values in-between, etc.
# Arduino: (0 a 1023)
# Raspberry Pi: (0 a 26690)
More Info: https://www.arduino.cc/reference/en/language/functions/math/map/
"""
def map(x,in_min,in_max,out_min,out_max):
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
def main():
value_ads = 3300 # value obtained by ADS1115
value_pin = map((value_ads - 565), 0, 26690, 0, 1023) # 565 / 535 fix value
rzero = getRZero(value_pin,RLOAD,ATMOCO2,PARA,PARB)
correctedRZero = getCorrectedRZero(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG,value_pin,RLOAD,ATMOCO2,PARA,PARB)
resistance = getResistance(value_pin,RLOAD)
ppm = getPPM(PARA,RZERO,PARB,value_pin,RLOAD)
correctedPPM = getCorrectedPPM(t,h,CORA,CORB,CORC,CORD,CORE,CORF,CORG,value_pin,RLOAD,PARA,RZERO,PARB)
print("\n MQ135 Gas Sensor:\n")
print("\t MQ135 RZero: %s" % round(rzero))
print("\t Corrected RZero: %s" % round(correctedRZero))
print("\t Resistance: %s" % round(resistance))
print("\t PPM: %s" % round(ppm))
print("\t Corrected PPM: %s ppm" % round(correctedPPM))
if __name__ == "__main__":
main()