This commit is contained in:
Vincenzo Pio Florio 2024-12-03 20:20:05 +01:00
parent 034c7231ef
commit 767835c62c
3 changed files with 165 additions and 86 deletions

View File

@ -8,7 +8,7 @@
typedef struct { typedef struct {
float mean; float mean;
float standardDeviation; float standardDeviation;
int possibleFaultySensor; bool *possibleFaultySensor;
} Metrics; } Metrics;
typedef struct { typedef struct {

View File

@ -12,9 +12,6 @@ static float **readings;
static int sensorsNumber; static int sensorsNumber;
static int slidingWindowSize; static int slidingWindowSize;
/** /**
* @brief Sets the number of sensors. * @brief Sets the number of sensors.
* *
@ -22,7 +19,8 @@ static int slidingWindowSize;
* *
* @param number The number of sensors to set. * @param number The number of sensors to set.
*/ */
static void setSensorsNumber(int number) { static void setSensorsNumber(int number)
{
sensorsNumber = number; sensorsNumber = number;
} }
@ -33,7 +31,8 @@ static void setSensorsNumber(int number) {
* *
* @param size The desired size of the sliding window. * @param size The desired size of the sliding window.
*/ */
static void setSlidingWindowSize(int size) { static void setSlidingWindowSize(int size)
{
slidingWindowSize = 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. * 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 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 *)); readings = (float **)malloc(numSensors * sizeof(float *));
// Check if memory allocation was successful // Check if memory allocation was successful
if (readings == NULL) { if (readings == NULL)
{
perror("Failed to allocate memory for readings"); perror("Failed to allocate memory for readings");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Allocate memory for each sensor's sliding window of readings // 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)); readings[i] = (float *)calloc(windowSize, sizeof(float));
if (readings[i] == NULL) { if (readings[i] == NULL)
{
perror("Failed to allocate memory for sensor readings"); perror("Failed to allocate memory for sensor readings");
exit(EXIT_FAILURE); 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. * @return true if the main readings array was successfully freed, false otherwise.
*/ */
bool freeReadings() { bool freeReadings()
for (int i = 0; i < sensorsNumber; i++) { {
for (int i = 0; i < sensorsNumber; i++)
{
free(readings[i]); free(readings[i]);
} }
if(readings != NULL){ if (readings != NULL)
{
free(readings); free(readings);
readings = NULL; readings = NULL;
return true; return true;
} }
else{ else
{
return false; return false;
} }
} }
@ -112,7 +119,8 @@ bool freeReadings() {
* @return int The number of sensors. * @return int The number of sensors.
*/ */
// Get the number of sensors // Get the number of sensors
int getSensorsNumber() { int getSensorsNumber()
{
return sensorsNumber; return sensorsNumber;
} }
@ -124,25 +132,29 @@ int getSensorsNumber() {
* @return The size of the sliding window. * @return The size of the sliding window.
*/ */
// Get the sliding window size // Get the sliding window size
int getSlidingWindowSize() { int getSlidingWindowSize()
{
return slidingWindowSize; return slidingWindowSize;
} }
/** /**
* @brief Checks if the sliding window for a given sensor is full. * @brief Checks if the sliding window for a given sensor is full.
* *
* This function iterates through the readings of a specified sensor and * This function iterates through the readings of a specified sensor and
* determines if all entries in the sliding window are non-zero, indicating * determines if all entries in the sliding window are non-zero, indicating
* that the window is full. * that the window is full.
* *
* @param sensorIndex The index of the sensor to check. * @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. * false otherwise.
*/ */
// Control on the fullness of the sliding window // Control on the fullness of the sliding window
bool isFull(int sensorIndex) { bool isFull(int sensorIndex)
for (int i = 0; i < slidingWindowSize; i++) { {
if (readings[sensorIndex][i] == 0) { for (int i = 0; i < slidingWindowSize; i++)
{
if (readings[sensorIndex][i] == 0)
{
return false; return false;
} }
} }
@ -159,10 +171,14 @@ bool isFull(int sensorIndex) {
* @param sensorIndex The index of the sensor to retrieve the reading from. * @param sensorIndex The index of the sensor to retrieve the reading from.
* @return The last reading from the specified sensor. * @return The last reading from the specified sensor.
*/ */
float getLastReading(int sensorIndex) { float getLastReading(int sensorIndex)
if (isFull(sensorIndex)) { {
if (isFull(sensorIndex))
{
return readings[sensorIndex][slidingWindowSize - 1]; return readings[sensorIndex][slidingWindowSize - 1];
} else { }
else
{
return readings[sensorIndex][0]; return readings[sensorIndex][0];
} }
} }
@ -178,18 +194,25 @@ static int lastSensorIndex = -1;
* *
* @param value The new sensor reading to be added. * @param value The new sensor reading to be added.
*/ */
void addReading(float value) { void addReading(float value)
{
lastSensorIndex = (lastSensorIndex + 1) % sensorsNumber; lastSensorIndex = (lastSensorIndex + 1) % sensorsNumber;
int sensorIndex = lastSensorIndex; int sensorIndex = lastSensorIndex;
if (isFull(sensorIndex)) { if (isFull(sensorIndex))
for (int i = 0; i < slidingWindowSize - 1; i++) { {
for (int i = 0; i < slidingWindowSize - 1; i++)
{
readings[sensorIndex][i] = readings[sensorIndex][i + 1]; readings[sensorIndex][i] = readings[sensorIndex][i + 1];
} }
readings[sensorIndex][slidingWindowSize - 1] = value; readings[sensorIndex][slidingWindowSize - 1] = value;
} else { }
for (int i = 0; i < slidingWindowSize; i++) { else
if (readings[sensorIndex][i] == 0) { {
for (int i = 0; i < slidingWindowSize; i++)
{
if (readings[sensorIndex][i] == 0)
{
readings[sensorIndex][i] = value; readings[sensorIndex][i] = value;
break; 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. * @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. * @return The average reading of the specified sensor if the sliding window is full; otherwise, returns 0.
*/ */
float getAverageOnSensor(int sensorIndex) { float getAverageOnSensor(int sensorIndex)
if(isFull(sensorIndex) == false){ {
if (isFull(sensorIndex) == false)
{
printf("The sliding window is not full\n"); printf("The sliding window is not full\n");
return 0; return 0;
} }
else{ else
{
float sum = 0; float sum = 0;
for (int i = 0; i < slidingWindowSize; i++) { for (int i = 0; i < slidingWindowSize; i++)
{
sum += readings[sensorIndex][i]; sum += readings[sensorIndex][i];
} }
return sum / slidingWindowSize; return sum / slidingWindowSize;
@ -229,9 +256,11 @@ float getAverageOnSensor(int sensorIndex) {
* *
* @return The average reading from all sensors as a float. * @return The average reading from all sensors as a float.
*/ */
float getAverageOnAllSensors() { float getAverageOnAllSensors()
{
float sum = 0; float sum = 0;
for (int i = 0; i < sensorsNumber; i++) { for (int i = 0; i < sensorsNumber; i++)
{
sum += getLastReading(i); sum += getLastReading(i);
} }
return sum / sensorsNumber; return sum / sensorsNumber;
@ -249,15 +278,19 @@ float getAverageOnAllSensors() {
* @return The overall average of the sensor readings if all sliding windows are full, * @return The overall average of the sensor readings if all sliding windows are full,
* otherwise returns 0. * otherwise returns 0.
*/ */
float getOverallAverage() { float getOverallAverage()
{
float sum = 0; float sum = 0;
int totalReadings = 0; int totalReadings = 0;
for (int i = 0; i < sensorsNumber; i++) { for (int i = 0; i < sensorsNumber; i++)
if (!isFull(i)) { {
if (!isFull(i))
{
printf("The sliding window for sensor %d is not full\n", i); printf("The sliding window for sensor %d is not full\n", i);
return 0; return 0;
} }
for (int j = 0; j < slidingWindowSize; j++) { for (int j = 0; j < slidingWindowSize; j++)
{
sum += readings[i][j]; sum += readings[i][j];
totalReadings++; totalReadings++;
} }
@ -277,15 +310,19 @@ float getOverallAverage() {
* @param sensorIndex The index of the sensor for which the standard deviation is to be calculated. * @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. * @return The standard deviation of the sensor readings, or 0 if the sliding window is not full.
*/ */
float getStandardDeviationOnSensor(int sensorIndex) { float getStandardDeviationOnSensor(int sensorIndex)
if(isFull(sensorIndex) == false){ {
if (isFull(sensorIndex) == false)
{
printf("The sliding window is not full\n"); printf("The sliding window is not full\n");
return 0; return 0;
} }
else{ else
{
float sum = 0; float sum = 0;
float average = getAverageOnSensor(sensorIndex); 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); sum += pow(readings[sensorIndex][i] - average, 2);
} }
return sqrt(sum / slidingWindowSize); return sqrt(sum / slidingWindowSize);
@ -296,16 +333,18 @@ float getStandardDeviationOnSensor(int sensorIndex) {
* @brief Calculates the standard deviation of the readings from all sensors. * @brief Calculates the standard deviation of the readings from all sensors.
* *
* This function computes the standard deviation of the sensor readings by first * This function computes the standard deviation of the sensor readings by first
* calculating the average of all sensor readings, then summing the squared * calculating the average of all sensor readings, then summing the squared
* differences between each reading and the average, and finally taking the * differences between each reading and the average, and finally taking the
* square root of the average of these squared differences. * square root of the average of these squared differences.
* *
* @return The standard deviation of the sensor readings. * @return The standard deviation of the sensor readings.
*/ */
float getStandardDeviationOnAllSensors() { float getStandardDeviationOnAllSensors()
{
float sum = 0; float sum = 0;
float average = getAverageOnAllSensors(); float average = getAverageOnAllSensors();
for (int i = 0; i < sensorsNumber; i++) { for (int i = 0; i < sensorsNumber; i++)
{
float lastReading = getLastReading(i); float lastReading = getLastReading(i);
sum += pow(lastReading - average, 2); 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 variables `slidingWindowSize` and `sensorsNumber` are assumed to be defined globally.
* @note The 2D array `readings` is assumed to contain the sensor data. * @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 upperThreshold = average + 2.17 * standardDeviation; // 97% confidence interval
float lowerThreshold = average - 2.17 * standardDeviation; // Lower bound for anomaly detection float lowerThreshold = average - 2.17 * standardDeviation; // Lower bound for anomaly detection
outlierCount = 0; outlierCount = 0;
for (int j = 0; j < slidingWindowSize; j++) { 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 i = 0; i < sensorsNumber; i++)
{
if (readings[i][j] > upperThreshold || readings[i][j] < lowerThreshold)
{
outlierCount++; 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. * @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; float sum = 0;
int totalReadings = 0; int totalReadings = 0;
float totalAverage = getOverallAverage(); float totalAverage = getOverallAverage();
for (int i = 0; i < sensorsNumber; i++) { for (int i = 0; i < sensorsNumber; i++)
if (!isFull(i)) { {
if (!isFull(i))
{
printf("The sliding window for sensor %d is not full\n", i); printf("The sliding window for sensor %d is not full\n", i);
return 0; return 0;
} }
for (int j = 0; j < slidingWindowSize; j++) { for (int j = 0; j < slidingWindowSize; j++)
{
sum += pow(readings[i][j] - getOverallAverage(), 2); sum += pow(readings[i][j] - getOverallAverage(), 2);
totalReadings++; totalReadings++;
} }
@ -383,58 +429,71 @@ float getOverallStandardDeviation() {
* *
* @return The number of outliers. * @return The number of outliers.
*/ */
int getOutlierCount() { int getOutlierCount()
{
return outlierCount; return outlierCount;
} }
Metrics getMetrics(float **readings, int sensorNumber, int slidingWindow){ Metrics getMetrics(float **readings, int sensorNumber, int slidingWindow)
{
Metrics metrics; Metrics metrics;
int average = 0; float average = 0;
int standardDeviation = 0; float standardDeviation = 0;
int outlierCount = 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; faultySensors[i] = 0;
possiblyFaultySensors[i] = false;
} }
float sum = 0; 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]; sum += readings[i][j];
} }
} }
average = sum / (sensorNumber * slidingWindow); 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 += pow(readings[i][j] - average, 2);
} }
} }
standardDeviation = sqrt(standardDeviation / (sensorNumber * slidingWindow)); standardDeviation = sqrt(standardDeviation / (sensorNumber * slidingWindow));
for(int i = 0; i < sensorNumber; i++){ for (int j = 0; j < slidingWindow; j++)
for(int j = 0; j < slidingWindow; j++){ {
if(readings[i][j] > average + 2.17 * standardDeviation || readings[i][j] < average - 2.17 * standardDeviation){ for (int i = 0; i < sensorNumber; i++)
{
if (readings[i][j] > average + 2.17 * standardDeviation || readings[i][j] < average - 2.17 * standardDeviation)
{
outlierCount++; outlierCount++;
faultySensors[i]++; faultySensors[i]++;
} }
} }
} }
int max = 0; for (int i = 0; i < sensorNumber; i++)
for(int i = 0; i < sensorNumber; i++){ {
if(faultySensors[i] > max){ if (faultySensors[i] >= 0.001 * slidingWindow)
max = faultySensors[i]; {
possiblyFaultySensors[i] = true;
} }
} }
metrics.mean = average; metrics.mean = average;
metrics.standardDeviation = standardDeviation; metrics.standardDeviation = standardDeviation;
metrics.possibleFaultySensor = max; metrics.possibleFaultySensor = possiblyFaultySensors;
free(faultySensors);
return metrics; return metrics;
} }

View File

@ -429,22 +429,42 @@ void test_getMetrics()
// initialize a matrix of readings // initialize a matrix of readings
float **readings = (float **)malloc(NUMBER_OF_SENSORS * sizeof(float *)); 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)); readings[sensor] = (float *)malloc(10000 * sizeof(float));
for (int j = 0; j < SLIDING_WINDOW_SIZE; j++) }
// 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 // add a broken sensor
Metrics metrics = getMetrics(readings, NUMBER_OF_SENSORS, SLIDING_WINDOW_SIZE); 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("Mean: %f\n", metrics.mean);
printf("Standard Deviation: %f\n", metrics.standardDeviation); 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]);
}
} }