From 767835c62cfc891980832dbfa0d170e8b4e79f91 Mon Sep 17 00:00:00 2001 From: mrheltic Date: Tue, 3 Dec 2024 20:20:05 +0100 Subject: [PATCH] Hotfixes --- include/dataAcquisition.h | 2 +- libraries/dataAcquisition.c | 213 +++++++++++++++++++++++------------- test/test_dataAcquisition.c | 36 ++++-- 3 files changed, 165 insertions(+), 86 deletions(-) diff --git a/include/dataAcquisition.h b/include/dataAcquisition.h index 0c91fbe..be5595c 100644 --- a/include/dataAcquisition.h +++ b/include/dataAcquisition.h @@ -8,7 +8,7 @@ typedef struct { float mean; float standardDeviation; - int possibleFaultySensor; + bool *possibleFaultySensor; } Metrics; typedef struct { diff --git a/libraries/dataAcquisition.c b/libraries/dataAcquisition.c index c3cb26d..ae9d0da 100644 --- a/libraries/dataAcquisition.c +++ b/libraries/dataAcquisition.c @@ -12,9 +12,6 @@ static float **readings; static int sensorsNumber; static int slidingWindowSize; - - - /** * @brief Sets the number of sensors. * @@ -22,7 +19,8 @@ static int slidingWindowSize; * * @param number The number of sensors to set. */ -static void setSensorsNumber(int number) { +static void setSensorsNumber(int number) +{ sensorsNumber = number; } @@ -33,7 +31,8 @@ static void setSensorsNumber(int number) { * * @param size The desired size of the sliding window. */ -static void setSlidingWindowSize(int size) { +static void setSlidingWindowSize(int size) +{ slidingWindowSize = size; } @@ -53,7 +52,8 @@ static void setSlidingWindowSize(int size) { * * If memory allocation fails at any point, the function prints an error message and exits the program. */ -void initializeReadings(int numSensors, float deltaTime) { +void initializeReadings(int numSensors, float deltaTime) +{ int windowSize = (int)(1000 / deltaTime); // Standard case of 1 second of acquisition @@ -61,15 +61,18 @@ void initializeReadings(int numSensors, float deltaTime) { readings = (float **)malloc(numSensors * sizeof(float *)); // Check if memory allocation was successful - if (readings == NULL) { + if (readings == NULL) + { perror("Failed to allocate memory for readings"); exit(EXIT_FAILURE); } // Allocate memory for each sensor's sliding window of readings - for (int i = 0; i < numSensors; i++) { + for (int i = 0; i < numSensors; i++) + { readings[i] = (float *)calloc(windowSize, sizeof(float)); - if (readings[i] == NULL) { + if (readings[i] == NULL) + { perror("Failed to allocate memory for sensor readings"); exit(EXIT_FAILURE); } @@ -89,17 +92,21 @@ void initializeReadings(int numSensors, float deltaTime) { * * @return true if the main readings array was successfully freed, false otherwise. */ -bool freeReadings() { - for (int i = 0; i < sensorsNumber; i++) { +bool freeReadings() +{ + for (int i = 0; i < sensorsNumber; i++) + { free(readings[i]); } - - if(readings != NULL){ + + if (readings != NULL) + { free(readings); readings = NULL; return true; } - else{ + else + { return false; } } @@ -112,7 +119,8 @@ bool freeReadings() { * @return int The number of sensors. */ // Get the number of sensors -int getSensorsNumber() { +int getSensorsNumber() +{ return sensorsNumber; } @@ -124,25 +132,29 @@ int getSensorsNumber() { * @return The size of the sliding window. */ // Get the sliding window size -int getSlidingWindowSize() { +int getSlidingWindowSize() +{ return slidingWindowSize; } /** * @brief Checks if the sliding window for a given sensor is full. * - * This function iterates through the readings of a specified sensor and - * determines if all entries in the sliding window are non-zero, indicating + * This function iterates through the readings of a specified sensor and + * determines if all entries in the sliding window are non-zero, indicating * that the window is full. * * @param sensorIndex The index of the sensor to check. - * @return true if the sliding window is full (all entries are non-zero), + * @return true if the sliding window is full (all entries are non-zero), * false otherwise. */ // Control on the fullness of the sliding window -bool isFull(int sensorIndex) { - for (int i = 0; i < slidingWindowSize; i++) { - if (readings[sensorIndex][i] == 0) { +bool isFull(int sensorIndex) +{ + for (int i = 0; i < slidingWindowSize; i++) + { + if (readings[sensorIndex][i] == 0) + { return false; } } @@ -159,10 +171,14 @@ bool isFull(int sensorIndex) { * @param sensorIndex The index of the sensor to retrieve the reading from. * @return The last reading from the specified sensor. */ -float getLastReading(int sensorIndex) { - if (isFull(sensorIndex)) { +float getLastReading(int sensorIndex) +{ + if (isFull(sensorIndex)) + { return readings[sensorIndex][slidingWindowSize - 1]; - } else { + } + else + { return readings[sensorIndex][0]; } } @@ -178,18 +194,25 @@ static int lastSensorIndex = -1; * * @param value The new sensor reading to be added. */ -void addReading(float value) { +void addReading(float value) +{ lastSensorIndex = (lastSensorIndex + 1) % sensorsNumber; int sensorIndex = lastSensorIndex; - if (isFull(sensorIndex)) { - for (int i = 0; i < slidingWindowSize - 1; i++) { + if (isFull(sensorIndex)) + { + for (int i = 0; i < slidingWindowSize - 1; i++) + { readings[sensorIndex][i] = readings[sensorIndex][i + 1]; } readings[sensorIndex][slidingWindowSize - 1] = value; - } else { - for (int i = 0; i < slidingWindowSize; i++) { - if (readings[sensorIndex][i] == 0) { + } + else + { + for (int i = 0; i < slidingWindowSize; i++) + { + if (readings[sensorIndex][i] == 0) + { readings[sensorIndex][i] = value; break; } @@ -207,14 +230,18 @@ void addReading(float value) { * @param sensorIndex The index of the sensor for which the average reading is to be calculated. * @return The average reading of the specified sensor if the sliding window is full; otherwise, returns 0. */ -float getAverageOnSensor(int sensorIndex) { - if(isFull(sensorIndex) == false){ +float getAverageOnSensor(int sensorIndex) +{ + if (isFull(sensorIndex) == false) + { printf("The sliding window is not full\n"); return 0; } - else{ + else + { float sum = 0; - for (int i = 0; i < slidingWindowSize; i++) { + for (int i = 0; i < slidingWindowSize; i++) + { sum += readings[sensorIndex][i]; } return sum / slidingWindowSize; @@ -229,9 +256,11 @@ float getAverageOnSensor(int sensorIndex) { * * @return The average reading from all sensors as a float. */ -float getAverageOnAllSensors() { +float getAverageOnAllSensors() +{ float sum = 0; - for (int i = 0; i < sensorsNumber; i++) { + for (int i = 0; i < sensorsNumber; i++) + { sum += getLastReading(i); } return sum / sensorsNumber; @@ -249,15 +278,19 @@ float getAverageOnAllSensors() { * @return The overall average of the sensor readings if all sliding windows are full, * otherwise returns 0. */ -float getOverallAverage() { +float getOverallAverage() +{ float sum = 0; int totalReadings = 0; - for (int i = 0; i < sensorsNumber; i++) { - if (!isFull(i)) { + for (int i = 0; i < sensorsNumber; i++) + { + if (!isFull(i)) + { printf("The sliding window for sensor %d is not full\n", i); return 0; } - for (int j = 0; j < slidingWindowSize; j++) { + for (int j = 0; j < slidingWindowSize; j++) + { sum += readings[i][j]; totalReadings++; } @@ -277,15 +310,19 @@ float getOverallAverage() { * @param sensorIndex The index of the sensor for which the standard deviation is to be calculated. * @return The standard deviation of the sensor readings, or 0 if the sliding window is not full. */ -float getStandardDeviationOnSensor(int sensorIndex) { - if(isFull(sensorIndex) == false){ +float getStandardDeviationOnSensor(int sensorIndex) +{ + if (isFull(sensorIndex) == false) + { printf("The sliding window is not full\n"); return 0; } - else{ + else + { float sum = 0; float average = getAverageOnSensor(sensorIndex); - for (int i = 0; i < slidingWindowSize; i++) { + for (int i = 0; i < slidingWindowSize; i++) + { sum += pow(readings[sensorIndex][i] - average, 2); } return sqrt(sum / slidingWindowSize); @@ -296,16 +333,18 @@ float getStandardDeviationOnSensor(int sensorIndex) { * @brief Calculates the standard deviation of the readings from all sensors. * * This function computes the standard deviation of the sensor readings by first - * calculating the average of all sensor readings, then summing the squared - * differences between each reading and the average, and finally taking the + * calculating the average of all sensor readings, then summing the squared + * differences between each reading and the average, and finally taking the * square root of the average of these squared differences. * * @return The standard deviation of the sensor readings. */ -float getStandardDeviationOnAllSensors() { +float getStandardDeviationOnAllSensors() +{ float sum = 0; float average = getAverageOnAllSensors(); - for (int i = 0; i < sensorsNumber; i++) { + for (int i = 0; i < sensorsNumber; i++) + { float lastReading = getLastReading(i); sum += pow(lastReading - average, 2); } @@ -328,18 +367,21 @@ float getStandardDeviationOnAllSensors() { * @note The variables `slidingWindowSize` and `sensorsNumber` are assumed to be defined globally. * @note The 2D array `readings` is assumed to contain the sensor data. */ -void anomalyDetect(float average, float standardDeviation) { +void anomalyDetect(float average, float standardDeviation) +{ float upperThreshold = average + 2.17 * standardDeviation; // 97% confidence interval float lowerThreshold = average - 2.17 * standardDeviation; // Lower bound for anomaly detection outlierCount = 0; - for (int j = 0; j < slidingWindowSize; j++) { - for (int i = 0; i < sensorsNumber; i++) { - if (readings[i][j] > upperThreshold || readings[i][j] < lowerThreshold) { + for (int j = 0; j < slidingWindowSize; j++) + { + for (int i = 0; i < sensorsNumber; i++) + { + if (readings[i][j] > upperThreshold || readings[i][j] < lowerThreshold) + { outlierCount++; } } } - } /** @@ -353,16 +395,20 @@ void anomalyDetect(float average, float standardDeviation) { * * @return The overall standard deviation of the sensor readings. Returns 0 if any sensor's sliding window is not full. */ -float getOverallStandardDeviation() { +float getOverallStandardDeviation() +{ float sum = 0; int totalReadings = 0; float totalAverage = getOverallAverage(); - for (int i = 0; i < sensorsNumber; i++) { - if (!isFull(i)) { + for (int i = 0; i < sensorsNumber; i++) + { + if (!isFull(i)) + { printf("The sliding window for sensor %d is not full\n", i); return 0; } - for (int j = 0; j < slidingWindowSize; j++) { + for (int j = 0; j < slidingWindowSize; j++) + { sum += pow(readings[i][j] - getOverallAverage(), 2); totalReadings++; } @@ -383,58 +429,71 @@ float getOverallStandardDeviation() { * * @return The number of outliers. */ -int getOutlierCount() { +int getOutlierCount() +{ return outlierCount; } -Metrics getMetrics(float **readings, int sensorNumber, int slidingWindow){ +Metrics getMetrics(float **readings, int sensorNumber, int slidingWindow) +{ Metrics metrics; - int average = 0; - int standardDeviation = 0; + float average = 0; + float standardDeviation = 0; int outlierCount = 0; - int* faultySensors = (int*)malloc(sensorNumber * sizeof(int)); + int *faultySensors = (int *)malloc(sensorNumber * sizeof(int)); + bool *possiblyFaultySensors = (bool *)malloc(sensorNumber * sizeof(bool)); - for(int i = 0; i < sensorNumber; i++){ + for (int i = 0; i < sensorNumber; i++) + { faultySensors[i] = 0; + possiblyFaultySensors[i] = false; } float sum = 0; - for(int i = 0; i < sensorNumber; i++){ - for(int j = 0; j < slidingWindow; j++){ + for (int j = 0; j < slidingWindow; j++) + { + for (int i = 0; i < sensorNumber; i++) + { sum += readings[i][j]; } } average = sum / (sensorNumber * slidingWindow); - for(int i = 0; i < sensorNumber; i++){ - for(int j = 0; j < slidingWindow; j++){ + for (int j = 0; j < slidingWindow; j++) + { + for (int i = 0; i < sensorNumber; i++) + { standardDeviation += pow(readings[i][j] - average, 2); } } standardDeviation = sqrt(standardDeviation / (sensorNumber * slidingWindow)); - for(int i = 0; i < sensorNumber; i++){ - for(int j = 0; j < slidingWindow; j++){ - if(readings[i][j] > average + 2.17 * standardDeviation || readings[i][j] < average - 2.17 * standardDeviation){ + for (int j = 0; j < slidingWindow; j++) + { + for (int i = 0; i < sensorNumber; i++) + { + if (readings[i][j] > average + 2.17 * standardDeviation || readings[i][j] < average - 2.17 * standardDeviation) + { outlierCount++; faultySensors[i]++; } } } - int max = 0; - for(int i = 0; i < sensorNumber; i++){ - if(faultySensors[i] > max){ - max = faultySensors[i]; + for (int i = 0; i < sensorNumber; i++) + { + if (faultySensors[i] >= 0.001 * slidingWindow) + { + possiblyFaultySensors[i] = true; } } metrics.mean = average; metrics.standardDeviation = standardDeviation; - metrics.possibleFaultySensor = max; - + metrics.possibleFaultySensor = possiblyFaultySensors; + free(faultySensors); return metrics; } \ No newline at end of file diff --git a/test/test_dataAcquisition.c b/test/test_dataAcquisition.c index 27a677f..486c98c 100644 --- a/test/test_dataAcquisition.c +++ b/test/test_dataAcquisition.c @@ -429,22 +429,42 @@ void test_getMetrics() // initialize a matrix of readings float **readings = (float **)malloc(NUMBER_OF_SENSORS * sizeof(float *)); - for (int i = 0; i < NUMBER_OF_SENSORS; i++) + for (int sensor = 0; sensor < NUMBER_OF_SENSORS; sensor++) { - readings[i] = (float *)malloc(SLIDING_WINDOW_SIZE * sizeof(float)); - for (int j = 0; j < SLIDING_WINDOW_SIZE; j++) + readings[sensor] = (float *)malloc(10000 * sizeof(float)); + } + + // fill the matrix with normal distribution data + for (int i = 0; i < 10000; i++) + { + for (int sensor = 0; sensor < NUMBER_OF_SENSORS; sensor++) { - readings[i][j] = j + 1; + float u1 = (float)rand() / RAND_MAX; + float u2 = (float)rand() / RAND_MAX; + float z0 = sqrt(-2.0 * log(u1)) * cos(2.0 * M_PI * u2); + readings[sensor][i] = NORMAL_DISTRIBUTION_MEAN + z0 * NORMAL_DISTRIBUTION_STDDEV; } } - // get metrics - Metrics metrics = getMetrics(readings, NUMBER_OF_SENSORS, SLIDING_WINDOW_SIZE); + // add a broken sensor + for (int i = 0; i < 100; i++) + { + readings[0][i] = 1000; + } - printf("Metrics:\n"); + // get metrics + Metrics metrics = getMetrics(readings, NUMBER_OF_SENSORS, 10000); + + printf("\nMetrics:\n") ; printf("Mean: %f\n", metrics.mean); printf("Standard Deviation: %f\n", metrics.standardDeviation); - printf("Possible Faulty Sensor: %d\n", metrics.possibleFaultySensor); + + // print the faulty sensors + printf("Possible faulty sensors: "); + for (int i = 0; i < NUMBER_OF_SENSORS; i++) + { + printf("%d ", metrics.possibleFaultySensor[i]); + } }