embeddedLibrary/test/test_dataAcquisition.c
2024-12-03 20:20:05 +01:00

512 lines
21 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "../include/dataAcquisition.h"
#define TEST_NUMBER 18
#define NUMBER_OF_SENSORS 5
#define SLIDING_WINDOW_SIZE 10
#define AVERAGE_UNCERTAINTY 0.01
#define STD_UNCERTAINTY 0.01
#define M_PI 3.14159265358979323846
#define NORMAL_DISTRIBUTION_MEAN 10.0
#define NORMAL_DISTRIBUTION_STDDEV 2.0
/**
* @brief Test function to verify the initialization of sensor readings.
*
* This function tests the `initializeReadings` function by initializing the
* readings with a specified number of sensors and sliding window size. It then
* asserts that the number of sensors and the sliding window size are correctly
* set.
*
* @note This test assumes that the constants `NUMBER_OF_SENSORS` and
* `SLIDING_WINDOW_SIZE` are defined elsewhere in the code.
*/
void test_initializeReadings_uniform()
{
initializeReadings(NUMBER_OF_SENSORS, 100);
assert(getSensorsNumber() == NUMBER_OF_SENSORS);
assert(getSlidingWindowSize() == SLIDING_WINDOW_SIZE);
}
/**
* @brief Test function to add uniform readings to all sensors and verify if the last sensor's buffer is full.
*
* This function iterates through a range of values from 1 to SLIDING_WINDOW_SIZE and adds each value to all sensors.
* After adding the readings, it asserts that the buffer for the last sensor (NUMBER_OF_SENSORS - 1) is full.
*
* @note Assumes that the addReading function adds a reading to all sensors and that the isFull function checks if a sensor's buffer is full.
*/
void test_addReading_uniform()
{
for (int value = 1; value <= SLIDING_WINDOW_SIZE; value++)
{
for (int sensor = 0; sensor < NUMBER_OF_SENSORS; sensor++)
{
addReading(value);
}
}
assert(isFull(NUMBER_OF_SENSORS - 1) == true); // Assuming the last sensor acquired the data
}
/**
* @brief Test function to verify the average calculation on a sensor with uniform data.
*
* This function tests the `getAverageOnSensor` function by calculating the average
* value on the last sensor (NUMBER_OF_SENSORS - 1) and comparing it to the expected
* average value. The expected average is calculated as (SLIDING_WINDOW_SIZE + 1) / 2.0.
* The test asserts that the difference between the calculated average and the expected
* average is within the defined AVERAGE_UNCERTAINTY.
*/
void test_averageOnSensor_uniform()
{
//printf("Average on sensor %d: %f\n", NUMBER_OF_SENSORS - 1, getAverageOnSensor(NUMBER_OF_SENSORS - 1));
float average = getAverageOnSensor(NUMBER_OF_SENSORS - 1);
float expected_average = (SLIDING_WINDOW_SIZE + 1) / 2.0;
assert(fabs(average - expected_average) < AVERAGE_UNCERTAINTY);
}
/**
* @brief Test the standard deviation calculation on the last sensor with uniform data.
*
* This function tests the standard deviation calculation for the last sensor
* in the array of sensors. It compares the calculated standard deviation with
* an expected value to ensure the accuracy of the standard deviation function.
*
* The test uses the following steps:
* 1. Calculate the standard deviation for the last sensor.
* 2. Define the expected standard deviation value.
* 3. Assert that the difference between the calculated and expected values is
* within an acceptable uncertainty range (STD_UNCERTAINTY).
*
* @note The expected standard deviation value is hardcoded as 2.872281323269.
*/
void test_standardDeviationOnSensor_uniform()
{
//printf("Standard deviation on sensor %d: %f\n", NUMBER_OF_SENSORS - 1, getStandardDeviationOnSensor(NUMBER_OF_SENSORS - 1));
float standard_deviation = getStandardDeviationOnSensor(NUMBER_OF_SENSORS - 1);
float expected_standard_deviation = 2.872281323269;
assert(fabs(standard_deviation - expected_standard_deviation) < STD_UNCERTAINTY);
}
/**
* @brief Test function to verify the average calculation on all sensors when the values are uniform.
*
* This function calculates the average value from all sensors using the `getAverageOnAllSensors` function
* and compares it to the expected average value, which is defined by `SLIDING_WINDOW_SIZE`.
* The test asserts that the difference between the calculated average and the expected average
* is within the acceptable uncertainty range defined by `AVERAGE_UNCERTAINTY`.
*/
void test_averageOnAllSensors_uniform()
{
//printf("Average on all sensors: %f\n", getAverageOnAllSensors());
float average = getAverageOnAllSensors();
float expected_average = SLIDING_WINDOW_SIZE;
assert(fabs(average - expected_average) < AVERAGE_UNCERTAINTY);
}
/**
* @brief Test the standard deviation calculation on all sensors with uniform data.
*
* This function tests the `getStandardDeviationOnAllSensors` function by comparing
* the calculated standard deviation with the expected value of 0. The test assumes
* that all sensors have uniform data, resulting in a standard deviation of 0.
*
* The test passes if the absolute difference between the calculated standard deviation
* and the expected standard deviation is less than the defined uncertainty (`STD_UNCERTAINTY`).
*
* @note The `printf` statement is commented out and can be used for debugging purposes
* to print the calculated standard deviation.
*/
void test_standardDeviationOnAllSensors_uniform()
{
//printf("Standard deviation on all sensors: %f\n", getStandardDeviationOnAllSensors());
float standard_deviation = getStandardDeviationOnAllSensors();
float expected_standard_deviation = 0;
assert(fabs(standard_deviation - expected_standard_deviation) < STD_UNCERTAINTY);
}
/**
* @brief Test the overall average calculation with uniform sensor data.
*
* This function tests the `getOverallAverage` function by comparing the
* calculated average with the expected average value when all sensors
* have uniform data. The expected overall average is calculated as
* (SLIDING_WINDOW_SIZE + 1) / 2.0. The test asserts that the difference
* between the calculated average and the expected average is within
* the defined uncertainty (AVERAGE_UNCERTAINTY).
*/
void test_overallAverage_uniform()
{
//printf("Overall average on all sensors: %f\n", getOverallAverage());
float average = getOverallAverage();
float expected_overall_average = (SLIDING_WINDOW_SIZE + 1) / 2.0;
assert(fabs(average - expected_overall_average) < AVERAGE_UNCERTAINTY);
}
/**
* @brief Test the overall standard deviation for uniform distribution.
*
* This function tests the standard deviation calculation for the last sensor
* in a uniform distribution scenario. It compares the calculated standard
* deviation with the expected value and asserts that the difference is within
* an acceptable uncertainty range.
*
* @note The expected standard deviation value is hardcoded as 2.872281323269.
* The acceptable uncertainty range is defined by the macro STD_UNCERTAINTY.
*/
void test_overallStandardDeviation_uniform()
{
//printf("Overall standard deviation: %f\n", getOverallStandardDeviation());
float standard_deviation = getStandardDeviationOnSensor(NUMBER_OF_SENSORS - 1);
float expected_standard_deviation = 2.872281323269;
assert(fabs(standard_deviation - expected_standard_deviation) < STD_UNCERTAINTY);
}
/**
* @brief Test function for anomaly detection with uniform data.
*
* This function tests the anomaly detection mechanism by:
* 1. Calculating the overall average and standard deviation of the data.
* 2. Detecting anomalies based on the calculated average and standard deviation.
* 3. Asserting that the initial outlier count is zero.
* 4. Adding an outlier to the data.
* 5. Recalculating the overall average and standard deviation.
* 6. Detecting anomalies again with the updated data.
* 7. Asserting that the outlier count is one after adding the outlier.
*
* The function uses the following helper functions:
* - getOverallAverage(): Returns the overall average of the data.
* - getOverallStandardDeviation(): Returns the overall standard deviation of the data.
* - anomalyDetect(float average, float standard_deviation): Detects anomalies based on the provided average and standard deviation.
* - getOutlierCount(): Returns the current count of outliers detected.
* - addReading(float value): Adds a new reading to the data set.
*
* The assertions use a tolerance of 0.01 to account for floating-point precision errors.
*/
void test_anomalyDetect_uniform()
{
float average = getOverallAverage();
float standard_deviation = getOverallStandardDeviation();
anomalyDetect(average, standard_deviation);
//printf("Outlier count: %i\n", getOutlierCount());
assert(fabs(getOutlierCount() - 0) < 0.01);
// Adding an outlier
addReading(20);
average = getOverallAverage();
standard_deviation = getOverallStandardDeviation();
anomalyDetect(average, standard_deviation);
//printf("Outlier count: %i\n", getOutlierCount());
assert(fabs(getOutlierCount() - 1) < 0.01);
}
/**
* @brief Unit test for the freeReadings function.
*
* This function tests the freeReadings function to ensure it correctly
* frees the allocated memory and returns true upon successful execution.
*
* @note This test uses the assert function to verify the expected behavior.
*/
void test_freeReadings()
{
assert(freeReadings() == true);
}
// TODO: Test all the functions with a normal distribution
// TODO: Evaluate the normal distribution with the anomaly detection
/**
* @brief Test the initialization of sensor readings with normal parameters.
*
* This function tests the `initializeReadings` function by initializing the readings
* with a specified number of sensors and sliding window size. It then asserts that
* the number of sensors and the sliding window size are correctly set.
*
* @note This test assumes that the constants `NUMBER_OF_SENSORS` and `SLIDING_WINDOW_SIZE`
* are defined elsewhere in the code.
*/
void test_initializeReadings_normal()
{
initializeReadings(NUMBER_OF_SENSORS, 100);
assert(getSensorsNumber() == NUMBER_OF_SENSORS);
assert(getSlidingWindowSize() == SLIDING_WINDOW_SIZE);
}
/**
* @brief Test function to add readings to the data acquisition system.
*
* This function simulates adding readings to the data acquisition system
* for all sensors over a sliding window. It generates random values
* following a normal distribution with a specified mean and standard
* deviation, and adds these values as readings for each sensor.
*
* The function then asserts that the data acquisition system is full
* for the last sensor, indicating that readings have been successfully
* added for all sensors.
*
* @note This test assumes that the last sensor (NUMBER_OF_SENSORS - 1)
* has acquired the data.
*/
void test_addReading_normal()
{
for (int i = 0; i < SLIDING_WINDOW_SIZE; i++)
{
for (int sensor = 0; sensor < NUMBER_OF_SENSORS; sensor++)
{
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);
float value = NORMAL_DISTRIBUTION_MEAN + z0 * NORMAL_DISTRIBUTION_STDDEV;
addReading(value);
}
}
assert(isFull(NUMBER_OF_SENSORS - 1) == true); // Assuming the last sensor acquired the data
}
/**
* @brief Test the average value on a sensor under normal conditions.
*
* This function calculates the average value on the last sensor (NUMBER_OF_SENSORS - 1)
* and asserts that the difference between the calculated average and the expected mean
* (NORMAL_DISTRIBUTION_MEAN) is within an acceptable range defined by AVERAGE_UNCERTAINTY * 50.
*
* The test ensures that the average value on the sensor is within the expected range,
* indicating that the sensor data acquisition is functioning correctly under normal conditions.
*/
void test_averageOnSensor_normal()
{
//printf("Average on sensor %d: %f\n", NUMBER_OF_SENSORS - 1, getAverageOnSensor(NUMBER_OF_SENSORS - 1));
float average = getAverageOnSensor(NUMBER_OF_SENSORS - 1);
assert(fabs(average - NORMAL_DISTRIBUTION_MEAN) < AVERAGE_UNCERTAINTY * 50);
}
/**
* @brief Tests the standard deviation calculation on the last sensor.
*
* This function calculates the standard deviation for the last sensor
* and asserts that the calculated value is within an acceptable range
* of the expected standard deviation for a normal distribution.
*
* The acceptable range is defined as the expected standard deviation
* (NORMAL_DISTRIBUTION_STDDEV) plus or minus a tolerance (STD_UNCERTAINTY * 100).
*
* @note This test assumes that the sensor data follows a normal distribution.
*/
void test_standardDeviationOnSensor_normal()
{
//printf("Standard deviation on sensor %d: %f\n", NUMBER_OF_SENSORS - 1, getStandardDeviationOnSensor(NUMBER_OF_SENSORS - 1));
float standard_deviation = getStandardDeviationOnSensor(NUMBER_OF_SENSORS - 1);
assert(fabs(standard_deviation - NORMAL_DISTRIBUTION_STDDEV) < STD_UNCERTAINTY * 100);
}
/**
* @brief Test the average value calculation on all sensors under normal conditions.
*
* This function tests the `getAverageOnAllSensors` function to ensure that the
* average value calculated from all sensors is within an acceptable range of
* the expected normal distribution mean. The acceptable range is defined by
* `AVERAGE_UNCERTAINTY` multiplied by 100.
*
* The test asserts that the absolute difference between the calculated average
* and the expected normal distribution mean (`NORMAL_DISTRIBUTION_MEAN`) is
* less than the specified uncertainty range.
*/
void test_averageOnAllSensors_normal()
{
//printf("Average on all sensors: %f\n", getAverageOnAllSensors());
float average = getAverageOnAllSensors();
assert(fabs(average - NORMAL_DISTRIBUTION_MEAN) < AVERAGE_UNCERTAINTY * 100);
}
/**
* @brief Test the standard deviation calculation on all sensors under normal conditions.
*
* This function tests the `getStandardDeviationOnAllSensors` function to ensure that the
* calculated standard deviation is within an acceptable range of the expected normal
* distribution standard deviation. The test asserts that the absolute difference between
* the calculated standard deviation and the expected normal distribution standard deviation
* is less than a specified uncertainty threshold.
*
* @note The expected normal distribution standard deviation is defined by the macro
* `NORMAL_DISTRIBUTION_STDDEV`, and the acceptable uncertainty is defined by the macro
* `STD_UNCERTAINTY`.
*/
void test_standardDeviationOnAllSensors_normal()
{
//printf("Standard deviation on all sensors: %f\n", getStandardDeviationOnAllSensors());
float standard_deviation = getStandardDeviationOnAllSensors();
assert(fabs(standard_deviation - NORMAL_DISTRIBUTION_STDDEV) < STD_UNCERTAINTY * 100);
}
/**
* @brief Test the overall average calculation under normal conditions.
*
* This function tests the `getOverallAverage` function to ensure that the
* calculated average of all sensors is within an acceptable range of the
* expected normal distribution mean. The test asserts that the difference
* between the calculated average and the expected mean is less than a
* specified uncertainty threshold.
*
* @note The test uses the `fabs` function to compute the absolute difference
* between the calculated average and the expected mean.
*/
void test_overallAverage_normal()
{
//printf("Overall average on all sensors: %f\n", getOverallAverage());
float average = getOverallAverage();
assert(fabs(average - NORMAL_DISTRIBUTION_MEAN) < AVERAGE_UNCERTAINTY * 100);
}
/**
* @brief Test the overall standard deviation for normal distribution.
*
* This function tests the standard deviation calculation for the last sensor
* in the array of sensors. It compares the calculated standard deviation
* with the expected standard deviation for a normal distribution.
*
* The test passes if the absolute difference between the calculated standard
* deviation and the expected standard deviation is less than the product of
* the standard uncertainty and 100.
*
* @note The function `getStandardDeviationOnSensor` is used to get the
* standard deviation for a specific sensor.
*
* @see getStandardDeviationOnSensor
*/
void test_overallStandardDeviation_normal()
{
//printf("Overall standard deviation: %f\n", getOverallStandardDeviation());
float standard_deviation = getStandardDeviationOnSensor(NUMBER_OF_SENSORS - 1);
assert(fabs(standard_deviation - NORMAL_DISTRIBUTION_STDDEV) < STD_UNCERTAINTY * 100);
}
/**
* @brief Tests the anomaly detection function under normal conditions.
*
* This function performs the following steps:
* 1. Calculates the overall average and standard deviation of the data.
* 2. Calls the anomaly detection function with the calculated average and standard deviation.
* 3. Asserts that the number of detected outliers is within the expected range (assuming 5% of the data is outliers).
* 4. Adds an outlier to the data.
* 5. Recalculates the overall average and standard deviation.
* 6. Calls the anomaly detection function again with the new average and standard deviation.
* 7. Asserts that the number of detected outliers has increased by one.
*
* The test assumes that the number of sensors and the sliding window size are defined by the constants
* NUMBER_OF_SENSORS and SLIDING_WINDOW_SIZE, respectively. It also assumes that the normal distribution
* mean is defined by the constant NORMAL_DISTRIBUTION_MEAN.
*/
void test_anomalyDetect_normal()
{
float average = getOverallAverage();
float standard_deviation = getOverallStandardDeviation();
anomalyDetect(average, standard_deviation);
//printf("Outlier count: %i\n", getOutlierCount());
assert(fabs(NUMBER_OF_SENSORS * SLIDING_WINDOW_SIZE * 0.05 >= getOutlierCount())); // Assuming 5% of the data is outliers
// Adding an outlier
addReading(NORMAL_DISTRIBUTION_MEAN * 100);
average = getOverallAverage();
standard_deviation = getOverallStandardDeviation();
anomalyDetect(average, standard_deviation);
//printf("Outlier count: %i\n", getOutlierCount());
assert(fabs(NUMBER_OF_SENSORS * SLIDING_WINDOW_SIZE * 0.05 + 1 >= getOutlierCount())); // Assuming 5% of the data is outliers and adding one more
}
void test_getMetrics()
{
// initialize a matrix of readings
float **readings = (float **)malloc(NUMBER_OF_SENSORS * sizeof(float *));
for (int sensor = 0; sensor < NUMBER_OF_SENSORS; sensor++)
{
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++)
{
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;
}
}
// add a broken sensor
for (int i = 0; i < 100; i++)
{
readings[0][i] = 1000;
}
// 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);
// print the faulty sensors
printf("Possible faulty sensors: ");
for (int i = 0; i < NUMBER_OF_SENSORS; i++)
{
printf("%d ", metrics.possibleFaultySensor[i]);
}
}
int main() {
int tests_run = 0;
int tests_passed = 0;
printf("=== Test Suite ===\n");
#define RUN_TEST(test) do { \
printf("Progress: %.2f%%, Running %s...", (tests_run / (float)TEST_NUMBER) * 100, #test); \
test(); \
tests_run++; \
tests_passed++; \
printf("OK\n"); \
} while(0)
srand(42);
RUN_TEST(test_initializeReadings_uniform);
RUN_TEST(test_addReading_uniform);
RUN_TEST(test_averageOnSensor_uniform);
RUN_TEST(test_standardDeviationOnSensor_uniform);
RUN_TEST(test_averageOnAllSensors_uniform);
RUN_TEST(test_standardDeviationOnAllSensors_uniform);
RUN_TEST(test_overallAverage_uniform);
RUN_TEST(test_overallStandardDeviation_uniform);
RUN_TEST(test_anomalyDetect_uniform);
RUN_TEST(test_addReading_normal);
RUN_TEST(test_averageOnSensor_normal);
RUN_TEST(test_standardDeviationOnSensor_normal);
RUN_TEST(test_averageOnAllSensors_normal);
RUN_TEST(test_standardDeviationOnAllSensors_normal);
RUN_TEST(test_overallAverage_normal);
RUN_TEST(test_overallStandardDeviation_normal);
RUN_TEST(test_anomalyDetect_normal);
RUN_TEST(test_freeReadings);
RUN_TEST(test_getMetrics);
printf("\n=== Results ===\n");
printf("Tests run: %d\n", tests_run);
printf("Tests passed: %d\n", tests_passed);
printf("Test coverage: %.2f%%\n", (tests_passed / (float)tests_run) * 100);
return 0;
}