2014-12-09 19:46:25 +00:00
|
|
|
|
/** Histogram functions.
|
|
|
|
|
*
|
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
2016-11-22 11:14:25 -05:00
|
|
|
|
* @copyright 2016, Institute for Automation of Complex Power Systems, EONERC
|
2015-06-02 21:53:04 +02:00
|
|
|
|
*********************************************************************************/
|
2014-12-09 19:46:25 +00:00
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2015-06-03 10:13:35 +02:00
|
|
|
|
#include <string.h>
|
2014-12-09 22:51:02 +00:00
|
|
|
|
#include <float.h>
|
2014-12-09 19:46:25 +00:00
|
|
|
|
#include <math.h>
|
2015-01-20 13:52:32 +00:00
|
|
|
|
#include <time.h>
|
2014-12-09 19:46:25 +00:00
|
|
|
|
|
|
|
|
|
#include "utils.h"
|
|
|
|
|
#include "hist.h"
|
|
|
|
|
|
2014-12-09 22:51:02 +00:00
|
|
|
|
#define VAL(h, i) ((h)->low + (i) * (h)->resolution)
|
|
|
|
|
#define INDEX(h, v) round((v - (h)->low) / (h)->resolution)
|
|
|
|
|
|
2016-11-08 00:36:04 -05:00
|
|
|
|
int hist_create(struct hist *h, double low, double high, double resolution)
|
2014-12-09 19:46:25 +00:00
|
|
|
|
{
|
2014-12-09 22:51:02 +00:00
|
|
|
|
h->low = low;
|
|
|
|
|
h->high = high;
|
2014-12-09 19:46:25 +00:00
|
|
|
|
h->resolution = resolution;
|
2016-10-30 22:55:12 -04:00
|
|
|
|
|
|
|
|
|
if (resolution > 0) {
|
|
|
|
|
h->length = (high - low) / resolution;
|
2016-11-08 00:36:04 -05:00
|
|
|
|
h->data = alloc(h->length * sizeof(hist_cnt_t));
|
2016-10-30 22:55:12 -04:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
h->length = 0;
|
|
|
|
|
h->data = NULL;
|
|
|
|
|
}
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2014-12-09 19:46:25 +00:00
|
|
|
|
hist_reset(h);
|
2016-11-08 00:36:04 -05:00
|
|
|
|
|
|
|
|
|
return 0;
|
2014-12-09 19:46:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-21 15:26:52 +01:00
|
|
|
|
void hist_destroy(struct hist *h)
|
2014-12-09 19:46:25 +00:00
|
|
|
|
{
|
2016-10-30 22:55:12 -04:00
|
|
|
|
if (h->data) {
|
|
|
|
|
free(h->data);
|
|
|
|
|
h->data = NULL;
|
|
|
|
|
}
|
2014-12-09 19:46:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void hist_put(struct hist *h, double value)
|
|
|
|
|
{
|
2014-12-09 22:51:02 +00:00
|
|
|
|
int idx = INDEX(h, value);
|
2015-10-08 10:49:51 +02:00
|
|
|
|
|
|
|
|
|
h->last = value;
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2014-12-09 22:51:02 +00:00
|
|
|
|
/* Update min/max */
|
|
|
|
|
if (value > h->highest)
|
|
|
|
|
h->highest = value;
|
|
|
|
|
if (value < h->lowest)
|
|
|
|
|
h->lowest = value;
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2014-12-09 22:51:02 +00:00
|
|
|
|
/* Check bounds and increment */
|
2015-01-20 10:52:04 +00:00
|
|
|
|
if (idx >= h->length)
|
2014-12-09 22:51:02 +00:00
|
|
|
|
h->higher++;
|
2015-01-20 10:52:04 +00:00
|
|
|
|
else if (idx < 0)
|
2014-12-09 22:51:02 +00:00
|
|
|
|
h->lower++;
|
2016-10-30 22:55:12 -04:00
|
|
|
|
else if (h->data != NULL)
|
2014-12-09 22:51:02 +00:00
|
|
|
|
h->data[idx]++;
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2015-06-02 22:06:59 +02:00
|
|
|
|
h->total++;
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2015-06-02 22:06:59 +02:00
|
|
|
|
/* Online / running calculation of variance and mean
|
|
|
|
|
* by Donald Knuth’s Art of Computer Programming, Vol 2, page 232, 3rd edition */
|
|
|
|
|
if (h->total == 1) {
|
|
|
|
|
h->_m[1] = h->_m[0] = value;
|
|
|
|
|
h->_s[1] = 0.0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
h->_m[0] = h->_m[1] + (value - h->_m[1]) / h->total;
|
|
|
|
|
h->_s[0] = h->_s[1] + (value - h->_m[1]) * (value - h->_m[0]);
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2015-06-02 22:06:59 +02:00
|
|
|
|
// set up for next iteration
|
2015-08-07 01:11:43 +02:00
|
|
|
|
h->_m[1] = h->_m[0];
|
2015-06-02 22:06:59 +02:00
|
|
|
|
h->_s[1] = h->_s[0];
|
2014-12-09 22:51:02 +00:00
|
|
|
|
}
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2014-12-09 19:46:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void hist_reset(struct hist *h)
|
|
|
|
|
{
|
2014-12-09 22:51:02 +00:00
|
|
|
|
h->total = 0;
|
|
|
|
|
h->higher = 0;
|
|
|
|
|
h->lower = 0;
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2014-12-09 22:51:02 +00:00
|
|
|
|
h->highest = DBL_MIN;
|
|
|
|
|
h->lowest = DBL_MAX;
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2016-10-30 22:55:12 -04:00
|
|
|
|
if (h->data)
|
|
|
|
|
memset(h->data, 0, h->length * sizeof(unsigned));
|
2014-12-09 19:46:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-09 22:51:02 +00:00
|
|
|
|
double hist_mean(struct hist *h)
|
|
|
|
|
{
|
2015-06-02 22:06:59 +02:00
|
|
|
|
return (h->total > 0) ? h->_m[0] : 0.0;
|
2014-12-09 22:51:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double hist_var(struct hist *h)
|
|
|
|
|
{
|
2015-06-02 22:06:59 +02:00
|
|
|
|
return (h->total > 1) ? h->_s[0] / (h->total - 1) : 0.0;
|
2014-12-09 22:51:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double hist_stddev(struct hist *h)
|
|
|
|
|
{
|
|
|
|
|
return sqrt(hist_var(h));
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-30 22:55:56 -04:00
|
|
|
|
void hist_print(struct hist *h, int details)
|
2014-12-09 22:51:02 +00:00
|
|
|
|
{ INDENT
|
2016-10-30 22:54:20 -04:00
|
|
|
|
stats("Counted values: %ju (%ju between %f and %f)", h->total, h->total-h->higher-h->lower, h->high, h->low);
|
2015-10-13 12:06:50 +02:00
|
|
|
|
stats("Highest: %f Lowest: %f", h->highest, h->lowest);
|
|
|
|
|
stats("Mu: %f Sigma2: %f Sigma: %f", hist_mean(h), hist_var(h), hist_stddev(h));
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2016-10-30 22:55:56 -04:00
|
|
|
|
if (details > 0 && h->total - h->higher - h->lower > 0) {
|
2015-09-22 12:58:37 +02:00
|
|
|
|
char *buf = hist_dump(h);
|
2015-10-13 12:06:50 +02:00
|
|
|
|
stats("Matlab: %s", buf);
|
2015-09-22 12:58:37 +02:00
|
|
|
|
free(buf);
|
2015-10-13 12:06:50 +02:00
|
|
|
|
|
|
|
|
|
hist_plot(h);
|
2015-06-10 14:58:42 +02:00
|
|
|
|
}
|
2014-12-09 22:51:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-09 19:46:25 +00:00
|
|
|
|
void hist_plot(struct hist *h)
|
|
|
|
|
{
|
2015-03-31 15:02:51 +02:00
|
|
|
|
char buf[HIST_HEIGHT];
|
|
|
|
|
memset(buf, '#', sizeof(buf));
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2015-06-10 14:58:42 +02:00
|
|
|
|
hist_cnt_t max = 1;
|
2014-12-09 19:46:25 +00:00
|
|
|
|
|
2015-06-02 22:06:59 +02:00
|
|
|
|
/* Get highest bar */
|
2014-12-09 19:46:25 +00:00
|
|
|
|
for (int i = 0; i < h->length; i++) {
|
|
|
|
|
if (h->data[i] > max)
|
|
|
|
|
max = h->data[i];
|
|
|
|
|
}
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2014-12-09 19:46:25 +00:00
|
|
|
|
/* Print plot */
|
2015-10-13 12:06:50 +02:00
|
|
|
|
stats("%9s | %5s | %s", "Value", "Count", "Plot");
|
2015-03-31 15:02:51 +02:00
|
|
|
|
line();
|
|
|
|
|
|
2014-12-09 19:46:25 +00:00
|
|
|
|
for (int i = 0; i < h->length; i++) {
|
2015-10-14 12:18:25 +02:00
|
|
|
|
double value = VAL(h, i);
|
2016-10-30 22:54:20 -04:00
|
|
|
|
hist_cnt_t cnt = h->data[i];
|
2015-10-14 12:18:25 +02:00
|
|
|
|
int bar = HIST_HEIGHT * ((double) cnt / max);
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2015-10-14 12:18:25 +02:00
|
|
|
|
if (value > h->lowest || value < h->highest)
|
2016-10-30 22:54:20 -04:00
|
|
|
|
stats("%+9g | %5ju | %.*s", value, cnt, bar, buf);
|
2014-12-09 19:46:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-22 12:58:37 +02:00
|
|
|
|
char * hist_dump(struct hist *h)
|
2014-12-09 19:46:25 +00:00
|
|
|
|
{
|
2015-09-22 12:58:37 +02:00
|
|
|
|
char *buf = alloc(128);
|
|
|
|
|
|
|
|
|
|
strcatf(&buf, "[ ");
|
2014-12-09 19:46:25 +00:00
|
|
|
|
|
2015-03-31 13:50:30 +02:00
|
|
|
|
for (int i = 0; i < h->length; i++)
|
2016-10-30 22:54:20 -04:00
|
|
|
|
strcatf(&buf, "%ju ", h->data[i]);
|
2015-03-31 13:50:30 +02:00
|
|
|
|
|
2015-09-22 12:58:37 +02:00
|
|
|
|
strcatf(&buf, "]");
|
|
|
|
|
|
|
|
|
|
return buf;
|
2015-01-20 13:52:32 +00:00
|
|
|
|
}
|
2014-12-09 19:46:25 +00:00
|
|
|
|
|
2016-10-22 20:38:31 -04:00
|
|
|
|
#ifdef WITH_JANSSON
|
|
|
|
|
json_t * hist_json(struct hist *h)
|
|
|
|
|
{
|
|
|
|
|
json_t *b = json_array();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < h->length; i++)
|
|
|
|
|
json_array_append(b, json_integer(h->data[i]));
|
|
|
|
|
|
|
|
|
|
return json_pack("{ s: f, s: f, s: i, s: i, s: i, s: f, s: f, s: f, s: f, s: f, s: o }",
|
|
|
|
|
"low", h->low,
|
|
|
|
|
"high", h->high,
|
|
|
|
|
"total", h->total,
|
|
|
|
|
"higher", h->higher,
|
|
|
|
|
"lower", h->lower,
|
|
|
|
|
"highest", h->highest,
|
|
|
|
|
"lowest", h->lowest,
|
|
|
|
|
"mean", hist_mean(h),
|
|
|
|
|
"variance", hist_var(h),
|
|
|
|
|
"stddev", hist_stddev(h),
|
|
|
|
|
"buckets", b
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int hist_dump_json(struct hist *h, FILE *f)
|
|
|
|
|
{
|
|
|
|
|
json_t *j = hist_json(h);
|
|
|
|
|
|
|
|
|
|
int ret = json_dumpf(j, f, 0);
|
|
|
|
|
|
|
|
|
|
json_decref(j);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
#endif /* WITH_JANNSON */
|
|
|
|
|
|
|
|
|
|
int hist_dump_matlab(struct hist *h, FILE *f)
|
2015-01-20 13:52:32 +00:00
|
|
|
|
{
|
2015-09-22 12:58:37 +02:00
|
|
|
|
char *buf = hist_dump(h);
|
2015-08-07 01:11:43 +02:00
|
|
|
|
|
2015-01-20 13:52:32 +00:00
|
|
|
|
fprintf(f, "%lu = struct( ", time(NULL));
|
2016-10-22 20:38:31 -04:00
|
|
|
|
fprintf(f, "'low', %f, ", h->low);
|
|
|
|
|
fprintf(f, "'high', %f, ", h->high);
|
2016-10-30 22:54:20 -04:00
|
|
|
|
fprintf(f, "'total', %ju, ", h->total);
|
|
|
|
|
fprintf(f, "'higher', %ju, ", h->higher);
|
|
|
|
|
fprintf(f, "'lower', %ju, ", h->lower);
|
2016-10-22 20:38:31 -04:00
|
|
|
|
fprintf(f, "'highest', %f, ", h->highest);
|
|
|
|
|
fprintf(f, "'lowest', %f, ", h->lowest);
|
2015-01-20 13:52:32 +00:00
|
|
|
|
fprintf(f, "'mean', %f, ", hist_mean(h));
|
2016-10-22 20:38:31 -04:00
|
|
|
|
fprintf(f, "'variance', %f, ", hist_var(h));
|
2015-01-20 13:52:32 +00:00
|
|
|
|
fprintf(f, "'stddev', %f, ", hist_stddev(h));
|
2016-10-22 20:38:31 -04:00
|
|
|
|
fprintf(f, "'buckets', %s ", buf);
|
2015-01-20 13:52:32 +00:00
|
|
|
|
fprintf(f, "),\n");
|
2015-09-22 12:58:37 +02:00
|
|
|
|
|
|
|
|
|
free(buf);
|
2016-10-22 20:38:31 -04:00
|
|
|
|
|
|
|
|
|
return 0;
|
2014-12-09 19:46:25 +00:00
|
|
|
|
}
|