215 } |
217 } |
216 date = time.Date(yy, time.Month(mm), dd, h, m, s, 0, time.Local) |
218 date = time.Date(yy, time.Month(mm), dd, h, m, s, 0, time.Local) |
217 return |
219 return |
218 } |
220 } |
219 |
221 |
|
222 func average(items []measurement) (measurement, error) { |
|
223 var avgMeasure measurement |
|
224 var avgCount int |
|
225 |
|
226 for _, data := range items { |
|
227 avgMeasure.Systolic += data.Systolic |
|
228 avgMeasure.Diastolic += data.Diastolic |
|
229 avgMeasure.Pulse += data.Pulse |
|
230 avgCount++ |
|
231 } |
|
232 |
|
233 roundDivision := func(a, b int) int { |
|
234 return int(0.5 + float64(a)/float64(b)) |
|
235 } |
|
236 |
|
237 if avgCount == 0 { |
|
238 return avgMeasure, fmt.Errorf("cannot compute average: empty set") |
|
239 } |
|
240 |
|
241 avgMeasure.Systolic = roundDivision(avgMeasure.Systolic, avgCount) |
|
242 avgMeasure.Diastolic = roundDivision(avgMeasure.Diastolic, avgCount) |
|
243 avgMeasure.Pulse = roundDivision(avgMeasure.Pulse, avgCount) |
|
244 |
|
245 return avgMeasure, nil |
|
246 } |
|
247 |
|
248 func intMedian(numbers []int) int { |
|
249 middle := len(numbers) / 2 |
|
250 med := numbers[middle] |
|
251 if len(numbers)%2 == 0 { |
|
252 med = (med + numbers[middle-1]) / 2 |
|
253 } |
|
254 return med |
|
255 } |
|
256 |
|
257 func median(items []measurement) (measurement, error) { |
|
258 var med measurement |
|
259 if len(items) == 0 { |
|
260 return med, fmt.Errorf("cannot compute average: empty set") |
|
261 } |
|
262 |
|
263 var sys, dia, pul []int |
|
264 for _, data := range items { |
|
265 sys = append(sys, data.Systolic) |
|
266 dia = append(dia, data.Diastolic) |
|
267 pul = append(pul, data.Pulse) |
|
268 } |
|
269 |
|
270 sort.Ints(sys) |
|
271 sort.Ints(dia) |
|
272 sort.Ints(pul) |
|
273 |
|
274 med.Systolic = intMedian(sys) |
|
275 med.Diastolic = intMedian(dia) |
|
276 med.Pulse = intMedian(pul) |
|
277 |
|
278 return med, nil |
|
279 } |
|
280 |
|
281 func stdDeviation(items []measurement) (measurement, error) { |
|
282 var sDev measurement |
|
283 |
|
284 if len(items) <= 1 { |
|
285 return sDev, fmt.Errorf("cannot compute deviation: set too small") |
|
286 } |
|
287 |
|
288 var sumSys, sumDia, sumPul float64 |
|
289 avg, err := average(items) |
|
290 if err != nil { |
|
291 return sDev, err |
|
292 } |
|
293 |
|
294 for _, data := range items { |
|
295 sumSys += math.Pow(float64(data.Systolic-avg.Systolic), 2) |
|
296 sumDia += math.Pow(float64(data.Diastolic-avg.Diastolic), 2) |
|
297 sumPul += math.Pow(float64(data.Pulse-avg.Pulse), 2) |
|
298 } |
|
299 |
|
300 sDev.Systolic = int(math.Sqrt(sumSys / float64(len(items)-1))) |
|
301 sDev.Diastolic = int(math.Sqrt(sumDia / float64(len(items)-1))) |
|
302 sDev.Pulse = int(math.Sqrt(sumPul / float64(len(items)-1))) |
|
303 |
|
304 return sDev, nil |
|
305 } |
|
306 |
220 func main() { |
307 func main() { |
221 inFile := flag.String([]string{"-input-file", "i"}, "", "Input JSON file") |
308 inFile := flag.String([]string{"-input-file", "i"}, "", "Input JSON file") |
222 outFile := flag.String([]string{"-output-file", "o"}, "", "Output JSON file") |
309 outFile := flag.String([]string{"-output-file", "o"}, "", "Output JSON file") |
223 limit := flag.Uint([]string{"-limit", "l"}, 0, "Limit number of items to N first") |
310 limit := flag.Uint([]string{"-limit", "l"}, 0, "Limit number of items to N first") |
224 since := flag.String([]string{"-since"}, "", |
311 since := flag.String([]string{"-since"}, "", |
225 "Filter records from date (YYYY-mm-dd HH:MM:SS)") |
312 "Filter records from date (YYYY-mm-dd HH:MM:SS)") |
226 format := flag.String([]string{"-format", "f"}, "", "Output format (csv, json)") |
313 format := flag.String([]string{"-format", "f"}, "", "Output format (csv, json)") |
227 avg := flag.Bool([]string{"-average", "a"}, false, "Compute average") |
314 avg := flag.Bool([]string{"-average", "a"}, false, "Compute average") |
|
315 stats := flag.Bool([]string{"-stats"}, false, "Compute statistics") |
228 merge := flag.Bool([]string{"-merge", "m"}, false, |
316 merge := flag.Bool([]string{"-merge", "m"}, false, |
229 "Try to merge input JSON file with fetched data") |
317 "Try to merge input JSON file with fetched data") |
230 device := flag.String([]string{"-device", "d"}, "/dev/ttyUSB0", "Serial device") |
318 device := flag.String([]string{"-device", "d"}, "/dev/ttyUSB0", "Serial device") |
231 |
319 |
232 flag.Parse() |
320 flag.Parse() |
286 |
374 |
287 if *limit > 0 && len(items) > int(*limit) { |
375 if *limit > 0 && len(items) > int(*limit) { |
288 items = items[0:*limit] |
376 items = items[0:*limit] |
289 } |
377 } |
290 |
378 |
291 var avgMeasure measurement |
379 if *format == "csv" { |
292 var avgCount int |
380 for i, data := range items { |
293 |
|
294 for i, data := range items { |
|
295 if *format == "csv" { |
|
296 fmt.Printf("%d;%x;%d-%02d-%02d %02d:%02d;%d;%d;%d\n", |
381 fmt.Printf("%d;%x;%d-%02d-%02d %02d:%02d;%d;%d;%d\n", |
297 i+1, data.Header, |
382 i+1, data.Header, |
298 data.Year, data.Month, data.Day, |
383 data.Year, data.Month, data.Day, |
299 data.Hour, data.Minute, |
384 data.Hour, data.Minute, |
300 data.Systolic, data.Diastolic, data.Pulse) |
385 data.Systolic, data.Diastolic, data.Pulse) |
301 } |
386 } |
302 |
387 } |
303 avgMeasure.Systolic += data.Systolic |
388 |
304 avgMeasure.Diastolic += data.Diastolic |
389 if *stats { |
305 avgMeasure.Pulse += data.Pulse |
390 *avg = true |
306 avgCount++ |
391 } |
307 } |
392 |
308 |
393 if *avg && len(items) > 0 { |
309 if *avg && avgCount > 0 { |
394 avgMeasure, err := average(items) |
310 roundDivision := func(a, b int) int { |
395 if err != nil { |
311 return int(0.5 + float64(a)/float64(b)) |
396 log.Println("Error:", err) |
312 } |
397 } else { |
313 avgMeasure.Systolic = roundDivision(avgMeasure.Systolic, avgCount) |
398 fmt.Printf("Average: %d;%d;%d\n", avgMeasure.Systolic, |
314 avgMeasure.Diastolic = roundDivision(avgMeasure.Diastolic, avgCount) |
399 avgMeasure.Diastolic, avgMeasure.Pulse) |
315 avgMeasure.Pulse = roundDivision(avgMeasure.Pulse, avgCount) |
400 } |
316 |
401 } |
317 fmt.Printf("Average: %d;%d;%d\n", avgMeasure.Systolic, |
402 |
318 avgMeasure.Diastolic, avgMeasure.Pulse) |
403 if *stats && len(items) > 1 { |
|
404 d, err := stdDeviation(items) |
|
405 if err != nil { |
|
406 log.Println("Error:", err) |
|
407 } else { |
|
408 fmt.Printf("Standard deviation: %d;%d;%d\n", |
|
409 d.Systolic, d.Diastolic, d.Pulse) |
|
410 } |
|
411 } |
|
412 if *stats && len(items) > 0 { |
|
413 m, err := median(items) |
|
414 if err != nil { |
|
415 log.Println("Error:", err) |
|
416 } else { |
|
417 fmt.Printf("Median values: %d;%d;%d\n", |
|
418 m.Systolic, m.Diastolic, m.Pulse) |
|
419 } |
319 } |
420 } |
320 |
421 |
321 if *format == "json" || *outFile != "" { |
422 if *format == "json" || *outFile != "" { |
322 rawJSON, err := json.MarshalIndent(items, "", " ") |
423 rawJSON, err := json.MarshalIndent(items, "", " ") |
323 if err != nil { |
424 if err != nil { |