1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00
VILLASnode/lib/hist.c

288 lines
6.2 KiB
C
Raw Permalink Normal View History

/** Histogram functions.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
2017-04-27 12:56:43 +02:00
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
2017-04-27 12:56:43 +02:00
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
2017-04-27 12:56:43 +02:00
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
2015-06-02 21:53:04 +02:00
*********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
2015-06-03 10:13:35 +02:00
#include <string.h>
#include <float.h>
#include <math.h>
#include <time.h>
2017-12-09 02:19:28 +08:00
#include <villas/utils.h>
#include <villas/hist.h>
#include <villas/config.h>
#include <villas/table.h>
#define VAL(h, i) ((h)->low + (i) * (h)->resolution)
#define INDEX(h, v) round((v - (h)->low) / (h)->resolution)
int hist_init(struct hist *h, int buckets, hist_cnt_t warmup)
{
h->length = buckets;
h->warmup = warmup;
h->data = buckets ? alloc(h->length * sizeof(hist_cnt_t)) : NULL;
2015-08-07 01:11:43 +02:00
hist_reset(h);
return 0;
}
int hist_destroy(struct hist *h)
{
if (h->data) {
free(h->data);
h->data = NULL;
}
return 0;
}
void hist_put(struct hist *h, double value)
{
2015-10-08 10:49:51 +02:00
h->last = value;
2015-08-07 01:11:43 +02: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
if (h->total < h->warmup) {
}
else if (h->total == h->warmup) {
h->low = hist_mean(h) - 3 * hist_stddev(h);
h->high = hist_mean(h) + 3 * hist_stddev(h);
h->resolution = (h->high - h->low) / h->length;
}
else {
int idx = INDEX(h, value);
/* Check bounds and increment */
if (idx >= h->length)
h->higher++;
else if (idx < 0)
h->lower++;
else if (h->data != NULL)
h->data[idx]++;
}
2015-08-07 01:11:43 +02:00
h->total++;
2015-08-07 01:11:43 +02:00
/* Online / running calculation of variance and mean
* by Donald Knuths 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
// set up for next iteration
2015-08-07 01:11:43 +02:00
h->_m[1] = h->_m[0];
h->_s[1] = h->_s[0];
}
2015-08-07 01:11:43 +02:00
}
void hist_reset(struct hist *h)
{
h->total = 0;
h->higher = 0;
h->lower = 0;
2015-08-07 01:11:43 +02:00
h->highest = DBL_MIN;
h->lowest = DBL_MAX;
2015-08-07 01:11:43 +02:00
if (h->data)
memset(h->data, 0, h->length * sizeof(unsigned));
}
double hist_mean(struct hist *h)
{
2017-05-28 19:42:12 +02:00
return (h->total > 0) ? h->_m[0] : NAN;
}
double hist_var(struct hist *h)
{
2017-05-28 19:42:12 +02:00
return (h->total > 1) ? h->_s[0] / (h->total - 1) : NAN;
}
double hist_stddev(struct hist *h)
{
return sqrt(hist_var(h));
}
void hist_print(struct hist *h, int details)
{
2017-05-05 22:27:50 +00:00
if (h->total > 0) {
2017-05-05 16:18:25 +02:00
hist_cnt_t missed = h->total - h->higher - h->lower;
2017-05-05 16:18:25 +02:00
stats("Counted values: %ju (%ju between %f and %f)", h->total, missed, h->low, h->high);
stats("Highest: %g", h->highest);
stats("Lowest: %g", h->lowest);
stats("Mu: %g", hist_mean(h));
2018-04-26 09:30:54 +02:00
stats("1/Mu: %g", 1.0/hist_mean(h));
stats("Variance: %g", hist_var(h));
stats("Stddev: %g", hist_stddev(h));
2017-05-05 16:18:25 +02:00
if (details > 0 && h->total - h->higher - h->lower > 0) {
char *buf = hist_dump(h);
stats("Matlab: %s", buf);
free(buf);
hist_plot(h);
}
}
2017-05-05 16:18:25 +02:00
else
stats("Counted values: %ju", h->total);
}
void hist_plot(struct hist *h)
{
hist_cnt_t max = 1;
/* Get highest bar */
for (int i = 0; i < h->length; i++) {
if (h->data[i] > max)
max = h->data[i];
}
2017-07-24 19:33:35 +02:00
struct table_column cols[] = {
{ -9, "Value", "%+9.3g", NULL, TABLE_ALIGN_RIGHT },
{ -6, "Count", "%6ju", NULL, TABLE_ALIGN_RIGHT },
{ 0, "Plot", "%s", "occurences", TABLE_ALIGN_LEFT }
};
2017-07-24 19:33:35 +02:00
struct table table = {
.ncols = ARRAY_LEN(cols),
.cols = cols
};
2015-08-07 01:11:43 +02:00
/* Print plot */
table_header(&table);
for (int i = 0; i < h->length; i++) {
2015-10-14 12:18:25 +02:00
double value = VAL(h, i);
hist_cnt_t cnt = h->data[i];
int bar = cols[2]._width * ((double) cnt / max);
2017-07-24 19:33:35 +02:00
char *buf = strf("%s", "");
2017-05-05 22:27:50 +00:00
for (int i = 0; i < bar; i++)
buf = strcatf(&buf, "\u2588");
table_row(&table, value, cnt, buf);
2017-05-05 22:27:50 +00:00
free(buf);
}
2017-07-24 19:33:35 +02:00
table_footer(&table);
}
char * hist_dump(struct hist *h)
{
char *buf = alloc(128);
strcatf(&buf, "[ ");
for (int i = 0; i < h->length; i++)
strcatf(&buf, "%ju ", h->data[i]);
strcatf(&buf, "]");
return buf;
}
2016-10-22 20:38:31 -04:00
json_t * hist_json(struct hist *h)
{
json_t *json_buckets, *json_hist;
2017-05-28 19:42:12 +02:00
json_hist = json_pack("{ s: f, s: f, s: i }",
2016-10-22 20:38:31 -04:00
"low", h->low,
"high", h->high,
2017-05-28 19:42:12 +02:00
"total", h->total
2016-10-22 20:38:31 -04:00
);
2017-07-24 19:33:35 +02:00
2017-05-28 19:42:12 +02:00
if (h->total > 0) {
json_object_update(json_hist, json_pack("{ s: i, s: i, s: f, s: f, s: f, s: f, s: f }",
"higher", h->higher,
"lower", h->lower,
"highest", h->highest,
"lowest", h->lowest,
"mean", hist_mean(h),
"variance", hist_var(h),
"stddev", hist_stddev(h)
));
}
if (h->total - h->lower - h->higher > 0) {
json_buckets = json_array();
for (int i = 0; i < h->length; i++)
json_array_append(json_buckets, json_integer(h->data[i]));
json_object_set(json_hist, "buckets", json_buckets);
}
return json_hist;
2016-10-22 20:38:31 -04:00
}
int hist_dump_json(struct hist *h, FILE *f)
{
json_t *j = hist_json(h);
2016-10-22 20:38:31 -04:00
int ret = json_dumpf(j, f, 0);
2016-10-22 20:38:31 -04:00
json_decref(j);
2016-10-22 20:38:31 -04:00
return ret;
}
int hist_dump_matlab(struct hist *h, FILE *f)
{
fprintf(f, "struct(");
2016-10-22 20:38:31 -04:00
fprintf(f, "'low', %f, ", h->low);
fprintf(f, "'high', %f, ", h->high);
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);
fprintf(f, "'mean', %f, ", hist_mean(h));
2016-10-22 20:38:31 -04:00
fprintf(f, "'variance', %f, ", hist_var(h));
fprintf(f, "'stddev', %f, ", hist_stddev(h));
if (h->total - h->lower - h->higher > 0) {
char *buf = hist_dump(h);
fprintf(f, "'buckets', %s", buf);
free(buf);
}
else
fprintf(f, "'buckets', zeros(1, %d)", h->length);
fprintf(f, ")");
2016-10-22 20:38:31 -04:00
return 0;
}