Improve Comments; Add Extrema calculation
This commit is contained in:
parent
e84e1d5100
commit
a94a357f7a
435
MMS24-25.c
435
MMS24-25.c
@ -16,12 +16,16 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h> // For variadic functions
|
||||
|
||||
// UNIX Libraries
|
||||
#ifdef __unix__
|
||||
#include <sys/stat.h> // For checking if a file exists
|
||||
#endif
|
||||
|
||||
// Header File for this implementation
|
||||
#include "MMS24-25.h"
|
||||
|
||||
// Preprocessor Definitions in case they are not defined
|
||||
// #region Preprocessor Definitions in case they are not defined
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
@ -31,8 +35,24 @@
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
#ifndef S_IFDIR
|
||||
#define S_IFDIR 0040000
|
||||
#endif
|
||||
#ifndef ssize_t
|
||||
#define ssize_t long
|
||||
#endif
|
||||
#ifndef EOF
|
||||
#define EOF -1
|
||||
#endif
|
||||
// #endregion
|
||||
|
||||
// #region Error Handling and Debugging
|
||||
|
||||
/*
|
||||
* Prints an error message to stderr and exits the program with EXIT_FAILURE.
|
||||
* If the program is compiled with the _TESTS_NONSTOP flag, the program will
|
||||
* not exit.
|
||||
*/
|
||||
void _error(char *fmt, ...) {
|
||||
fprintf(stderr, "< \x1B[31;4;1mERROR\x1B[0m : \x1B[34m'");
|
||||
|
||||
@ -50,6 +70,10 @@ void _error(char *fmt, ...) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints a memory error message to stderr and exits the program with
|
||||
* EXIT_FAILURE.
|
||||
*/
|
||||
void _mem_error(char *fmt, ...) {
|
||||
fprintf(stderr, "< \x1B[31;4;1mMEM_ERROR\x1B[0m : \x1B[34m'");
|
||||
|
||||
@ -65,6 +89,9 @@ void _mem_error(char *fmt, ...) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints a debug message to stderr.
|
||||
*/
|
||||
void _debug(char *fmt, ...) {
|
||||
fprintf(stderr, "[ \x1B[37;4;1mDEBUG\x1B[0m ] \x1B[34m'");
|
||||
|
||||
@ -76,6 +103,9 @@ void _debug(char *fmt, ...) {
|
||||
fprintf(stderr, "'\x1B[0m\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints a warning message to stderr.
|
||||
*/
|
||||
void _warn(char *fmt, ...) {
|
||||
fprintf(stderr, "[ \x1B[33;4;1mWARN\x1B[0m ] \x1B[34m'");
|
||||
|
||||
@ -88,8 +118,59 @@ void _warn(char *fmt, ...) {
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region Aufgabe 1
|
||||
// #region C99 Compatibility
|
||||
#if _GNU_SOURCE || _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
|
||||
#else
|
||||
/*
|
||||
* Implementation of the getline function for systems that do not implement it.
|
||||
*/
|
||||
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
if (*lineptr == NULL) {
|
||||
*n = 128;
|
||||
*lineptr = (char*) malloc(*n);
|
||||
if (*lineptr == NULL)
|
||||
_mem_error("getline: Failed to allocate memory for *lineptr.");
|
||||
}
|
||||
|
||||
char *pos = *lineptr;
|
||||
char c;
|
||||
|
||||
while ((c = fgetc(stream)) != EOF) {
|
||||
// For UNIX with \n:
|
||||
#ifdef __unix__
|
||||
if (c == '\n')
|
||||
break;
|
||||
#else
|
||||
// For Windows with \r\n:
|
||||
if (c == '\r')
|
||||
if ((c = fgetc(stream)) == '\n')
|
||||
break;
|
||||
else
|
||||
ungetc(c, stream);
|
||||
#endif
|
||||
|
||||
if ((pos - *lineptr) >= *n) {
|
||||
*n *= 2;
|
||||
*lineptr = (char*) realloc(*lineptr, *n);
|
||||
if (*lineptr == NULL)
|
||||
_mem_error("getline: Failed to reallocate memory for *lineptr.");
|
||||
}
|
||||
|
||||
*pos++ = c;
|
||||
}
|
||||
|
||||
*pos = '\0';
|
||||
|
||||
#ifdef _DEBUG_
|
||||
_debug("getline: Read line '%s' with length %ld.", *lineptr, (pos - *lineptr));
|
||||
#endif
|
||||
|
||||
return feof(stream) ? -1 : (pos - *lineptr);
|
||||
}
|
||||
#endif
|
||||
// #endregion
|
||||
|
||||
// #region Aufgabe 1
|
||||
/*
|
||||
* Interpolates a line between two points (x1, y1) and (x2, y2) and returns
|
||||
* the y-coordinate of the point on the line at xq.
|
||||
@ -126,6 +207,13 @@ double interpolateLine(
|
||||
/*
|
||||
* Rescales an array of double values so that the minimum value is dMin and
|
||||
* the difference between any two values is scaled by dFactor.
|
||||
*
|
||||
* Given $ |pdIn| = |pdOut| = iLen $ it should be, that:
|
||||
* $ min(pdIn) = dMin $, as well as
|
||||
* \[ \forall i, j \in (0,\dots,iLen-1):
|
||||
* (pdOut_i - pdOut_j) = (pdIn_i - pdIn_j) *dFactor \],
|
||||
* which naturally results from:
|
||||
* $ pdOut_i = pdIn_i *dFactor + (dMin - min(pdIn)) $.
|
||||
*/
|
||||
void rescaleDoubleArray(
|
||||
double *pdIn,
|
||||
@ -134,16 +222,6 @@ void rescaleDoubleArray(
|
||||
double dFactor,
|
||||
double *pdOut
|
||||
) {
|
||||
/*
|
||||
* Rescale an array of double values, so that the following rules apply:
|
||||
* Given $ |pdIn| = |pdOut| = iLen $ it should be, that:
|
||||
* $ min(pdIn) = dMin $, as well as
|
||||
* \[ \forall i, j \in (0,\dots,iLen-1):
|
||||
* (pdOut_i - pdOut_j) = (pdIn_i - pdIn_j) *dFactor \],
|
||||
* which naturally results from:
|
||||
* $ pdOut_i = pdIn_i *dFactor + (dMin - min(pdIn)) $.
|
||||
*/
|
||||
|
||||
if (iLen == 0) {
|
||||
_warn("rescaleDoubleArray: iLen is 0");
|
||||
return;
|
||||
@ -170,17 +248,16 @@ void rescaleDoubleArray(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an array of `iNumValues` double value, so that the values
|
||||
* represent the Y-coordinates of a sine curve of which one full period
|
||||
* occupies `iNumSamplesPerPeriod` values.
|
||||
*/
|
||||
double *generateSineValues(
|
||||
int iNumValues,
|
||||
int iNumSamplesPerPeriod,
|
||||
double dAmp
|
||||
) {
|
||||
/*
|
||||
* Generate an array of `iNumValues` double value, so that the values
|
||||
* represent the Y-coordinates of a sine curve of which one full period
|
||||
* occupies `iNumSamplesPerPeriod` values.
|
||||
*/
|
||||
|
||||
// Check for invalid input
|
||||
if (iNumSamplesPerPeriod == 0)
|
||||
/*
|
||||
@ -215,7 +292,7 @@ double *generateSineValues(
|
||||
sineArray = (double*) malloc(sizeof(double) * iNumValues);
|
||||
|
||||
if (sineArray == NULL)
|
||||
_mem_error("*generateSineValues: Failed to allocate memory for Sine Array");
|
||||
_mem_error("*generateSineValues: Failed to allocate memory for Sine Array.");
|
||||
|
||||
for (int i=0; i<iNumValues;i++){
|
||||
sineArray[i] = dAmp * sin(((2*M_PI)/iNumSamplesPerPeriod) * i);
|
||||
@ -224,36 +301,42 @@ double *generateSineValues(
|
||||
return sineArray;
|
||||
}
|
||||
|
||||
// Only if UNIX Comliant
|
||||
#ifdef __unix__
|
||||
// Returns true if the given szFile is a valid file.
|
||||
int isValidFile(const char* szFile) {
|
||||
struct stat statBuffer;
|
||||
return (stat(szFile, &statBuffer) >= 0 && !(statBuffer.st_mode & S_IFDIR));
|
||||
}
|
||||
#endif
|
||||
|
||||
void writeDoubleArray(double *pdOut, int iLen, char *pcOutName) {
|
||||
/*
|
||||
/*
|
||||
* Write an array of double values to a file with the name `pcOutName`.
|
||||
* Each value is separated by a linebreak.
|
||||
*/
|
||||
|
||||
void writeDoubleArray(double *pdOut, int iLen, char *pcOutName) {
|
||||
// Check if the path is NULL
|
||||
if (pcOutName == NULL)
|
||||
_error("writeDoubleArray: pcOutName is NULL");
|
||||
|
||||
// Check if the path is a valid file
|
||||
if (!isValidFile(pcOutName))
|
||||
_error("writeDoubleArray: '%s' is not a valid file", pcOutName);
|
||||
_error("writeDoubleArray: pcOutName is NULL.");
|
||||
|
||||
// Open the file
|
||||
FILE *file = fopen(pcOutName, "w");
|
||||
|
||||
if (file == NULL)
|
||||
/*
|
||||
* If the file could not be opened, this is a fatal error, since we
|
||||
* cannot write to a file that we cannot open.
|
||||
*/
|
||||
_error("writeDoubleArray: Error while opening file '%s'.", pcOutName);
|
||||
|
||||
if (pdOut == NULL)
|
||||
_error("writeDoubleArray: pdOut is NULL");
|
||||
|
||||
if (iLen == 0)
|
||||
_warn("writeDoubleArray: iLen is 0");
|
||||
_warn("writeDoubleArray: iLen is 0.");
|
||||
|
||||
if (pdOut == NULL && iLen != 0)
|
||||
/*
|
||||
* If the array is NULL but the length is not 0, this is a fatal error,
|
||||
*/
|
||||
_error("writeDoubleArray: pdOut is NULL.");
|
||||
|
||||
for (int i = 0; i < iLen; i++) {
|
||||
fprintf(file, "%f\n", pdOut[i]);
|
||||
@ -262,27 +345,44 @@ void writeDoubleArray(double *pdOut, int iLen, char *pcOutName) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a linebreak separated list of double values from a file with the name
|
||||
* `pcInName` and stores them in the array `ppdIn`.
|
||||
*/
|
||||
int readDoubleArray(char *pcInName, double **ppdIn) {
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t read;
|
||||
int i = 0;
|
||||
char *line = NULL; // Buffer for the line
|
||||
size_t len = 0; // Length of the buffer; not strictly necessary
|
||||
ssize_t read; // Length of the read line; not strictly necessary
|
||||
int i = 0; // Counter for the number of read values/lines
|
||||
|
||||
// Set the output pointer to NULL before malloc-ing
|
||||
*ppdIn = NULL;
|
||||
|
||||
// Check if the path is NULL
|
||||
if (pcInName == NULL)
|
||||
_error("readDoubleArray: pcInName is NULL.");
|
||||
|
||||
#ifdef __unix__
|
||||
// Check if the path is a valid file
|
||||
if (!isValidFile(pcInName))
|
||||
_error("readDoubleArray: '%s' is not a valid file.", pcInName);
|
||||
#endif
|
||||
|
||||
FILE *file = fopen(pcInName, "r");
|
||||
if (file == NULL)
|
||||
_error("readDoubleArray: Error while opening file '%s'.\n", pcInName);
|
||||
_error("readDoubleArray: Error while opening file '%s'.", pcInName);
|
||||
|
||||
while ((read = getline(&line, &len, file)) != -1) {
|
||||
if (*ppdIn == NULL) {
|
||||
// Allocate memory for the first value
|
||||
*ppdIn = (double*) malloc(sizeof(double));
|
||||
} else {
|
||||
// Reallocate memory for any further values
|
||||
*ppdIn = (double*) realloc(*ppdIn, sizeof(double) *(i+1));
|
||||
}
|
||||
|
||||
if (*ppdIn == NULL)
|
||||
_error("readDoubleArray: Failed to allocate or re-allocate memory for pdIn\n");
|
||||
_mem_error("readDoubleArray: Failed to allocate or re-allocate memory for pdIn.");
|
||||
|
||||
(*ppdIn)[i] = atof(line);
|
||||
i++;
|
||||
@ -294,12 +394,16 @@ int readDoubleArray(char *pcInName, double **ppdIn) {
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new MMSignal struct and initializes all values to 0 and all
|
||||
* pointers to NULL.
|
||||
*/
|
||||
MMSignal *createSignal() {
|
||||
MMSignal *signal = NULL;
|
||||
signal = (MMSignal*) malloc(sizeof(MMSignal));
|
||||
|
||||
if (signal == NULL)
|
||||
_error("createSignal: Failed to allocate memory for signal\n");
|
||||
_mem_error("createSignal: Failed to allocate memory for signal");
|
||||
|
||||
signal->pdValues = NULL;
|
||||
signal->iNumValues = 0;
|
||||
@ -312,18 +416,21 @@ MMSignal *createSignal() {
|
||||
return signal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a deep copy of a LocalExtrema struct.
|
||||
*/
|
||||
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");
|
||||
_mem_error("copyLocalExtrema: Failed to allocate memory for localExtrema");
|
||||
|
||||
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");
|
||||
_mem_error("copyLocalExtrema: Failed to allocate memory for localExtrema->piLocalExtremaPos");
|
||||
|
||||
for (int i = 0; i < pexIn->iNumLocalExtrema; i++) {
|
||||
localExtrema->piLocalExtremaPos[i] = pexIn->piLocalExtremaPos[i];
|
||||
@ -332,13 +439,16 @@ LocalExtrema* copyLocalExtrema(LocalExtrema *pexIn) {
|
||||
return localExtrema;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a deep copy of an Extrema struct.
|
||||
*/
|
||||
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");
|
||||
_mem_error("copyExtrema: Failed to allocate memory for extrema");
|
||||
|
||||
extrema->iGlobalMinPos = pexIn->iGlobalMinPos;
|
||||
extrema->iGlobalMaxPos = pexIn->iGlobalMaxPos;
|
||||
@ -349,6 +459,9 @@ Extrema* copyExtrema(Extrema *pexIn) {
|
||||
return extrema;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a deep copy of a MMSignal struct.
|
||||
*/
|
||||
MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
|
||||
MMSignal *signal = createSignal();
|
||||
|
||||
@ -356,13 +469,13 @@ MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
|
||||
// Initialize and copy the values (deep copy)
|
||||
signal->pdValues = (double*) malloc(sizeof(double) *pmmsIn->iNumValues);
|
||||
if (signal->pdValues == NULL)
|
||||
_error("createSignalFromSignal: Failed to allocate memory for signal->pdValues\n");
|
||||
_mem_error("createSignalFromSignal: Failed to allocate memory for signal->pdValues");
|
||||
|
||||
for (int i = 0; i < pmmsIn->iNumValues; i++) {
|
||||
signal->pdValues[i] = pmmsIn->pdValues[i];
|
||||
}
|
||||
} else {
|
||||
_warn("createSignalFromSignal: pmmsIn->pdValues is NULL\n");
|
||||
_warn("createSignalFromSignal: pmmsIn->pdValues is NULL");
|
||||
signal->pdValues = NULL;
|
||||
}
|
||||
|
||||
@ -375,7 +488,7 @@ MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
|
||||
|
||||
// Deep copy of Extrema
|
||||
if (pmmsIn->pexExtrema == NULL) {
|
||||
_warn("createSignalFromSignal: pmmsIn->pexExtrema is NULL\n");
|
||||
_warn("createSignalFromSignal: pmmsIn->pexExtrema is NULL");
|
||||
signal->pexExtrema = NULL;
|
||||
return signal;
|
||||
}
|
||||
@ -385,12 +498,16 @@ MMSignal *createSignalFromSignal(MMSignal *pmmsIn) {
|
||||
return signal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new MMSignal struct with an array of `iArrayLen` values, all
|
||||
* initialized to `dDefaultValue`.
|
||||
*/
|
||||
MMSignal *createSignalWithDefault(int iArrayLen, double dDefaultValue) {
|
||||
MMSignal *signal = createSignal();
|
||||
|
||||
signal->pdValues = (double*) malloc(sizeof(double) *iArrayLen);
|
||||
if (signal->pdValues == NULL)
|
||||
_error("createSignalWithDefault: Failed to allocate memory for signal->pdValues\n");
|
||||
_mem_error("createSignalWithDefault: Failed to allocate memory for signal->pdValues");
|
||||
|
||||
for (int i = 0; i < iArrayLen; i++) {
|
||||
signal->pdValues[i] = dDefaultValue;
|
||||
@ -401,12 +518,16 @@ MMSignal *createSignalWithDefault(int iArrayLen, double dDefaultValue) {
|
||||
return signal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new MMSignal struct with an array of `iArrayLen` values,
|
||||
* containing the values from the array `pdIn`.
|
||||
*/
|
||||
MMSignal *createSignalFromDoubleArray(int iArrayLen, double *pdIn) {
|
||||
MMSignal *signal = createSignal();
|
||||
|
||||
signal->pdValues = (double*) malloc(sizeof(double) *iArrayLen);
|
||||
if (signal->pdValues == NULL)
|
||||
_error("createSignalFromDoubleArray: Failed to allocate memory for signal->pdValues\n");
|
||||
_mem_error("createSignalFromDoubleArray: Failed to allocate memory for signal->pdValues");
|
||||
|
||||
for (int i = 0; i < iArrayLen; i++) {
|
||||
signal->pdValues[i] = pdIn[i];
|
||||
@ -417,28 +538,33 @@ MMSignal *createSignalFromDoubleArray(int iArrayLen, double *pdIn) {
|
||||
return signal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new MMSignal struct and reads the values from a file with the
|
||||
* name `pcInName`.
|
||||
*/
|
||||
MMSignal *createSignalFromFile(char *pcInName) {
|
||||
double *pdIn = NULL;
|
||||
int iArrayLen = readDoubleArray(pcInName, &pdIn);
|
||||
|
||||
MMSignal *signal = createSignal();
|
||||
|
||||
signal->pdValues = (double*) malloc(sizeof(double) *iArrayLen);
|
||||
if (signal->pdValues == NULL)
|
||||
_error("createSignalFromFile: Failed to allocate memory for signal->pdValues\n");
|
||||
signal->pdValues = NULL;
|
||||
signal->iNumValues = readDoubleArray(pcInName, &signal->pdValues);
|
||||
|
||||
for (int i = 0; i < iArrayLen; i++) {
|
||||
signal->pdValues[i] = pdIn[i];
|
||||
}
|
||||
if (signal->iNumValues == 0)
|
||||
_warn("createSignalFromFile: signal->iNumValues is 0");
|
||||
|
||||
signal->iNumValues = iArrayLen;
|
||||
if (signal->pdValues == NULL && signal->iNumValues != 0)
|
||||
_error("createSignalFromFile: signal->pdValues is NULL while signal->iNumValues is not %d", signal->iNumValues);
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes the values of a MMSignal struct to a file with the name `pcInName`.
|
||||
*/
|
||||
void writeMMSignal(char *pcInName, MMSignal *pmmsIn) {
|
||||
if (pmmsIn->pdValues == NULL)
|
||||
_error("writeMMSignal: pmmsIn->pdValues is NULL\n");
|
||||
_error("writeMMSignal: pmmsIn->pdValues is NULL");
|
||||
|
||||
writeDoubleArray(
|
||||
pmmsIn->pdValues,
|
||||
@ -447,6 +573,9 @@ void writeMMSignal(char *pcInName, MMSignal *pmmsIn) {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes a LocalExtrema struct and frees the memory.
|
||||
*/
|
||||
void deleteLocalExtrema(LocalExtrema *pexIn) {
|
||||
if (pexIn == NULL)
|
||||
return;
|
||||
@ -455,6 +584,9 @@ void deleteLocalExtrema(LocalExtrema *pexIn) {
|
||||
free(pexIn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes an Extrema struct and frees the memory.
|
||||
*/
|
||||
void deleteExtrema(Extrema *pexIn) {
|
||||
if (pexIn == NULL)
|
||||
return;
|
||||
@ -464,6 +596,9 @@ void deleteExtrema(Extrema *pexIn) {
|
||||
free(pexIn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes a MMSignal struct and frees the memory.
|
||||
*/
|
||||
void deleteSignal(MMSignal *pmmsIn) {
|
||||
if (pmmsIn == NULL)
|
||||
return;
|
||||
@ -478,6 +613,11 @@ void deleteSignal(MMSignal *pmmsIn) {
|
||||
// #endregion
|
||||
|
||||
// #region Aufgabe 2
|
||||
|
||||
/*
|
||||
* Calculates the area under a curve defined by the array `pdIn` of length
|
||||
* `iLen`. The area is calculated as the sum of all values in the array.
|
||||
*/
|
||||
double calculateArea(double *pdIn, int iLen) {
|
||||
double area = 0;
|
||||
|
||||
@ -494,6 +634,11 @@ double calculateArea(double *pdIn, int iLen) {
|
||||
return area;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the mean of an array of double values `pdIn` of length `iLen`.
|
||||
* The mean is calculated as the area under the curve divided by the length of
|
||||
* the array.
|
||||
*/
|
||||
double calculateMean(double *pdIn, int 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
|
||||
@ -502,6 +647,11 @@ double calculateMean(double *pdIn, int iLen) {
|
||||
return calculateArea(pdIn, iLen) / iLen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the standard deviation of an array of double values `pdIn` of
|
||||
* length `iLen`. The standard deviation is calculated as the square root of
|
||||
* the variance.
|
||||
*/
|
||||
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 } \]
|
||||
@ -517,6 +667,11 @@ double calculateStddev(double *pdIn, int iLen) {
|
||||
return sqrt(stdDev / iLen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the median of an array of double values `pdIn` of length `iLen`.
|
||||
* The median is calculated as the middle value of the sorted array if the
|
||||
* length is odd, or the average of the two middle values if the length is even.
|
||||
*/
|
||||
double calculateMedian(double *pdIn, int iLen) {
|
||||
/* The median is calculated as follows:
|
||||
* \[ median(pdIn) = \begin{cases}
|
||||
@ -532,33 +687,118 @@ double calculateMedian(double *pdIn, int iLen) {
|
||||
}
|
||||
}
|
||||
|
||||
LocalExtrema *initLocalExtrema(int iLen) {
|
||||
/*
|
||||
* Creates a new LocalExtrema struct
|
||||
*/
|
||||
LocalExtrema *initLocalExtrema(int *piInPos, int iLen) {
|
||||
LocalExtrema *localExtrema = (LocalExtrema*) malloc(sizeof(LocalExtrema));
|
||||
if (localExtrema == NULL)
|
||||
_error("initLocalExtrema: Failed to allocate memory for localExtrema\n");
|
||||
_mem_error("initLocalExtrema: Failed to allocate memory for localExtrema");
|
||||
|
||||
localExtrema->iNumLocalExtrema = 0;
|
||||
localExtrema->iNumLocalExtrema = iLen;
|
||||
localExtrema->piLocalExtremaPos = (int*) malloc(sizeof(int) *iLen);
|
||||
if (localExtrema->piLocalExtremaPos == NULL)
|
||||
_error("initLocalExtrema: Failed to allocate memory for localExtrema->piLocalExtremaPos\n");
|
||||
_mem_error("initLocalExtrema: Failed to allocate memory for localExtrema->piLocalExtremaPos");
|
||||
|
||||
for (int i = 0; i < iLen; i++) {
|
||||
localExtrema->piLocalExtremaPos[i] = piInPos[i];
|
||||
}
|
||||
|
||||
return localExtrema;
|
||||
}
|
||||
|
||||
int getMinMaxPos(double *pdIn, int iLen, int *iMinPos, int *iMaxPos) {
|
||||
*iMaxPos = 0;
|
||||
*iMinPos = 0;
|
||||
|
||||
for (int i = 1; i < iLen; i++) {
|
||||
if (pdIn[i] > pdIn[*iMaxPos])
|
||||
*iMaxPos = i;
|
||||
if (pdIn[i] < pdIn[*iMinPos])
|
||||
*iMinPos = i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the local extrema of an array of double values `pdIn` of length `iLen`.
|
||||
* The local extrema are calculated as the points where the derivative changes
|
||||
* sign.
|
||||
*/
|
||||
void findLocalExtremaFromArray(
|
||||
double *pdIn,
|
||||
int iLen,
|
||||
LocalExtrema **ppexLocalMax,
|
||||
LocalExtrema **ppexLocalMin
|
||||
) {
|
||||
int iNumLocalMax = 0;
|
||||
int iNumLocalMin = 0;
|
||||
int *piLocalMaxPos = NULL;
|
||||
int *piLocalMinPos = NULL;
|
||||
|
||||
for (int i = 1; i < iLen - 1; i++) {
|
||||
if (pdIn[i] > pdIn[i-1] && pdIn[i] > pdIn[i+1]) {
|
||||
iNumLocalMax++;
|
||||
|
||||
if (piLocalMaxPos == NULL)
|
||||
piLocalMaxPos = (int*) malloc(sizeof(int) *iNumLocalMax);
|
||||
else
|
||||
piLocalMaxPos = (int*) realloc(piLocalMaxPos, sizeof(int) *iNumLocalMax);
|
||||
|
||||
if (piLocalMaxPos == NULL)
|
||||
_mem_error("findLocalExtremaFromArray: Failed to allocate memory for piLocalMaxPos");
|
||||
|
||||
piLocalMaxPos[iNumLocalMax-1] = i;
|
||||
}
|
||||
|
||||
if (pdIn[i] < pdIn[i-1] && pdIn[i] < pdIn[i+1]) {
|
||||
iNumLocalMin++;
|
||||
|
||||
if (piLocalMinPos == NULL)
|
||||
piLocalMinPos = (int*) malloc(sizeof(int) *iNumLocalMin);
|
||||
else
|
||||
piLocalMinPos = (int*) realloc(piLocalMinPos, sizeof(int) *iNumLocalMin);
|
||||
|
||||
if (piLocalMinPos == NULL)
|
||||
_mem_error("findLocalExtremaFromArray: Failed to allocate memory for piLocalMinPos");
|
||||
|
||||
piLocalMinPos[iNumLocalMin-1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
*ppexLocalMax = initLocalExtrema(piLocalMaxPos, iNumLocalMax);
|
||||
*ppexLocalMin = initLocalExtrema(piLocalMinPos, iNumLocalMin);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the global extrema of an array of double values `pdIn` of length
|
||||
* `iLen`. The global extrema are calculated as the points where the derivative
|
||||
* changes sign.
|
||||
*/
|
||||
Extrema *initExtrema(double *pdIn, int iLen) {
|
||||
Extrema *extrema = (Extrema*) malloc(sizeof(Extrema));
|
||||
if (extrema == NULL)
|
||||
_error("initExtrema: Failed to allocate memory for extrema\n");
|
||||
_mem_error("initExtrema: Failed to allocate memory for extrema");
|
||||
|
||||
extrema->pexLocalMax = initLocalExtrema(iLen);
|
||||
extrema->pexLocalMin = initLocalExtrema(iLen);
|
||||
// Get the global extrema
|
||||
getMinMaxPos(pdIn, iLen, &extrema->iGlobalMinPos, &extrema->iGlobalMaxPos);
|
||||
|
||||
extrema->iGlobalMaxPos = 0;
|
||||
extrema->iGlobalMinPos = 0;
|
||||
// Initialize the local extrema
|
||||
extrema->pexLocalMax = NULL;
|
||||
extrema->pexLocalMin = NULL;
|
||||
|
||||
// Find the local extrema
|
||||
findLocalExtremaFromArray(
|
||||
pdIn, iLen,
|
||||
&extrema->pexLocalMax,
|
||||
&extrema->pexLocalMin
|
||||
);
|
||||
|
||||
return extrema;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes the features of a MMSignal struct.
|
||||
*/
|
||||
void initMMSignalFeatures(MMSignal *pmmsIn) {
|
||||
pmmsIn->dArea = 0;
|
||||
pmmsIn->dMean = 0;
|
||||
@ -567,16 +807,20 @@ void initMMSignalFeatures(MMSignal *pmmsIn) {
|
||||
pmmsIn->pexExtrema = initExtrema(pmmsIn->pdValues, pmmsIn->iNumValues);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes a histogram struct with the values of an array of double values
|
||||
* `pdIn` of length `iLen`. The histogram is divided into `iNumBins` bins.
|
||||
*/
|
||||
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");
|
||||
_mem_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");
|
||||
_warn("initHistogram: iLen is 0");
|
||||
|
||||
histogram->dIntervalMin = pdIn[0];
|
||||
histogram->dIntervalMax = pdIn[0];
|
||||
@ -587,24 +831,24 @@ Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) {
|
||||
histogram->dIntervalMax = pdIn[i];
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_
|
||||
#ifdef _DEBUG_
|
||||
_debug("initHistogram: histogram->dIntervalMin = %lf", histogram->dIntervalMin);
|
||||
_debug("initHistogram: histogram->dIntervalMax = %lf", histogram->dIntervalMax);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
histogram->dBinWidth = (histogram->dIntervalMax - histogram->dIntervalMin) / iNumBins;
|
||||
histogram->iNumBins = iNumBins;
|
||||
|
||||
#ifdef _DEBUG_
|
||||
#ifdef _DEBUG_
|
||||
_debug("initHistogram: histogram->dBinWidth = %lf", histogram->dBinWidth);
|
||||
#endif
|
||||
#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");
|
||||
_mem_error("initHistogram: Failed to allocate memory for histogram->pdBinValues");
|
||||
|
||||
for (int i = 0; i < iNumBins; i++) {
|
||||
histogram->pdBinValues[i] = 0;
|
||||
@ -622,18 +866,21 @@ Histogram *initHistogram(double *pdIn, int iLen, int iNumBins) {
|
||||
histogram->pdBinValues[i] /= iLen;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_
|
||||
#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
|
||||
#endif
|
||||
|
||||
return histogram;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes a histogram struct and frees the memory.
|
||||
*/
|
||||
void deleteHistogram(Histogram *phIn) {
|
||||
if (phIn == NULL)
|
||||
return;
|
||||
@ -642,7 +889,14 @@ void deleteHistogram(Histogram *phIn) {
|
||||
free(phIn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the entropy of a histogram struct.
|
||||
*/
|
||||
double calculateEntropy(Histogram *phisIn) {
|
||||
/* The entropy is calculated as follows:
|
||||
* \[ entropy(phisIn) = - \sum_{i=1}^{ |phisIn| } phisIn_i \log_2(phisIn_i) \]
|
||||
*/
|
||||
|
||||
double entropy = 0;
|
||||
|
||||
for (int i = 0; i < phisIn->iNumBins; i++) {
|
||||
@ -658,13 +912,16 @@ double calculateEntropy(Histogram *phisIn) {
|
||||
|
||||
// #region Aufgabe 3
|
||||
|
||||
/*
|
||||
* Convolve two signals `pmmsInA` and `pmmsInB` and return the result.
|
||||
*/
|
||||
MMSignal *convoluteSignals(MMSignal *pmmsInA, MMSignal *pmmsInB) {
|
||||
// Calculate output length
|
||||
int iOutLen = pmmsInA->iNumValues + pmmsInB->iNumValues - 1;
|
||||
|
||||
double *pdOut = (double*) malloc(sizeof(double) *iOutLen);
|
||||
if (pdOut == NULL)
|
||||
_error("convoluteSignals: Failed to allocate memory for pdOut\n");
|
||||
_mem_error("convoluteSignals: Failed to allocate memory for pdOut");
|
||||
|
||||
for (int i = 0; i < iOutLen; i++) {
|
||||
pdOut[i] = 0;
|
||||
@ -682,16 +939,18 @@ MMSignal *convoluteSignals(MMSignal *pmmsInA, MMSignal *pmmsInB) {
|
||||
return signal;
|
||||
}
|
||||
|
||||
// #FIXME: Check if this checks out
|
||||
/*
|
||||
* Calculate the n-th line of Pascal's triangle and return it as a signal.
|
||||
*/
|
||||
MMSignal *getPascalLine(int iLinenum) {
|
||||
if (iLinenum <= 0)
|
||||
_error("getPascalLine: iLinenum must be greater than 0\n");
|
||||
_error("getPascalLine: iLinenum must be greater than 0");
|
||||
|
||||
// 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");
|
||||
_mem_error("getPascalLine: Failed to allocate memory for pdValues");
|
||||
|
||||
for (int i = 0; i < iLinenum; i++) {
|
||||
pdValues[i] = 1;
|
||||
@ -709,15 +968,26 @@ MMSignal *getPascalLine(int iLinenum) {
|
||||
// #endregion
|
||||
|
||||
// #region Aufgabe 4
|
||||
|
||||
/*
|
||||
* Computes the Discrete Fourier Transform of a signal, given as two arrays of
|
||||
* real and imaginary values. The result is stored in two arrays of real and
|
||||
* imaginary values.
|
||||
*/
|
||||
void computeDFT(
|
||||
int iLen,
|
||||
double *pdRealIn, double *pdImgIn,
|
||||
double *pdRealOut, double *pdImgOut,
|
||||
int iDirection
|
||||
) {
|
||||
if (iDirection == 0)
|
||||
_error("computeDFT: iDirection must not be 0!");
|
||||
|
||||
// Check the value of iDirection
|
||||
if (iDirection != -1 && iDirection != 1)
|
||||
_error("computeDFT: iDirection must be either -1 or 1\n");
|
||||
if (iDirection != -1 && iDirection != 1) {
|
||||
_warn("computeDFT: iDirection should be either -1 or 1! Normalizing!");
|
||||
iDirection = iDirection < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
for (int k = 0; k < iLen; k++) {
|
||||
pdRealOut[k] = 0;
|
||||
@ -741,6 +1011,9 @@ void computeDFT(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a signal from cartesian to polar coordinates.
|
||||
*/
|
||||
void convertCart2Polar(double *pdRealIn, double *pdImgIn, double *pdRadiusOut, double *pdAngleOut, int iLen) {
|
||||
for (int i = 0; i < iLen; i++) {
|
||||
pdRadiusOut[i] = sqrt(pow(pdRealIn[i], 2) + pow(pdImgIn[i], 2));
|
||||
@ -748,10 +1021,14 @@ void convertCart2Polar(double *pdRealIn, double *pdImgIn, double *pdRadiusOut, d
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a signal from polar to cartesian coordinates.
|
||||
*/
|
||||
void convertPolar2Cart(double *pdRadiusIn, double *pdAngleIn, double *pdRealOut, double *pdImgOut, int iLen) {
|
||||
for (int i = 0; i < iLen; i++) {
|
||||
pdRealOut[i] = pdRadiusIn[i] * cos(pdAngleIn[i]);
|
||||
pdImgOut[i] = pdRadiusIn[i] * sin(pdAngleIn[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
2
Makefile
2
Makefile
@ -1,6 +1,6 @@
|
||||
CC=gcc
|
||||
SOURCE_FILE=MMS24-25.c
|
||||
OPTS=-lm
|
||||
OPTS=-lm -std=c99
|
||||
|
||||
all: clean tests run
|
||||
|
||||
|
||||
11
tests.c
11
tests.c
@ -8,6 +8,17 @@
|
||||
#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'");
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user