1+ <?php
2+
3+
4+ /**
5+ * SCKSensorData
6+ *
7+ * Authors: Smart Citizen Team
8+ *
9+ * SCKSensorData implements all the methods necessary for calibrating
10+ * and rescaling the data received from a Smart Citizen Kit 1.1.
11+ *
12+ *
13+ * TODO: Data validation based on each sensor ranges.
14+ *
15+ * Example usage (receive data, converted and store it in a csv file):
16+ *
17+ * <?php
18+ * include('../sck_sensor_data.php');
19+ *
20+ * $headers = getallheaders();
21+ *
22+ * $data = $headers['X-SmartCitizenData'];
23+ *
24+ * $datapoints = json_decode($data, true);
25+ *
26+ * foreach ($datapoints as $datapoint) {
27+ * $datapoint = SCKSensorData::SCK11Convert($datapoint);
28+ * $csv .= implode(', ', $datapoint);
29+ * }
30+ *
31+ * $csv .= PHP_EOL;
32+ *
33+ * file_put_contents('./data.csv', $csv, FILE_APPEND);
34+ * ?>
35+ *
36+ * SCKSensorData is free software: you can redistribute it and/or modify
37+ * it under the terms of the GNU Lesser General Public License as
38+ * published by the Free Software Foundation, either version 3 of
39+ * the License, or (at your option) any later version.
40+ *
41+ * SCKSensorData is distributed in the hope that it will be useful,
42+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
43+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44+ * GNU Lesser General Public License for more details.
45+ *
46+ * You should have received a copy of the GNU Lesser General Public
47+ * License along with SCKSensorData. If not, see
48+ * <http://www.gnu.org/licenses/>.
49+ *
50+ */
51+
52+
53+ class SCKSensorData
54+ {
55+
56+
57+ /**
58+ * SCK11Calibration
59+ *
60+ * Calibrates to propper SI units an SCK datapoint
61+ *
62+ * @param array $rawBat Indexed array containing a SCK 1.1 datapoint
63+ * @return array Indexed arrary with a SCK datapoint calibrated
64+ *
65+ */
66+
67+ public function SCK11Convert ($ rawData )
68+ {
69+
70+ $ data = array ();
71+
72+ if (self ::isValidDateTimeString ($ rawData ['timestamp ' ])) { //Check calibration....
73+
74+ $ data ['timestamp ' ] = $ rawData ['timestamp ' ];
75+
76+ $ data ['temp ' ] = self ::tempConversion ($ rawData ['temp ' ]);
77+ $ data ['hum ' ] = self ::humConversion ($ rawData ['hum ' ]);
78+ $ data ['noise ' ] = self ::noiseConversion ($ rawData ['noise ' ]);
79+ $ data ['co ' ] = self ::coConversion ($ rawData ['co ' ]);
80+ $ data ['no2 ' ] = self ::no2Conversion ($ rawData ['no2 ' ]);
81+ $ data ['light ' ] = self ::lightConversion ($ rawData ['light ' ]);
82+ $ data ['bat ' ] = self ::batConversion ($ rawData ['bat ' ]);
83+ $ data ['panel ' ] = self ::panelConversion ($ rawData ['panel ' ]);
84+ $ data ['nets ' ] = $ rawData ['nets ' ];
85+
86+ return $ data ;
87+
88+ } else {
89+
90+ return false ;
91+
92+ }
93+
94+ }
95+
96+ /**
97+ * tempConversion
98+ *
99+ * Temperature calibration for SHT21 based on the datasheet:
100+ * https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/HTU-21D.pdf
101+ *
102+ * Formula can be tune depending on the SCK enclosure.
103+ *
104+ *
105+ * @param float $rawTemp
106+ * @return float Temperature in ºC
107+ *
108+ */
109+
110+ public function tempConversion ($ rawTemp )
111+ {
112+ return round (-53 + 175.72 / 65536.0 * $ rawTemp , 2 );
113+ }
114+
115+ /**
116+ * humConversion
117+ *
118+ * Humidity calibration for SHT21 based on the datasheet:
119+ * https://github.com/fablabbcn/Smart-Citizen-Kit/wiki/Datasheets/HTU-21D.pdf
120+ *
121+ * Formula can be tune depending on the SCK enclosure.
122+ *
123+ *
124+ * @param float $rawHum
125+ * @return float Rel. Humidity in %
126+ *
127+ */
128+
129+ public function humConversion ($ rawHum )
130+ {
131+ return round (7 + 125.0 / 65536.0 * $ rawHum , 2 );
132+ }
133+
134+ /**
135+ * noiseConversion
136+ *
137+ * Noise calibration for SCK1.1 sound sensor. Converts mV in to dBs.
138+ * Based on a linear regresion from a lookup table (db.json) obtained after real measurements from our test facility.
139+ *
140+ *
141+ * @param float $rawSound
142+ * @return float noise as sound pressure in dB
143+ *
144+ */
145+
146+ public function noiseConversion ($ rawSound )
147+ {
148+ $ dbTable = json_decode (file_get_contents ("./sensors/db.json " ), true );
149+ return round (self ::tableCalibration ($ dbTable , $ rawSound ), 2 );
150+ }
151+
152+ /**
153+ * coConversion
154+ *
155+ * CO values rescaling. For obtaining ppm check:
156+ *
157+ * @param float $rawCO
158+ * @return float sensor resistance in KOhm
159+ *
160+ */
161+
162+ public function coConversion ($ rawCO )
163+ {
164+ return round ($ rawCO / 1000 , 2 );
165+ }
166+
167+ /**
168+ * no2Conversion
169+ *
170+ * NO2 values rescaling. For obtaining ppm check:
171+ *
172+ * returns k0hm
173+ * @param float $rawNO2
174+ * @return float sensor resistance in KOhm
175+ *
176+ */
177+
178+ public function no2Conversion ($ rawNO2 )
179+ {
180+ return round ($ rawNO2 / 1000 , 2 );
181+ }
182+
183+ /**
184+ * lightConversion
185+ *
186+ * Light values rescaling.
187+ *
188+ * returns lux
189+ * @param float $rawLight
190+ * @return float light level in lux
191+ *
192+ */
193+
194+ public function lightConversion ($ rawLight )
195+ {
196+ return round ($ rawLight / 10 , 2 );
197+ }
198+
199+ /**
200+ * batConversion
201+ *
202+ * Battery values rescaling.
203+ *
204+ * @param float $rawBat
205+ * @return float battery level in %
206+ *
207+ */
208+
209+
210+ public function batConversion ($ rawBat )
211+ {
212+ return round ($ rawBat / 10 , 2 );
213+ }
214+
215+ /**
216+ * panelConversion
217+ *
218+ * Solar panel values rescaling.
219+ *
220+ * @param float $rawBat
221+ * @return float Tension in volts
222+ *
223+ */
224+
225+ public function panelConversion ($ rawBat )
226+ {
227+ return round ($ rawBat / 100 , 2 );
228+ }
229+
230+ /**
231+ * isValidDateTimeString
232+ *
233+ * Check if a string is a valid time stamp
234+ *
235+ * @param string $str_dt
236+ * @return bool
237+ *
238+ */
239+
240+ private function isValidDateTimeString ($ str_dt )
241+ {
242+ $ date1 = DateTime::createFromFormat ('Y-m-d G:i:s ' , $ str_dt );
243+ $ date2 = DateTime::createFromFormat ('Y-m-d H:i:s ' , $ str_dt );
244+ return $ date1 && ($ date1 ->format ('Y-m-d G:i:s ' ) == $ str_dt || $ date2 ->format ('Y-m-d H:i:s ' ) == $ str_dt );
245+ }
246+
247+ /**
248+ * tableCalibration
249+ *
250+ * Calculates a point based on a linear regresion from a look up table
251+ *
252+ * @param array $refTable
253+ * @param float $rawValue
254+ * @return float
255+ *
256+ */
257+
258+ private function tableCalibration ($ refTable , $ rawValue )
259+ {
260+ for ($ i = 0 ; $ i < sizeof ($ refTable ) - 1 ; $ i ++) {
261+ $ prevValueRef = $ refTable [$ i ][0 ];
262+ $ nextValueRef = $ refTable [$ i + 1 ][0 ];
263+ if ($ rawValue >= $ prevValueRef && $ rawValue < $ nextValueRef ) {
264+ $ prevValueOutput = $ refTable [$ i ][1 ];
265+ $ nextValueOutput = $ refTable [$ i + 1 ][1 ];
266+ $ result = self ::linearRegression ($ rawValue , $ prevValueOutput , $ nextValueOutput , $ prevValueRef , $ nextValueRef );
267+ return $ result ;
268+ }
269+ }
270+ }
271+
272+ /**
273+ * linearRegression
274+ * *
275+ * @param float $valueInput
276+ * @param float $prevValueOutput
277+ * @param float $nextValueOutput
278+ * @param float $prevValueRef
279+ * @param float $nextValueRef
280+ * @return float
281+ *
282+ */
283+
284+ private function linearRegression ($ valueInput , $ prevValueOutput , $ nextValueOutput , $ prevValueRef , $ nextValueRef )
285+ {
286+ $ slope = ($ nextValueOutput - $ prevValueOutput ) / ($ nextValueRef - $ prevValueRef );
287+ $ result = $ slope * ($ valueInput - $ prevValueRef ) + $ prevValueOutput ;
288+ return $ result ;
289+ }
290+
291+
292+
293+ }
294+
295+ ?>
0 commit comments