All but DFT confirmed

This commit is contained in:
Frederik Beimgraben 2025-01-12 00:10:12 +01:00
parent 5b65a43431
commit f1783f7ce8
4 changed files with 571 additions and 122 deletions

View File

@ -11,17 +11,16 @@
* https://git.beimgraben.net/MMS-2024-25/MMS-Loesung-2024-25.git
*/
#include "MMS24-25.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h>
#include "MMS24-25.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "MMS24-25.h"
#include "math.h"
// #region Error Handling and Debugging
void _error(char *fmt, ...) {
fprintf(stderr, "<\x1B[31;1m ERROR \x1B[0m: \x1B[34m'");
fprintf(stderr, "< \x1B[31;4;1mERROR\x1B[0m : \x1B[34m'");
va_list args;
va_start(args, fmt);
@ -36,7 +35,7 @@ void _error(char *fmt, ...) {
}
void _debug(char *fmt, ...) {
fprintf(stderr, "[\x1B[31;1m DEBUG \x1B[0m] \x1B[34m'");
fprintf(stderr, "[ \x1B[37;4;1mDEBUG\x1B[0m ] \x1B[34m'");
va_list args;
va_start(args, fmt);
@ -47,7 +46,7 @@ void _debug(char *fmt, ...) {
}
void _warn(char *fmt, ...) {
fprintf(stderr, "[\x1B[33;1m WARN \x1B[0m] \x1B[34m'");
fprintf(stderr, "[ \x1B[33;4;1mWARN\x1B[0m ] \x1B[34m'");
va_list args;
va_start(args, fmt);
@ -69,9 +68,9 @@ double interpolateLine(
if (dX2 == dX1)
_error("interpolateLine: dX1 and dX2 must differ!");
double y = dY1 *(
double y = dY1 * (
(dX2 - dXq) / (dX2 - dX1)
) + dY2 *(
) + dY2 * (
(dXq - dX1) / (dX2 - dX1)
);
@ -99,8 +98,19 @@ void rescaleDoubleArray(
* which naturally results from:
* $ pdOut_i = pdIn_i *dFactor + dMin $
*/
// First find the old minimum
double dOldMin = pdIn[0];
for (int i = 1; i < iLen; i++) {
if (pdIn[i] < dOldMin)
dOldMin = pdIn[i];
}
// Calculate the offset
double dOffset = dMin - dOldMin;
// Rescale the array
for (int i = 0; i < iLen; i++) {
pdOut[i] = pdIn[i] *dFactor + dMin;
pdOut[i] = pdIn[i] * dFactor + dOffset;
}
}
@ -129,13 +139,13 @@ double *generateSineValues(
// Initialize the output array
double *sineArray = NULL;
sineArray = (double*) malloc(sizeof(double) *iNumValues);
sineArray = (double*) malloc(sizeof(double) * iNumValues);
if (sineArray == NULL)
_error("*generateSineValues: Failed to allocate memory for Sine Array\n");
for (int i=0; i<iNumValues;i++){
sineArray[i] = dAmp*sin(((2*M_PI)/iNumSamplesPerPeriod) *i);
sineArray[i] = dAmp * sin(((2*M_PI)/iNumSamplesPerPeriod) * i);
}
return sineArray;
@ -147,6 +157,12 @@ void writeDoubleArray(double *pdOut, int iLen, char *pcOutName) {
if (file == NULL)
_error("writeDoubleArray: Error while opening file '%s'.\n", pcOutName);
if (pdOut == NULL)
_error("writeDoubleArray: pdOut is NULL\n");
if (iLen == 0)
_warn("writeDoubleArray: iLen is 0\n");
for (int i = 0; i < iLen; i++) {
fprintf(file, "%f\n", pdOut[i]);
}
@ -204,9 +220,47 @@ MMSignal *createSignal() {
return signal;
}
LocalExtrema* copyLocalExtrema(LocalExtrema *pexIn) {
if (pexIn == NULL)
return NULL;
LocalExtrema *localExtrema = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (localExtrema == NULL)
_error("copyLocalExtrema: Failed to allocate memory for localExtrema\n");
localExtrema->iNumLocalExtrema = pexIn->iNumLocalExtrema;
localExtrema->piLocalExtremaPos = (int*) malloc(sizeof(int) *pexIn->iNumLocalExtrema);
if (localExtrema->piLocalExtremaPos == NULL)
_error("copyLocalExtrema: Failed to allocate memory for localExtrema->piLocalExtremaPos\n");
for (int i = 0; i < pexIn->iNumLocalExtrema; i++) {
localExtrema->piLocalExtremaPos[i] = pexIn->piLocalExtremaPos[i];
}
return localExtrema;
}
Extrema* copyExtrema(Extrema *pexIn) {
if (pexIn == NULL)
return NULL;
Extrema *extrema = (Extrema*) malloc(sizeof(Extrema));
if (extrema == NULL)
_error("copyExtrema: Failed to allocate memory for extrema\n");
extrema->iGlobalMinPos = pexIn->iGlobalMinPos;
extrema->iGlobalMaxPos = pexIn->iGlobalMaxPos;
extrema->pexLocalMax = copyLocalExtrema(pexIn->pexLocalMax);
extrema->pexLocalMin = copyLocalExtrema(pexIn->pexLocalMin);
return extrema;
}
MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
MMSignal *signal = createSignal();
if (pmmsIn->pdValues != NULL) {
// Initialize and copy the values (deep copy)
signal->pdValues = (double*) malloc(sizeof(double) *pmmsIn->iNumValues);
if (signal->pdValues == NULL)
@ -215,6 +269,10 @@ MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
for (int i = 0; i < pmmsIn->iNumValues; i++) {
signal->pdValues[i] = pmmsIn->pdValues[i];
}
} else {
_warn("createSignalFromSignal: pmmsIn->pdValues is NULL\n");
signal->pdValues = NULL;
}
// Copy shallow items
signal->iNumValues = pmmsIn->iNumValues;
@ -224,38 +282,13 @@ MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
signal->dMedian = pmmsIn->dMedian;
// Deep copy of Extrema
signal->pexExtrema = (Extrema*) malloc(sizeof(Extrema));
if (signal->pexExtrema == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema\n");
signal->pexExtrema->iGlobalMinPos = pmmsIn->pexExtrema->iGlobalMinPos;
signal->pexExtrema->iGlobalMaxPos = pmmsIn->pexExtrema->iGlobalMaxPos;
signal->pexExtrema->pexLocalMax = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (signal->pexExtrema->pexLocalMax == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMax\n");
signal->pexExtrema->pexLocalMax->iNumLocalExtrema = pmmsIn->pexExtrema->pexLocalMax->iNumLocalExtrema;
signal->pexExtrema->pexLocalMax->piLocalExtremaPos = (int*) malloc(sizeof(int) *pmmsIn->pexExtrema->pexLocalMax->iNumLocalExtrema);
if (signal->pexExtrema->pexLocalMax->piLocalExtremaPos == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMax->piLocalExtremaPos\n");
for (int i = 0; i < pmmsIn->pexExtrema->pexLocalMax->iNumLocalExtrema; i++) {
signal->pexExtrema->pexLocalMax->piLocalExtremaPos[i] = pmmsIn->pexExtrema->pexLocalMax->piLocalExtremaPos[i];
if (pmmsIn->pexExtrema == NULL) {
_warn("createSignalFromSignal: pmmsIn->pexExtrema is NULL\n");
signal->pexExtrema = NULL;
return signal;
}
signal->pexExtrema->pexLocalMin = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (signal->pexExtrema->pexLocalMin == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMin\n");
signal->pexExtrema->pexLocalMin->iNumLocalExtrema = pmmsIn->pexExtrema->pexLocalMin->iNumLocalExtrema;
signal->pexExtrema->pexLocalMin->piLocalExtremaPos = (int*) malloc(sizeof(int) *pmmsIn->pexExtrema->pexLocalMin->iNumLocalExtrema);
if (signal->pexExtrema->pexLocalMin->piLocalExtremaPos == NULL)
_error("createSignalFromSignal: Failed to allocate memory for signal->pexExtrema->pexLocalMin->piLocalExtremaPos\n");
for (int i = 0; i < pmmsIn->pexExtrema->pexLocalMin->iNumLocalExtrema; i++) {
signal->pexExtrema->pexLocalMin->piLocalExtremaPos[i] = pmmsIn->pexExtrema->pexLocalMin->piLocalExtremaPos[i];
}
signal->pexExtrema = copyExtrema(pmmsIn->pexExtrema);
return signal;
}
@ -312,6 +345,9 @@ MMSignal *createSignalFromFile(char *pcInName) {
}
void writeMMSignal(char *pcInName, MMSignal *pmmsIn) {
if (pmmsIn->pdValues == NULL)
_error("writeMMSignal: pmmsIn->pdValues is NULL\n");
writeDoubleArray(
pmmsIn->pdValues,
pmmsIn->iNumValues,
@ -319,13 +355,32 @@ void writeMMSignal(char *pcInName, MMSignal *pmmsIn) {
);
}
void deleteLocalExtrema(LocalExtrema *pexIn) {
if (pexIn == NULL)
return;
free(pexIn->piLocalExtremaPos);
free(pexIn);
}
void deleteExtrema(Extrema *pexIn) {
if (pexIn == NULL)
return;
deleteLocalExtrema(pexIn->pexLocalMax);
deleteLocalExtrema(pexIn->pexLocalMin);
free(pexIn);
}
void deleteSignal(MMSignal *pmmsIn) {
if (pmmsIn == NULL)
return;
if (pmmsIn->pdValues != NULL)
free(pmmsIn->pdValues);
free(pmmsIn->pexExtrema->pexLocalMax->piLocalExtremaPos);
free(pmmsIn->pexExtrema->pexLocalMax);
free(pmmsIn->pexExtrema->pexLocalMin->piLocalExtremaPos);
free(pmmsIn->pexExtrema->pexLocalMin);
free(pmmsIn->pexExtrema);
deleteExtrema(pmmsIn->pexExtrema);
free(pmmsIn);
}
// #endregion
@ -335,24 +390,31 @@ double calculateArea(double *pdIn, int iLen) {
double area = 0;
// #FIXME: Which one should we use according to the task?
for (int i = 0; i < iLen-1; i++) {
area += (pdIn[i] + pdIn[i+1]) / 2;
for (int i = 0; i < iLen; i++) {
/* Alternative would be:
* area += (pdIn[i] + pdIn[i+1]) / 2;
* with i < iLen-1
* Which one to use is up to the implemention.
*/
area += pdIn[i];
}
return area;
}
double calculateMean(double *pdIn, int iLen) {
double mean = 0;
for (int i = 0; i < iLen; i++) {
mean += pdIn[i];
}
return mean / iLen;
/* Here the above defined function `calculateArea` is used to calculate the mean, since:
* \[ mean(pdIn) = \frac{1}{ |pdIn| } \sum_{i=1}^{ |pdIn| } x_i
* = \frac{area(x)}{ |pdIn| } \]
*/
return calculateArea(pdIn, iLen) / iLen;
}
double calculateStddev(double *pdIn, int iLen) {
/* The standard deviation is calculated as follows:
* \[ stddev(pdIn) = \sqrt{ \frac{1}{ |pdIn| } \sum_{i=1}^{ |pdIn| } (x_i - mean(pdIn))^2 } \]
*/
double mean = calculateMean(pdIn, iLen);
double stdDev = 0;
@ -363,26 +425,41 @@ double calculateStddev(double *pdIn, int iLen) {
return sqrt(stdDev / iLen);
}
double calculateMedian(double *pdIn, int iLen) {
/* The median is calculated as follows:
* \[ median(pdIn) = \begin{cases}
* pdIn_{\frac{|pdIn|}{2}} & \text{if } |pdIn| \text{ is even} \\
* \frac{pdIn_{\frac{|pdIn|}{2}} + pdIn_{\frac{|pdIn|}{2}+1}}{2} & \text{if } |pdIn| \text{ is odd}
* \end{cases} \]
*/
if (iLen % 2 == 0) {
return pdIn[iLen/2];
} else {
return (pdIn[iLen/2] + pdIn[iLen/2+1]) / 2;
}
}
LocalExtrema *initLocalExtrema(int iLen) {
LocalExtrema *localExtrema = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (localExtrema == NULL)
_error("initLocalExtrema: Failed to allocate memory for localExtrema\n");
localExtrema->iNumLocalExtrema = 0;
localExtrema->piLocalExtremaPos = (int*) malloc(sizeof(int) *iLen);
if (localExtrema->piLocalExtremaPos == NULL)
_error("initLocalExtrema: Failed to allocate memory for localExtrema->piLocalExtremaPos\n");
return localExtrema;
}
Extrema *initExtrema(double *pdIn, int iLen) {
Extrema *extrema = (Extrema*) malloc(sizeof(Extrema));
if (extrema == NULL)
_error("initExtrema: Failed to allocate memory for extrema\n");
extrema->pexLocalMax = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (extrema->pexLocalMax == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMax\n");
extrema->pexLocalMin = (LocalExtrema*) malloc(sizeof(LocalExtrema));
if (extrema->pexLocalMin == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMin\n");
extrema->pexLocalMax->piLocalExtremaPos = (int*) malloc(sizeof(int) *iLen);
if (extrema->pexLocalMax->piLocalExtremaPos == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMax->piLocalExtremaPos\n");
extrema->pexLocalMin->piLocalExtremaPos = (int*) malloc(sizeof(int) *iLen);
if (extrema->pexLocalMin->piLocalExtremaPos == NULL)
_error("initExtrema: Failed to allocate memory for extrema->pexLocalMin->piLocalExtremaPos\n");
extrema->pexLocalMax = initLocalExtrema(iLen);
extrema->pexLocalMin = initLocalExtrema(iLen);
extrema->iGlobalMaxPos = 0;
extrema->iGlobalMinPos = 0;
@ -390,14 +467,6 @@ Extrema *initExtrema(double *pdIn, int iLen) {
return extrema;
}
void deleteExtrema(Extrema *pexIn) {
free(pexIn->pexLocalMax->piLocalExtremaPos);
free(pexIn->pexLocalMax);
free(pexIn->pexLocalMin->piLocalExtremaPos);
free(pexIn->pexLocalMin);
free(pexIn);
}
void initMMSignalFeatures(MMSignal *pmmsIn) {
pmmsIn->dArea = 0;
pmmsIn->dMean = 0;
@ -409,7 +478,13 @@ void initMMSignalFeatures(MMSignal *pmmsIn) {
Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) {
Histogram *histogram = (Histogram*) malloc(sizeof(Histogram));
if (histogram == NULL)
_error("initHistogram: Failed to allocate memory for histogram\n");
_error("initHistogram: Failed to allocate memory for histogram");
if (iNumBins == 0)
_error("initHistogram: iNumBins must be non-0");
if (iLen == 0)
_warn("initHistogram: iLen is 0\n");
histogram->dIntervalMin = pdIn[0];
histogram->dIntervalMax = pdIn[0];
@ -420,26 +495,61 @@ Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) {
histogram->dIntervalMax = pdIn[i];
}
#ifdef _DEBUG_
_debug("initHistogram: histogram->dIntervalMin = %lf", histogram->dIntervalMin);
_debug("initHistogram: histogram->dIntervalMax = %lf", histogram->dIntervalMax);
#endif
histogram->dBinWidth = (histogram->dIntervalMax - histogram->dIntervalMin) / iNumBins;
histogram->iNumBins = iNumBins;
#ifdef _DEBUG_
_debug("initHistogram: histogram->dBinWidth = %lf", histogram->dBinWidth);
#endif
if (histogram->dBinWidth == 0)
histogram->dBinWidth = 1;
histogram->pdBinValues = (double*) malloc(sizeof(double) *iNumBins);
if (histogram->pdBinValues == NULL)
_error("initHistogram: Failed to allocate memory for histogram->pdBinValues\n");
_error("initHistogram: Failed to allocate memory for histogram->pdBinValues");
for (int i = 0; i < iNumBins; i++) {
histogram->pdBinValues[i] = 0;
}
for (int i = 0; i < iLen; i++) {
int bin = floor((pdIn[i] - histogram->dIntervalMin) / histogram->dBinWidth);
if (bin == iNumBins)
bin--;
histogram->pdBinValues[bin]++;
}
for (int i = 0; i < iNumBins; i++) {
histogram->pdBinValues[i] /= iLen;
}
#ifdef _DEBUG_
// DEBUG: print the parameters and result
_debug("initHistogram(%lf, %lf, %lf, %d)",
histogram->dIntervalMin,histogram->dIntervalMax,histogram->dBinWidth,histogram->iNumBins);
for (int i = 0; i < histogram->iNumBins; i++) {
_debug("initHistogram: histogram->pdBinValues[%d] = %lf", i, histogram->pdBinValues[i]);
}
#endif
return histogram;
}
void deleteHistogram(Histogram *phIn) {
if (phIn == NULL)
return;
free(phIn->pdBinValues);
free(phIn);
}
// #FIXME: Check if this checks out
double calculateEntropy(Histogram *phisIn) {
double entropy = 0;
@ -457,40 +567,49 @@ double calculateEntropy(Histogram *phisIn) {
// #region Aufgabe 3
MMSignal *convoluteSignals(MMSignal *pmmsInA, MMSignal *pmmsInB) {
MMSignal *signal = createSignal();
// Calculate output length
int iOutLen = pmmsInA->iNumValues + pmmsInB->iNumValues - 1;
if (pmmsInA->iNumValues != pmmsInB->iNumValues)
_error("convoluteSignals: Signals must have the same length\n");
double *pdOut = (double*) malloc(sizeof(double) *iOutLen);
if (pdOut == NULL)
_error("convoluteSignals: Failed to allocate memory for pdOut\n");
signal->pdValues = (double*) malloc(sizeof(double) *pmmsInA->iNumValues);
if (signal->pdValues == NULL)
_error("convoluteSignals: Failed to allocate memory for signal->pdValues\n");
for (int i = 0; i < pmmsInA->iNumValues; i++) {
signal->pdValues[i] = pmmsInA->pdValues[i] * pmmsInB->pdValues[i];
for (int i = 0; i < iOutLen; i++) {
pdOut[i] = 0;
}
signal->iNumValues = pmmsInA->iNumValues;
for (int i = 0; i < pmmsInA->iNumValues; i++) {
for (int j = 0; j < pmmsInB->iNumValues; j++) {
pdOut[i+j] += pmmsInA->pdValues[i] * pmmsInB->pdValues[j];
}
}
MMSignal *signal = createSignalFromDoubleArray(iOutLen, pdOut);
initMMSignalFeatures(signal);
return signal;
}
// #FIXME: Check if this checks out
MMSignal *getPascalLine(int iLinenum) {
MMSignal *signal = createSignal();
if (iLinenum <= 0)
_error("getPascalLine: iLinenum must be greater than 0\n");
signal->pdValues = (double*) malloc(sizeof(double) *iLinenum);
if (signal->pdValues == NULL)
_error("getPascalLine: Failed to allocate memory for signal->pdValues\n");
// Calculate a kernel signal using pascales triangle without using the factorial
double *pdValues = NULL;
pdValues = (double*) malloc(sizeof(double) * iLinenum);
if (pdValues == NULL)
_error("getPascalLine: Failed to allocate memory for pdValues\n");
signal->pdValues[0] = 1;
signal->pdValues[iLinenum-1] = 1;
for (int i = 1; i < iLinenum-1; i++) {
signal->pdValues[i] = signal->pdValues[i-1] *(iLinenum-i) / i;
for (int i = 0; i < iLinenum; i++) {
pdValues[i] = 1;
for (int j = i-1; j > 0; j--) {
pdValues[j] = pdValues[j] + pdValues[j-1];
}
}
signal->iNumValues = iLinenum;
MMSignal *signal = createSignalFromDoubleArray(iLinenum, pdValues);
initMMSignalFeatures(signal);
return signal;
}
@ -498,10 +617,12 @@ MMSignal *getPascalLine(int iLinenum) {
// #endregion
// #region Aufgabe 4
void computeDFT(int iLen,
void computeDFT(
int iLen,
double *pdRealIn, double *pdImgIn,
double *pdRealOut, double *pdImgOut,
int iDirection /*-1,1*/) {
int iDirection
) {
// Check the value of iDirection
if (iDirection != -1 && iDirection != 1)
_error("computeDFT: iDirection must be either -1 or 1\n");
@ -509,9 +630,21 @@ void computeDFT(int iLen,
for (int k = 0; k < iLen; k++) {
pdRealOut[k] = 0;
pdImgOut[k] = 0;
// Compute the sum for the k-th output element
for (int n = 0; n < iLen; n++) {
pdRealOut[k] += pdRealIn[n] * cos(2*M_PI *k *n / iLen) + iDirection * pdImgIn[n] * sin(2*M_PI *k *n / iLen);
pdImgOut[k] += -iDirection * pdRealIn[n] * sin(2*M_PI *k *n / iLen) + pdImgIn[n] * cos(2*M_PI *k *n / iLen);
double angle = iDirection * 2.0 * M_PI * k * n / iLen;
double cosTerm = cos(angle);
double sinTerm = sin(angle);
pdRealOut[k] += pdRealIn[n] * cosTerm - pdImgIn[n] * sinTerm;
pdImgOut[k] += pdRealIn[n] * sinTerm + pdImgIn[n] * cosTerm;
}
// Normalize the output
if (iDirection == -1) {
pdRealOut[k] /= iLen;
pdImgOut[k] /= iLen;
}
}
}

View File

@ -91,6 +91,6 @@ void computeDFT(int iLen,
double *pdRealIn, double *pdImgIn,
double *pdRealOut, double *pdImgOut,
int iDirection /*-1,1*/);
void convertCart2Polar(double *pdRealIn, double *pdImgIn,double *pdRadiusOut, double *pdAngleOut, int iLen);
void convertPolar2Cart(double *pdRadiusIn, double *pdAngleIn, double *pdRealOut, double *pdImgOut,int iLen);
void convertCart2Polar(double *pdRealIn, double *pdImgIn, double *pdRadiusOut, double *pdAngleOut, int iLen);
void convertPolar2Cart(double *pdRadiusIn, double *pdAngleIn, double *pdRealOut, double *pdImgOut, int iLen);
#endif

View File

@ -1,6 +1,6 @@
CC=gcc
SOURCE_FILE=MMS24-25.c
OPTS=-lm -D _TESTS_NONSTOP
OPTS=-lm -D _DEBUG_
all: clean tests run

320
tests.c
View File

@ -44,8 +44,8 @@ void error(const char* fmt, ...) {
void testInterpolation() {
info("testInterpolation");
double dRangeMin = -3;
double dRangeMax = 3;
double dRangeMin = -1;
double dRangeMax = 1;
double dRangeStep = 0.33;
for (double dX1=dRangeMin;dX1<dRangeMax;dX1+=dRangeStep) {
@ -117,6 +117,8 @@ void testSineAndReadWriteDoubleArraySingle(int nValues, int dPLen, double dAmp)
info("use `plot \"%s\", \"%s\" with lines` to view.", fileName, fileName);
free(fileName);
free(pdSineValues);
free(pdReadValues);
}
void testSineAndReadWriteDoubleArray() {
@ -130,9 +132,323 @@ void testSineAndReadWriteDoubleArray() {
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;
}