From 13b2b80a81d0fb22fc19ea95960b6ce71b8558b5 Mon Sep 17 00:00:00 2001 From: oetiker Date: Thu, 4 Aug 2005 05:08:04 +0000 Subject: [PATCH] New VDEF functions for least squares slope, intercept & correlation for simple forecasting -- Trent Burkard git-svn-id: svn://svn.oetiker.ch/rrdtool/branches/1.2/program@669 a5681a0c-68f1-0310-ab6d-d61299d08faa --- doc/rrdgraph_rpn.pod | 12 ++++++++++++ src/rrd_graph.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/rrd_graph.h | 3 +++ 3 files changed, 63 insertions(+) diff --git a/doc/rrdgraph_rpn.pod b/doc/rrdgraph_rpn.pod index 74ac4ad..1aaef65 100644 --- a/doc/rrdgraph_rpn.pod +++ b/doc/rrdgraph_rpn.pod @@ -272,6 +272,18 @@ finite numbers and are always more than the I numbers. Example: C +=item LSLSLOPE, LSLINT, LSLCORREL + +Return the parameters for a Beast Bquares Bine I<(y = mx +b)> +which approximate the provided dataset. LSLSLOPE is the slope I<(m)> of +the line related to the COUNT position of the data. LSLINT is the +y-intercept I<(b)>, which happens also to be the first data point on the +graph. LSLCORREL is the Correlation Coefficient (also know as Pearson's +Product Moment Correlation Coefficient). It will range from 0 to +/-1 +and represents the quality of fit for the approximation. + +Example: C + =back =head1 SEE ALSO diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 2a13cb5..3ce3959 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -3406,6 +3406,9 @@ char *str; else if (!strcmp("TOTAL", func)) gdes->vf.op = VDEF_TOTAL; else if (!strcmp("FIRST", func)) gdes->vf.op = VDEF_FIRST; else if (!strcmp("LAST", func)) gdes->vf.op = VDEF_LAST; + else if (!strcmp("LSLSLOPE", func)) gdes->vf.op = VDEF_LSLSLOPE; + else if (!strcmp("LSLINT", func)) gdes->vf.op = VDEF_LSLINT; + else if (!strcmp("LSLCORREL",func)) gdes->vf.op = VDEF_LSLCORREL; else { rrd_set_error("Unknown function '%s' in VDEF '%s'\n" ,func @@ -3441,6 +3444,9 @@ char *str; case VDEF_TOTAL: case VDEF_FIRST: case VDEF_LAST: + case VDEF_LSLSLOPE: + case VDEF_LSLINT: + case VDEF_LSLCORREL: if (isnan(param)) { gdes->vf.param = DNAN; gdes->vf.val = DNAN; @@ -3599,6 +3605,48 @@ printf("DEBUG: %3li:%10.2f %c\n",step,array[step],step==field?'*':' '); dst->vf.when = src->start + (step+1)*src->step; } break; + case VDEF_LSLSLOPE: + case VDEF_LSLINT: + case VDEF_LSLCORREL:{ + /* Bestfit line by linear least squares method */ + + int cnt=0; + double SUMx, SUMy, SUMxy, SUMxx, SUMyy, slope, y_intercept, correl ; + SUMx = 0; SUMy = 0; SUMxy = 0; SUMxx = 0; SUMyy = 0; + + for (step=0;stepds_cnt])) { + cnt++; + SUMx += step; + SUMxx += step * step; + SUMxy += step * data[step*src->ds_cnt]; + SUMy += data[step*src->ds_cnt]; + SUMyy += data[step*src->ds_cnt]*data[step*src->ds_cnt]; + }; + } + + slope = ( SUMx*SUMy - cnt*SUMxy ) / ( SUMx*SUMx - cnt*SUMxx ); + y_intercept = ( SUMy - slope*SUMx ) / cnt; + correl = (SUMxy - (SUMx*SUMy)/cnt) / sqrt((SUMxx - (SUMx*SUMx)/cnt)*(SUMyy - (SUMy*SUMy)/cnt)); + + if (cnt) { + if (dst->vf.op == VDEF_LSLSLOPE) { + dst->vf.val = slope; + dst->vf.when = cnt*src->step; + } else if (dst->vf.op == VDEF_LSLINT) { + dst->vf.val = y_intercept; + dst->vf.when = cnt*src->step; + } else if (dst->vf.op == VDEF_LSLCORREL) { + dst->vf.val = correl; + dst->vf.when = cnt*src->step; + }; + + } else { + dst->vf.val = DNAN; + dst->vf.when = 0; + } + } + break; } return 0; } diff --git a/src/rrd_graph.h b/src/rrd_graph.h index 9ced52e..01b6799 100644 --- a/src/rrd_graph.h +++ b/src/rrd_graph.h @@ -42,6 +42,9 @@ enum vdef_op_en { ,VDEF_TOTAL /* average multiplied by time */ ,VDEF_FIRST /* first non-unknown value and time */ ,VDEF_LAST /* last non-unknown value and time */ + ,VDEF_LSLSLOPE /* least squares line slope */ + ,VDEF_LSLINT /* least squares line y_intercept */ + ,VDEF_LSLCORREL /* least squares line correlation coefficient */ }; enum text_prop_en { TEXT_PROP_DEFAULT=0, /* default settings */ TEXT_PROP_TITLE, /* properties for the title */ -- 2.11.0