From: Omar Tarabai Date: Thu, 26 Jun 2014 16:18:31 +0000 (+0000) Subject: sensor analysis: gaussian model X-Git-Tag: initial-import-from-subversion-38251~3556 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=e253b2d47cc6448b12ad006a3e7d95b58b90f256;p=oweals%2Fgnunet.git sensor analysis: gaussian model --- diff --git a/src/sensor/gnunet-service-sensor-analysis.c b/src/sensor/gnunet-service-sensor-analysis.c index 531f7857d..0dcae61b6 100644 --- a/src/sensor/gnunet-service-sensor-analysis.c +++ b/src/sensor/gnunet-service-sensor-analysis.c @@ -27,6 +27,7 @@ #include "gnunet_util_lib.h" #include "sensor.h" #include "gnunet_peerstore_service.h" +#include "gnunet_sensor_model_plugin.h" #define LOG(kind,...) GNUNET_log_from (kind, "sensor-analysis",__VA_ARGS__) @@ -57,6 +58,11 @@ struct SensorModel */ struct GNUNET_PEERSTORE_WatchContext *wc; + /* + * Closure for model plugin + */ + void *cls; + }; /** @@ -109,6 +115,12 @@ destroy_sensor_model (struct SensorModel *sensor_model) GNUNET_PEERSTORE_watch_cancel(sensor_model->wc); sensor_model->wc = NULL; } + if (NULL != sensor_model->cls) + { + model_api->destroy_model (sensor_model->cls); + sensor_model->cls = NULL; + } + GNUNET_free(sensor_model); sensor_model = NULL; } @@ -120,23 +132,23 @@ void SENSOR_analysis_stop() struct SensorModel *sm; LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopping sensor analysis module.\n"); - if (NULL != model_api) - { - GNUNET_break (NULL == GNUNET_PLUGIN_unload (model_lib_name, model_api)); - GNUNET_free (model_lib_name); - model_lib_name = NULL; - } while (NULL != models_head) { sm = models_head; - destroy_sensor_model(sm); GNUNET_CONTAINER_DLL_remove(models_head, models_tail, sm); + destroy_sensor_model(sm); } if (NULL != peerstore) { GNUNET_PEERSTORE_disconnect(peerstore); peerstore = NULL; } + if (NULL != model_api) + { + GNUNET_break (NULL == GNUNET_PLUGIN_unload (model_lib_name, model_api)); + GNUNET_free (model_lib_name); + model_lib_name = NULL; + } } /* @@ -147,8 +159,28 @@ sensor_watcher (void *cls, struct GNUNET_PEERSTORE_Record *record, char *emsg) { + struct SensorModel *sensor_model = cls; + double *val; + int anomalous; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a sensor value, will feed to sensor model.\n"); + if (sizeof(double) != record->value_size) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Received an invalid sensor value.")); + return GNUNET_YES; + } + val = (double *)(record->value); + anomalous = model_api->feed_model (sensor_model->cls, *val); + if (GNUNET_YES == anomalous) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Anomaly detected, value: %f.\n", + *val); + } + else + LOG (GNUNET_ERROR_TYPE_DEBUG, "Value non-anomalous.\n"); return GNUNET_YES; } @@ -176,6 +208,7 @@ init_sensor_model (void *cls, sensor_model->wc = GNUNET_PEERSTORE_watch(peerstore, "sensor", &peerid, sensor->name, &sensor_watcher, sensor_model); + sensor_model->cls = model_api->create_model(model_api->cls); GNUNET_CONTAINER_DLL_insert(models_head, models_tail, sensor_model); LOG (GNUNET_ERROR_TYPE_DEBUG, "Created sensor model for `%s'.\n", sensor->name); diff --git a/src/sensor/gnunet_sensor_model_plugin.h b/src/sensor/gnunet_sensor_model_plugin.h index b2973a60d..ddb39a928 100644 --- a/src/sensor/gnunet_sensor_model_plugin.h +++ b/src/sensor/gnunet_sensor_model_plugin.h @@ -57,6 +57,24 @@ struct GNUNET_SENSOR_ModelFunctions void * (*create_model) (void *cls); + /* + * Destroy a model instance + * + * @param cls closure (model state) + */ + void + (*destroy_model) (void *cls); + + /* + * Feed a new value to a model + * + * @param cls closure (model state) + * @param val value to be fed to the model + * @return #GNUNET_YES in case of a detected outlier, #GNUNET_NO otherwise + */ + int + (*feed_model) (void *cls, double val); + }; diff --git a/src/sensor/plugin_sensor_model_gaussian.c b/src/sensor/plugin_sensor_model_gaussian.c index bf2090217..052b1a94a 100644 --- a/src/sensor/plugin_sensor_model_gaussian.c +++ b/src/sensor/plugin_sensor_model_gaussian.c @@ -42,6 +42,16 @@ struct Plugin */ const struct GNUNET_CONFIGURATION_Handle *cfg; + /* + * Number of initial readings to be used for training only + */ + int training_window; + + /* + * Number of standard deviations considered within "normal" + */ + int confidence_interval; + }; /* @@ -55,8 +65,84 @@ struct Model */ struct Plugin *plugin; + /* + * Number of readings so far + */ + int n; + + /* + * Sum of readings + */ + long double sum; + + /* + * Sum square of readings + */ + long double sumsq; + }; +static void +update_sums (struct Model *model, double val) +{ + model->sum += val; + model->sumsq += val * val; + model->n ++; +} + +/* + * Feed a new value to a model + * + * @param cls closure (model state) + * @param val value to be fed to the model + * @return #GNUNET_YES in case of a detected outlier, #GNUNET_NO otherwise + */ +static int +sensor_gaussian_model_feed (void *cls, double val) +{ + struct Model *model = cls; + struct Plugin *plugin = model->plugin; + long double mean; + long double stddev; + long double allowed_variance; + + if (model->n < plugin->training_window) + { + update_sums(model, val); + return GNUNET_NO; + } + mean = model->sum / model->n; + stddev = sqrt( + (model->sumsq - 2 * mean * model->sum + model->n * mean * mean) + / + (model->n - 1) + ); + allowed_variance = (plugin->confidence_interval * stddev); + if ((val < (mean - allowed_variance)) || + (val > (mean + allowed_variance))) + return GNUNET_YES; + return GNUNET_NO; +} + +/* + * Destroy a model instance + * + * @param cls closure (model state) + */ +static void +sensor_gaussian_model_destroy_model (void *cls) +{ + struct Model *model = cls; + + GNUNET_free(model); +} + +/* + * Create a model instance + * + * @param cls closure (plugin state) + * @return model state to be used for later calls + */ static void * sensor_gaussian_model_create_model (void *cls) { @@ -80,14 +166,34 @@ libgnunet_plugin_sensor_model_gaussian_init (void *cls) static struct Plugin plugin; const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct GNUNET_SENSOR_ModelFunctions *api; + unsigned long long num; if (NULL != plugin.cfg) return NULL; /* can only initialize once! */ memset (&plugin, 0, sizeof (struct Plugin)); plugin.cfg = cfg; + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, + "sensor-model-gaussian", "TRAINING_WINDOW", &num)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Missing `TRAINING_WINDOW' value in configuration.\n")); + return NULL; + } + plugin.training_window = (int) num; + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, + "sensor-model-gaussian", "CONFIDENCE_INTERVAL", &num)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Missing `CONFIDENCE_INTERVAL' value in configuration.\n")); + return NULL; + } + plugin.confidence_interval = (int) num; api = GNUNET_new (struct GNUNET_SENSOR_ModelFunctions); api->cls = &plugin; - LOG(GNUNET_ERROR_TYPE_DEBUG, "Guassian model plugin is running\n"); + api->create_model = &sensor_gaussian_model_create_model; + api->destroy_model = &sensor_gaussian_model_destroy_model; + api->feed_model = &sensor_gaussian_model_feed; + LOG(GNUNET_ERROR_TYPE_DEBUG, "Gaussian model plugin is running.\n"); return api; } diff --git a/src/sensor/sensor.conf.in b/src/sensor/sensor.conf.in index 5c023d130..92b49100a 100644 --- a/src/sensor/sensor.conf.in +++ b/src/sensor/sensor.conf.in @@ -6,4 +6,8 @@ HOME = $SERVICEHOME @UNIXONLY@ PORT = 2087 [sensor-analysis] -model = gaussian \ No newline at end of file +model = gaussian + +[sensor-model-gaussian] +TRAINING_WINDOW = 1000 +CONFIDENCE_INTERVAL = 3 \ No newline at end of file