466 lines
12 KiB
C
466 lines
12 KiB
C
//
|
|
// Created by frederik on 1/11/25.
|
|
//
|
|
|
|
#include "MMS24-25.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <math.h>
|
|
|
|
// Preprocessor Definitions in case they are not defined
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
#ifndef EXIT_FAILURE
|
|
#define EXIT_FAILURE 1
|
|
#endif
|
|
#ifndef NULL
|
|
#define NULL 0
|
|
#endif
|
|
|
|
void info(char* fmt,...) {
|
|
fprintf(stderr, "[\x1B[37;1m INFO \x1B[0m] \x1B[34m'");
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "'\x1B[0m\n");
|
|
}
|
|
|
|
void success(char* fmt,...) {
|
|
fprintf(stderr, "[\x1B[32;1m PASS \x1B[0m] \x1B[34m'");
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "'\x1B[0m\n");
|
|
}
|
|
|
|
void error(const char* fmt, ...) {
|
|
va_list args;
|
|
|
|
fprintf(stderr, "<\x1B[31;1m ERROR \x1B[0m: \x1B[34m'");
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
fprintf(stderr, "'\x1B[0m >\n");
|
|
exit(-1);
|
|
}
|
|
|
|
void testInterpolation() {
|
|
info("testInterpolation");
|
|
|
|
double dRangeMin = -1;
|
|
double dRangeMax = 1;
|
|
double dRangeStep = 0.33;
|
|
|
|
for (double dX1=dRangeMin;dX1<dRangeMax;dX1+=dRangeStep) {
|
|
for (double dX2=dRangeMin;dX2<dRangeMax;dX2+=dRangeStep) {
|
|
for (double dY1=dRangeMin;dY1<dRangeMax;dY1+=dRangeStep) {
|
|
for (double dY2=dRangeMin;dY2<dRangeMax;dY2+=dRangeStep) {
|
|
for (double dX=dRangeMin;dX<dRangeMax;dX+=dRangeStep) {
|
|
if (dX1 == dX2 || dX1 == dX || dX2 == dX)
|
|
continue;
|
|
|
|
double dR1 = interpolateLine(dX1, dY1, dX2, dY2, dX);
|
|
double dR2 = interpolateLine(dX1, dY1, dX, dR1, dX2);
|
|
|
|
if (round(dR2*1e6) != round(dY2*1e6))
|
|
error("Failed assertion for: (%lf, %lf), (%lf, %lf) -> (%lf, %lf); %lf", dX1, dY1, dX2, dY2, dX, dR1, dR2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
success("testInterpolation();");
|
|
}
|
|
|
|
void testSineAndReadWriteDoubleArraySingle(int nValues, int dPLen, double dAmp) {
|
|
info("Trying: %d, %d, %lf", nValues, dPLen, dAmp);
|
|
|
|
char* fileName = NULL;
|
|
fileName = malloc(100*sizeof(char));
|
|
|
|
if (fileName == NULL) {
|
|
error("Could not allocate Memory for `fileName`!");
|
|
}
|
|
|
|
sprintf(fileName, "sine_%d_%d_%lf.results.txt", nValues, dPLen, dAmp);
|
|
|
|
double *pdSineValues = generateSineValues(
|
|
nValues,
|
|
dPLen,
|
|
dAmp
|
|
);
|
|
|
|
writeDoubleArray(
|
|
pdSineValues,
|
|
nValues,
|
|
fileName
|
|
);
|
|
|
|
success("Wrote %d values to %s", nValues, fileName);
|
|
|
|
double *pdReadValues = NULL;
|
|
int iReadValues = readDoubleArray(
|
|
fileName,
|
|
&pdReadValues
|
|
);
|
|
|
|
if (iReadValues != nValues) {
|
|
error("Failed to read the correct number of values: %d != %d", iReadValues, nValues);
|
|
}
|
|
|
|
success("Read %d values from %s", iReadValues, fileName);
|
|
|
|
for (int i=0; i<nValues; i++) {
|
|
if (round(pdSineValues[i]*1e6) != round(pdReadValues[i]*1e6)) {
|
|
error("Failed to read the correct value at index %d: %lf != %lf", i, pdSineValues[i], pdReadValues[i]);
|
|
}
|
|
}
|
|
|
|
info("use `plot \"%s\", \"%s\" with lines` to view.", fileName, fileName);
|
|
|
|
free(fileName);
|
|
free(pdSineValues);
|
|
free(pdReadValues);
|
|
}
|
|
|
|
void testSineAndReadWriteDoubleArray() {
|
|
info("testSineAndWriteDoubleArray");
|
|
|
|
testSineAndReadWriteDoubleArraySingle(1000, 300, 1);
|
|
testSineAndReadWriteDoubleArraySingle(10, 10, 0.5);
|
|
testSineAndReadWriteDoubleArraySingle(10, -10, 0.5);
|
|
testSineAndReadWriteDoubleArraySingle(10, 10, 0);
|
|
|
|
success("testSineAndWriteDoubleArray");
|
|
}
|
|
|
|
void testCreateSignalWithDefault() {
|
|
info("testCreateSignalWithDefault");
|
|
|
|
MMSignal *signal = createSignalWithDefault(10, M_PI);
|
|
|
|
if (signal->iNumValues != 10) {
|
|
error("Failed to create signal with 10 values: %d != 10", signal->iNumValues);
|
|
}
|
|
|
|
for (int i=0; i<10; i++) {
|
|
if (signal->pdValues[i] != M_PI) {
|
|
error("Failed to create signal with default value 0 at index %d: %lf != 0", i, signal->pdValues[i]);
|
|
}
|
|
}
|
|
|
|
success("testCreateSignalWithDefault");
|
|
|
|
deleteSignal(signal);
|
|
}
|
|
|
|
void testCreateSignalFromDoubleArray() {
|
|
info("testCreateSignalFromDoubleArray");
|
|
|
|
double pdValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
MMSignal *signal = createSignalFromDoubleArray(10, pdValues);
|
|
|
|
if (signal->iNumValues != 10) {
|
|
error("Failed to create signal with 10 values: %d != 10", signal->iNumValues);
|
|
}
|
|
|
|
for (int i=0; i<10; i++) {
|
|
if (signal->pdValues[i] != pdValues[i]) {
|
|
error("Failed to create signal with default value 0 at index %d: %lf != 0", i, signal->pdValues[i]);
|
|
}
|
|
}
|
|
|
|
success("testCreateSignalFromDoubleArray");
|
|
|
|
deleteSignal(signal);
|
|
}
|
|
|
|
void testCreateSignalFromFile() {
|
|
info("testCreateSignalFromFile");
|
|
|
|
double pdValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
char* fileName = "testCreateSignalFromFile.results.txt";
|
|
|
|
writeDoubleArray(pdValues, 10, fileName);
|
|
|
|
MMSignal *signal = createSignalFromFile(fileName);
|
|
|
|
if (signal->iNumValues != 10) {
|
|
error("Failed to create signal with 10 values: %d != 10", signal->iNumValues);
|
|
}
|
|
|
|
for (int i=0; i<10; i++) {
|
|
if (signal->pdValues[i] != pdValues[i]) {
|
|
error("Failed to create signal with default value 0 at index %d: %lf != 0", i, signal->pdValues[i]);
|
|
}
|
|
}
|
|
|
|
success("testCreateSignalFromFile");
|
|
|
|
deleteSignal(signal);
|
|
}
|
|
|
|
void testWriteMMSignal() {
|
|
info("testWriteMMSignal");
|
|
|
|
double pdValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
char* fileName = "testWriteMMSignal.results.txt";
|
|
|
|
MMSignal *signal = createSignalFromDoubleArray(10, pdValues);
|
|
|
|
writeMMSignal(fileName, signal);
|
|
|
|
MMSignal *readSignal = createSignalFromFile(fileName);
|
|
|
|
if (signal->iNumValues != readSignal->iNumValues) {
|
|
error("Failed to read the correct number of values: %d != %d", signal->iNumValues, readSignal->iNumValues);
|
|
}
|
|
|
|
for (int i=0; i<10; i++) {
|
|
if (signal->pdValues[i] != readSignal->pdValues[i]) {
|
|
error("Failed to read the correct value at index %d: %lf != %lf", i, signal->pdValues[i], readSignal->pdValues[i]);
|
|
}
|
|
}
|
|
|
|
deleteSignal(signal);
|
|
deleteSignal(readSignal);
|
|
|
|
success("testWriteMMSignal");
|
|
}
|
|
|
|
void testCalculateArea() {
|
|
info("testCalculateArea");
|
|
|
|
double pdValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
double dArea = calculateArea(pdValues, 10);
|
|
|
|
if (round(dArea*1e6) != 55e6) {
|
|
error("Failed to calculate the correct area: %lf != 55", dArea);
|
|
}
|
|
|
|
success("testCalculateArea");
|
|
}
|
|
|
|
void testCalculateMean() {
|
|
info("testCalculateMean");
|
|
|
|
double pdValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
double dMean = calculateMean(pdValues, 10);
|
|
|
|
if (round(dMean*1e6) != 5.5e6) {
|
|
error("Failed to calculate the correct mean: %lf != 5.5", dMean);
|
|
}
|
|
|
|
success("testCalculateMean");
|
|
}
|
|
|
|
void testCalculateStdDev() {
|
|
info("testCalculateStdDev");
|
|
|
|
double pdValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
double dStdDev = calculateStddev(pdValues, 10);
|
|
|
|
if (round(dStdDev*1e6) != 2.872281e6) {
|
|
error("Failed to calculate the correct standard deviation: %lf != 2.872281", dStdDev);
|
|
}
|
|
|
|
success("testCalculateStdDev");
|
|
}
|
|
|
|
void testCalculateMedian() {
|
|
info("testCalculateMedian");
|
|
|
|
double pdValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
double dMedian = calculateMedian(pdValues, 10);
|
|
|
|
if (dMedian != 6) {
|
|
error("Failed to calculate the correct median: %lf != 5.5", dMedian);
|
|
}
|
|
|
|
success("testCalculateMedian");
|
|
}
|
|
|
|
void testCalculateEntropy() {
|
|
info("testCalculateEntropy");
|
|
|
|
double pdValues[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
Histogram *histogram = initHistogram(pdValues, 11, 11);
|
|
|
|
double dEntropy = calculateEntropy(histogram);
|
|
|
|
if (round(dEntropy*1e6) != 3.459432e6) { // Should be log2(1/11) = 3.459432
|
|
error("Failed to calculate the correct entropy: %lf != 3.459432", dEntropy);
|
|
}
|
|
|
|
success("testCalculateEntropy");
|
|
}
|
|
|
|
void testConvoluteSignals() {
|
|
info("testConvoluteSignals");
|
|
|
|
double pdValues1[] = {1, 2, 3, 4, 5};
|
|
double pdValues2[] = {1, 2, 3, 4, 5};
|
|
|
|
MMSignal *signal1 = createSignalFromDoubleArray(5, pdValues1);
|
|
MMSignal *signal2 = createSignalFromDoubleArray(5, pdValues2);
|
|
|
|
MMSignal *signal3 = convoluteSignals(signal1, signal2);
|
|
|
|
if (signal3->iNumValues != 9) {
|
|
error("Failed to calculate the correct number of values: %d != 9", signal3->iNumValues);
|
|
}
|
|
|
|
double pdExpectedValues[] = {1, 4, 10, 20, 35, 44, 46, 40, 25};
|
|
|
|
for (int i=0; i<9; i++) {
|
|
if (signal3->pdValues[i] != pdExpectedValues[i]) {
|
|
error("Failed to calculate the correct value at index %d: %lf != %lf", i, signal3->pdValues[i], pdExpectedValues[i]);
|
|
}
|
|
}
|
|
|
|
success("testConvoluteSignals");
|
|
}
|
|
|
|
void testGetPascalLine() {
|
|
info("testGetPascalLine");
|
|
|
|
// For 5
|
|
MMSignal *signal = getPascalLine(5);
|
|
|
|
if (signal->iNumValues != 5) {
|
|
error("Failed to calculate the correct number of values: %d != 5", signal->iNumValues);
|
|
}
|
|
|
|
double pdExpectedValues[] = {1, 4, 6, 4, 1};
|
|
|
|
for (int i=0; i<5; i++) {
|
|
if (signal->pdValues[i] != pdExpectedValues[i]) {
|
|
error("Failed to calculate the correct value at index %d: %lf != %lf", i, signal->pdValues[i], pdExpectedValues[i]);
|
|
}
|
|
}
|
|
|
|
// For 1
|
|
signal = getPascalLine(1);
|
|
|
|
if (signal->iNumValues != 1) {
|
|
error("Failed to calculate the correct number of values: %d != 1", signal->iNumValues);
|
|
}
|
|
|
|
if (signal->pdValues[0] != 1) {
|
|
error("Failed to calculate the correct value at index 0: %lf != 1", signal->pdValues[0]);
|
|
}
|
|
|
|
// For 11
|
|
signal = getPascalLine(11);
|
|
|
|
if (signal->iNumValues != 11) {
|
|
error("Failed to calculate the correct number of values: %d != 11", signal->iNumValues);
|
|
}
|
|
|
|
double pdExpectedValues11[] = {1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1};
|
|
|
|
for (int i=0; i<11; i++) {
|
|
if (signal->pdValues[i] != pdExpectedValues11[i]) {
|
|
error("Failed to calculate the correct value at index %d: %lf != %lf", i, signal->pdValues[i], pdExpectedValues11[i]);
|
|
}
|
|
}
|
|
|
|
success("testGetPascalLine");
|
|
}
|
|
|
|
void testComputeDFT() {
|
|
info("testComputeDFT");
|
|
|
|
double pdRealIn[] = {1, 2, 3, 4, 5};
|
|
double pdImgIn[] = {1, 2, 3, 4, 5};
|
|
|
|
double pdRealOut[5];
|
|
double pdImgOut[5];
|
|
|
|
computeDFT(5, pdRealIn, pdImgIn, pdRealOut, pdImgOut, 1);
|
|
|
|
for (int i=0; i<5; i++) {
|
|
if (pdImgOut[i] < 0) {
|
|
printf("%lf - %lfi\n", pdRealOut[i], -pdImgOut[i]);
|
|
} else {
|
|
printf("%lf + %lfi\n", pdRealOut[i], pdImgOut[i]);
|
|
}
|
|
}
|
|
|
|
success("testComputeDFT");
|
|
}
|
|
|
|
void testConvertCart2Polar() {
|
|
// convertCart2Polar(double *pdRealIn, double *pdImgIn, double *pdRadiusOut, double *pdAngleOut, int iLen)
|
|
info("testConvertCart2Polar");
|
|
|
|
double pdRealIn[] = {1, 0, 1, -1, 0};
|
|
double pdImgIn[] = {0, 1, 1, 0, -1};
|
|
double pdRadiusOut[5];
|
|
double pdAngleOut[5];
|
|
|
|
convertCart2Polar(pdRealIn, pdImgIn, pdRadiusOut, pdAngleOut, 5);
|
|
|
|
for (int i=0; i<5; i++) {
|
|
printf("%lf + %lfi -> r=%lf / θ=%lfπ\n", pdRealIn[i], pdImgIn[i], pdRadiusOut[i], pdAngleOut[i] / M_PI);
|
|
}
|
|
|
|
success("testConvertCart2Polar");
|
|
}
|
|
|
|
void testConvertPolar2Cart() {
|
|
// convertPolar2Cart(double *pdRadiusIn, double *pdAngleIn, double *pdRealOut, double *pdImgOut, int iLen)
|
|
info("testConvertPolar2Cart");
|
|
|
|
double pdRadiusIn[] = {1, 1, 1, 1, 1};
|
|
double pdAngleIn[] = {0, M_PI/2, M_PI, 3*M_PI/2, 2*M_PI};
|
|
double pdRealOut[5];
|
|
double pdImgOut[5];
|
|
|
|
convertPolar2Cart(pdRadiusIn, pdAngleIn, pdRealOut, pdImgOut, 5);
|
|
|
|
for (int i=0; i<5; i++) {
|
|
printf("r=%lf / θ=%lfπ -> %lf + %lfi\n", pdRadiusIn[i], pdAngleIn[i] / M_PI, pdRealOut[i], pdImgOut[i]);
|
|
}
|
|
|
|
success("testConvertPolar2Cart");
|
|
}
|
|
|
|
int main (int iArgC, char** ppcArgV){
|
|
testInterpolation();
|
|
testSineAndReadWriteDoubleArray();
|
|
testCreateSignalWithDefault();
|
|
testCreateSignalFromDoubleArray();
|
|
testCreateSignalFromFile();
|
|
testWriteMMSignal();
|
|
testCalculateArea();
|
|
testCalculateMean();
|
|
testCalculateStdDev();
|
|
testCalculateMedian();
|
|
testCalculateEntropy();
|
|
testConvoluteSignals();
|
|
testGetPascalLine();
|
|
testComputeDFT();
|
|
testConvertCart2Polar();
|
|
testConvertPolar2Cart();
|
|
|
|
return 0;
|
|
}
|