/* =========================STYLE-GUIDELINES=========================== * All comments use MD-Syntax; * Formulas are written in KaTeX/TeX Syntax. * We adhere by the `kernel.org` style-guidelines. * See: https://www.kernel.org/doc/html/v4.10/process/coding-style.html * =============================AUTHORS================================ * Created by Frederik Beimgraben, Minh Dan Cam and Lea Hornberger in * the winter term of 2024/25 at the faculty of computer science at * Reutlingen University. * After grading the full source code will be available at: * https://git.beimgraben.net/MMS-2024-25/MMS-Loesung-2024-25.git */ #include "MMS24-25.h" #include "math.h" #include #include #include "MMS24-25.h" #include #include // #region Error Handling and Debugging void _error(char *fmt, ...) { fprintf(stderr, "<\x1B[31;1m ERROR \x1B[0m: \x1B[34m'"); va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "'\x1B[0m >\n"); #ifndef _TESTS_NONSTOP exit(EXIT_FAILURE); #endif } void _debug(char *fmt, ...) { fprintf(stderr, "[\x1B[31;1m DEBUG \x1B[0m] \x1B[34m'"); va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "'\x1B[0m\n"); } void _warn(char *fmt, ...) { fprintf(stderr, "[\x1B[33;1m WARN \x1B[0m] \x1B[34m'"); va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "'\x1B[0m\n"); } // #endregion // #region Aufgabe 1 double interpolateLine( double dX1, double dY1, double dX2, double dY2, double dXq ) { if (dX2 == dX1) _error("interpolateLine: dX1 and dX2 must differ!"); double y = dY1 *( (dX2 - dXq) / (dX2 - dX1) ) + dY2 *( (dXq - dX1) / (dX2 - dX1) ); #ifdef _DEBUG_ // DEBUG: print the parameters and result _debug("interpolateLine(%lf, %lf, %lf, %lf, %lf) -> %lf\n", dX1,dY1,dX2,dY2,dXq,y); #endif return y; } void rescaleDoubleArray( double *pdIn, int iLen, double dMin, 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 $ */ for (int i = 0; i < iLen; i++) { pdOut[i] = pdIn[i] *dFactor + dMin; } } 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. */ if (iNumSamplesPerPeriod == 0) _error("*generateSineValues: iNumSamplesPerPeriod must be non-0!"); if (iNumSamplesPerPeriod < 0) _warn("*generateSineValues: iNumSamplesPerPeriod is less than 0!"); if (iNumValues < 0) _error("*generateSineValues: iNumValues must be equal to or greater than 0!"); if (iNumValues == 0) _warn("*generateSineValues: iNumValues is 0!"); // Initialize the output array double *sineArray = NULL; sineArray = (double*) malloc(sizeof(double) *iNumValues); if (sineArray == NULL) _error("*generateSineValues: Failed to allocate memory for Sine Array\n"); for (int i=0; ipdValues = NULL; signal->iNumValues = 0; signal->dArea = 0; signal->dMean = 0; signal->dStdDev = 0; signal->dMedian = 0; signal->pexExtrema = NULL; return signal; } MMSignal *createSignalFromSignal(MMSignal *pmmsIn) { MMSignal *signal = createSignal(); // 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"); for (int i = 0; i < pmmsIn->iNumValues; i++) { signal->pdValues[i] = pmmsIn->pdValues[i]; } // Copy shallow items signal->iNumValues = pmmsIn->iNumValues; signal->dArea = pmmsIn->dArea; signal->dMean = pmmsIn->dMean; signal->dStdDev = pmmsIn->dStdDev; 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]; } 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]; } return signal; } 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"); for (int i = 0; i < iArrayLen; i++) { signal->pdValues[i] = dDefaultValue; } signal->iNumValues = iArrayLen; return signal; } 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"); for (int i = 0; i < iArrayLen; i++) { signal->pdValues[i] = pdIn[i]; } signal->iNumValues = iArrayLen; return signal; } 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"); for (int i = 0; i < iArrayLen; i++) { signal->pdValues[i] = pdIn[i]; } signal->iNumValues = iArrayLen; return signal; } void writeMMSignal(char *pcInName, MMSignal *pmmsIn) { writeDoubleArray( pmmsIn->pdValues, pmmsIn->iNumValues, pcInName ); } void deleteSignal(MMSignal *pmmsIn) { free(pmmsIn->pdValues); free(pmmsIn->pexExtrema->pexLocalMax->piLocalExtremaPos); free(pmmsIn->pexExtrema->pexLocalMax); free(pmmsIn->pexExtrema->pexLocalMin->piLocalExtremaPos); free(pmmsIn->pexExtrema->pexLocalMin); free(pmmsIn->pexExtrema); free(pmmsIn); } // #endregion // #region Aufgabe 2 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; } return area; } double calculateMean(double *pdIn, int iLen) { double mean = 0; for (int i = 0; i < iLen; i++) { mean += pdIn[i]; } return mean / iLen; } double calculateStddev(double *pdIn, int iLen) { double mean = calculateMean(pdIn, iLen); double stdDev = 0; for (int i = 0; i < iLen; i++) { stdDev += pow(pdIn[i] - mean, 2); } return sqrt(stdDev / iLen); } 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->iGlobalMaxPos = 0; extrema->iGlobalMinPos = 0; 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 = calculateArea(pmmsIn->pdValues, pmmsIn->iNumValues); pmmsIn->dMean = calculateMean(pmmsIn->pdValues, pmmsIn->iNumValues); pmmsIn->dStdDev = calculateStddev(pmmsIn->pdValues, pmmsIn->iNumValues); pmmsIn->dMedian = calculateMedian(pmmsIn->pdValues, pmmsIn->iNumValues); pmmsIn->pexExtrema = initExtrema(pmmsIn->pdValues, pmmsIn->iNumValues); } 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"); histogram->dIntervalMin = pdIn[0]; histogram->dIntervalMax = pdIn[0]; for (int i = 0; i < iLen; i++) { if (pdIn[i] < histogram->dIntervalMin) histogram->dIntervalMin = pdIn[i]; if (pdIn[i] > histogram->dIntervalMax) histogram->dIntervalMax = pdIn[i]; } histogram->dBinWidth = (histogram->dIntervalMax - histogram->dIntervalMin) / iNumBins; histogram->iNumBins = iNumBins; histogram->pdBinValues = (double*) malloc(sizeof(double) *iNumBins); if (histogram->pdBinValues == NULL) _error("initHistogram: Failed to allocate memory for histogram->pdBinValues\n"); for (int i = 0; i < iNumBins; i++) { histogram->pdBinValues[i] = 0; } return histogram; } void deleteHistogram(Histogram *phIn) { free(phIn->pdBinValues); free(phIn); } // #FIXME: Check if this checks out double calculateEntropy(Histogram *phisIn) { double entropy = 0; for (int i = 0; i < phisIn->iNumBins; i++) { if (phisIn->pdBinValues[i] != 0) { entropy += phisIn->pdBinValues[i] * log2(phisIn->pdBinValues[i]); } } return -entropy; } // #endregion // #region Aufgabe 3 MMSignal *convoluteSignals(MMSignal *pmmsInA, MMSignal *pmmsInB) { MMSignal *signal = createSignal(); if (pmmsInA->iNumValues != pmmsInB->iNumValues) _error("convoluteSignals: Signals must have the same length\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]; } signal->iNumValues = pmmsInA->iNumValues; return signal; } // #FIXME: Check if this checks out MMSignal *getPascalLine(int iLinenum) { MMSignal *signal = createSignal(); signal->pdValues = (double*) malloc(sizeof(double) *iLinenum); if (signal->pdValues == NULL) _error("getPascalLine: Failed to allocate memory for signal->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; } signal->iNumValues = iLinenum; return signal; } // #endregion