Skip to content

Commit

Permalink
added RunningMean Class/Module
Browse files Browse the repository at this point in the history
allows for fast and easy RunningMean Calculation in C++
  • Loading branch information
DavZim committed Apr 8, 2019
1 parent d91c9c9 commit ccf1e94
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 1 deletion.
3 changes: 3 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ Imports:
glue,
shiny,
plotly
Depends:
Rcpp (>= 0.12.15)
Remotes: ropenscilabs/webrockets
LinkingTo: Rcpp
RcppModules: RunningMeanModule
VignetteBuilder: knitr
Encoding: UTF-8
RoxygenNote: 6.1.1
Expand Down
5 changes: 4 additions & 1 deletion R/zzz.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.onUnload <- function(libpath) {
library.dynam.unload("arduinor", libpath)
}
}

Rcpp::loadModule("RunningMeanModule", TRUE)

3 changes: 3 additions & 0 deletions src/RcppExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@ BEGIN_RCPP
END_RCPP
}

RcppExport SEXP _rcpp_module_boot_RunningMeanModule();

static const R_CallMethodDef CallEntries[] = {
{"_arduinor_ar_init", (DL_FUNC) &_arduinor_ar_init, 2},
{"_arduinor_ar_is_open", (DL_FUNC) &_arduinor_ar_is_open, 1},
{"_arduinor_ar_close", (DL_FUNC) &_arduinor_ar_close, 1},
{"_arduinor_ar_read", (DL_FUNC) &_arduinor_ar_read, 4},
{"_arduinor_ar_flush", (DL_FUNC) &_arduinor_ar_flush, 1},
{"_rcpp_module_boot_RunningMeanModule", (DL_FUNC) &_rcpp_module_boot_RunningMeanModule, 0},
{NULL, NULL, 0}
};

Expand Down
50 changes: 50 additions & 0 deletions src/RunningMean.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "RunningMean.h"


RunningMean::RunningMean() : n(0) {
stop("n (size of window) must be supplied");
}

// Initiates a new Running Mean class of size n (constant)
RunningMean::RunningMean(int n) : n(n) {
if (n <= 0) stop("n (size of window) must be supplied");
deq.resize(n);
n_values = 0;
sum = 0;
}

// inserts a new value into the internal deque. Deletes the oldest value
void RunningMean::insert(double v) {
if (n == 0) stop("n (size of window) must be larger than zero");

// TODO: What happens if we insert a missing value?
if (!R_IsNA(v) && !R_IsNaN(v)) {
n_values++;
sum += v - deq.back();
deq.push_front(v);
deq.pop_back();
}
}

// Returns the running mean of the values in the deque
// if the size is 0, return NA, if the number of already inserted values (n_values)
// is smaller than the size of the deque, use n_values. This allows the running mean
// to return values even if the number of values is smaller than window lengths
// could also be set to NA if needed...
double RunningMean::get_mean() {
if (n == 0) return NA_REAL;
if (n_values < n) return(sum / n_values);
return sum / n;
}

// prints the values of the deque
void RunningMean::show() {
Rcout << "RunningMean object <" << static_cast<const void*>(this) <<
"> window size " << n << ", number of inserts " << n_values << "\n" <<
deq[0];
for (int i = 1; i < n; ++i) {
Rcout << " " << deq[i];
}
Rcout << "\n";
}

55 changes: 55 additions & 0 deletions src/RunningMean.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include <Rcpp.h>
using namespace Rcpp;

/*
* Example R Code
*
* # Initiate the Class with a window-length of size 3
* obj <- arduinor:::RunningMean$new(3)
*
* # insert a new value
* obj$insert(1.03)
* obj$insert(1.05)
* obj$insert(1.04)
*
* # inspect the object
* obj
*
* # get the running mean
* obj$get_mean()
*
* # add another value, effectively removing the first insert (1.03)
* obj$insert(1.06)
* obj
* obj$get_mean()
*
*/

// defines the RunningMean class
class RunningMean{
public:
RunningMean();
RunningMean(int n);

void insert(double val);
double get_mean();
void show();

private:
std::deque<double> deq;
const int n;
int n_values;
double sum;
};

// Exposes the class
RCPP_MODULE(RunningMeanModule) {
class_<RunningMean>("RunningMean")
.default_constructor("Default constructor")
.constructor<int>("Constructor with an argument")
.method("insert", &RunningMean::insert)
.method("get_mean", &RunningMean::get_mean)
.method("show", &RunningMean::show)
;
}

0 comments on commit ccf1e94

Please sign in to comment.