From aa84dad6557d4c6c651adc97892bfb87a73dcac0 Mon Sep 17 00:00:00 2001 From: Kevin Becker Date: Thu, 31 May 2018 10:02:59 +0200 Subject: [PATCH] updated .exe and src file --- bin/CPP_NLMS.exe | Bin 60928 -> 60928 bytes src/cpp_implementation/NLMSvariants.cpp | 476 ++++++++++++------------ 2 files changed, 243 insertions(+), 233 deletions(-) diff --git a/bin/CPP_NLMS.exe b/bin/CPP_NLMS.exe index fbd5af3258d7c5a0189f1aa2e1e9be4eb15b50ef..8059b29a5afa5a82dd52a7d643abe94f8ec17fc2 100644 GIT binary patch literal 60928 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 }fv&sh085Q4uDFD;AWK}VJ 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 diff --git a/src/cpp_implementation/NLMSvariants.cpp b/src/cpp_implementation/NLMSvariants.cpp index 8cc4ef1..d75b8b2 100644 --- a/src/cpp_implementation/NLMSvariants.cpp +++ b/src/cpp_implementation/NLMSvariants.cpp @@ -11,7 +11,7 @@ Created by Stefan Friese on 26.04.2018 #include #include #include -#include "nlms_types.h" // added types +#include "nlms_types.h" #define RGB_COLOR 255 #if defined(_MSC_VER) @@ -23,122 +23,124 @@ double *xSamples; // Input color values from PPM mldata_t *mlData = NULL; // Machine learning realted data point_t *points = NULL; // Graphing -/* *Graph building* */ + /* *Graph building* */ static imagePixel_t * rdPPM(char *fileName); // Read PPM file format void mkPpmFile(char *fileName, imagePixel_t *image); // Writes PPM file int ppmColorChannel(FILE* fp, imagePixel_t *image, // Writes colorChannel from PPM file to log file - char *colorChannel, mldata_t *mlData); + char *colorChannel, mldata_t *mlData); void colorSamples(FILE* fp, mldata_t *mlData); // Stores color channel values in xSamples -/* *File handling* */ -char * mkFileName ( char* buffer, // Date+suffix as filename - size_t max_len, int suffixId ); -char *fileSuffix ( int id ); // Filename ending of logs -char *fileHeader ( int id ); // Header inside the logfiles + /* *File handling* */ +char * mkFileName(char* buffer, // Date+suffix as filename + size_t max_len, int suffixId); +char *fileSuffix(int id); // Filename ending of logs +char *fileHeader(int id); // Header inside the logfiles void bufferLogger(char *buffer, point_t points[]); // Writes points to graph template -void mkSvgGraph ( point_t points[], char *templatePath); // Parses graph template and calls bufferLogger() -void weightsLogger ( double *weights, int suffix ); // Writes updated weights to a file +void mkSvgGraph(point_t points[], char *templatePath); // Parses graph template and calls bufferLogger() +void weightsLogger(double *weights, int suffix); // Writes updated weights to a file -/* *rand seed* */ -double r2 ( void ); // Random val between 0 and 1 -double rndm ( void ); + /* *rand seed* */ +double r2(void); // Random val between 0 and 1 +double rndm(void); /* *args parser* */ -void usage ( char **argv ); // Help text called by args parser +void usage(char **argv); // Help text called by args parser -/* *math* */ + /* *math* */ mldata_t * init_mldata_t(unsigned windowSize, unsigned samplesCount, double learnrate); double sum_array(double x[], int length); -void localMean ( mldata_t *mlData,point_t points[] ); // First, -void directPredecessor ( mldata_t *mlData, point_t points[] ); // Second, -void differentialPredecessor ( mldata_t *mlData, point_t points[] ); // Third filter implementation +void localMean(mldata_t *mlData, point_t points[]); // First, +void directPredecessor(mldata_t *mlData, point_t points[]); // Second, +void differentialPredecessor(mldata_t *mlData, point_t points[]); // Third filter implementation double windowXMean(int _arraylength, int xCount); // Returns mean value of given window -int main( int argc, char **argv ) { - char *colorChannel = (char *) malloc(sizeof(char)* 32); +int main(int argc, char **argv) { + char *colorChannel = (char *)malloc(sizeof(char) * 32); char *inputfile = (char *)malloc(sizeof(char) * 32); unsigned *seed = NULL; unsigned k, include = 0; unsigned windowSize = 5; unsigned samplesCount = 512; - char *stdcolor = "green", xBuffer[512]; + char *stdcolor = (char*)"green", xBuffer[512]; colorChannel = stdcolor; unsigned int uint_buffer[1], windowBuffer[1]; double learnrate = 0.4; - char *istrue = "true"; + char *istrue = (char*)"true"; char *templatePath = NULL; - - while( (argc > 1) && (argv[1][0] == '-') ) { // Parses parameters from stdin - switch( argv[1][1] ) { - case 'i': - inputfile = &argv[1][3]; - ++argv; - --argc; - break; - case 'w': - sscanf(&argv[1][3], "%u", windowBuffer); - windowSize = windowBuffer[0]; - ++argv; - --argc; - break; - case 'c': - colorChannel = &argv[1][3]; - ++argv; - --argc; - break; - case 's': - sscanf(&argv[1][3], "%u", uint_buffer); - seed = &uint_buffer[0]; - ++argv; - --argc; - break; - case 'n': - sscanf(&argv[1][3], "%u", &samplesCount); - ++argv; - --argc; - break; - case'h': - printf("Program name: %s\n", argv[0]); - usage(argv); - break; - case 'l': - sscanf(&argv[1][3], "%lf", &learnrate); - ++argv; - --argc; - break; - case 'g': - sscanf(&argv[1][3], "%s", xBuffer); - if ( strstr(xBuffer, istrue) ) { - include = 1; - } else if ( xBuffer && !strstr(xBuffer, istrue) ) { - templatePath = xBuffer; - include = 1; - } else { - printf( "Wrong Argruments: %s\n", argv[1]); - usage(argv); - } - ++argv; - --argc; - break; - default: - printf("Wrong Arguments: %s\n", argv[1]); - usage(argv); + + while ((argc > 1) && (argv[1][0] == '-')) { // Parses parameters from stdin + switch (argv[1][1]) { + case 'i': + inputfile = &argv[1][3]; + ++argv; + --argc; + break; + case 'w': + sscanf(&argv[1][3], "%u", windowBuffer); + windowSize = windowBuffer[0]; + ++argv; + --argc; + break; + case 'c': + colorChannel = &argv[1][3]; + ++argv; + --argc; + break; + case 's': + sscanf(&argv[1][3], "%u", uint_buffer); + seed = &uint_buffer[0]; + ++argv; + --argc; + break; + case 'n': + sscanf(&argv[1][3], "%u", &samplesCount); + ++argv; + --argc; + break; + case'h': + printf("Program name: %s\n", argv[0]); + usage(argv); + break; + case 'l': + sscanf(&argv[1][3], "%lf", &learnrate); + ++argv; + --argc; + break; + case 'g': + sscanf(&argv[1][3], "%s", xBuffer); + if (strstr(xBuffer, istrue)) { + include = 1; } - + else if (xBuffer && !strstr(xBuffer, istrue)) { + templatePath = xBuffer; + include = 1; + } + else { + printf("Wrong Argruments: %s\n", argv[1]); + usage(argv); + } + ++argv; + --argc; + break; + default: + printf("Wrong Arguments: %s\n", argv[1]); + usage(argv); + } + ++argv; --argc; } - init_mldata_t ( windowSize, samplesCount, learnrate ); - xSamples = (double *) malloc ( sizeof(double) * mlData->samplesCount ); // Resize input values - points = (point_t *) malloc ( sizeof(point_t) * mlData->samplesCount); // Resize points - imagePixel_t *image; + init_mldata_t(windowSize, samplesCount, learnrate); + xSamples = (double *)malloc(sizeof(double) * mlData->samplesCount); // Resize input values + points = (point_t *)malloc(sizeof(point_t) * mlData->samplesCount); // Resize points + imagePixel_t *image; image = rdPPM(inputfile); // Set Pointer on input values - printf("window Size: %d\n", mlData->windowSize); + printf("window Size: %d\n", mlData->windowSize); char fileName[50]; // Logfiles and their names mkFileName(fileName, sizeof(fileName), TEST_VALUES); FILE* fp5 = fopen(fileName, "w"); @@ -146,16 +148,17 @@ int main( int argc, char **argv ) { FILE* fp6 = fopen(fileName, "r"); colorSamples(fp6, mlData); - if ( (seed != NULL) ){ - srand( *seed ); // Seed for random number generating + if ((seed != NULL)) { + srand(*seed); // Seed for random number generating printf("srand is reproducable\n"); - } else { - srand( (unsigned int)time(NULL) ); + } + else { + srand((unsigned int)time(NULL)); printf("srand depends on time\n"); // Default seed is time(NULL) } printf("generated weights:\n"); - for (k = 0; k < mlData->windowSize; k++) { + for (k = 0; k < mlData->windowSize; k++) { mlData->weights[k] = rndm(); // Init random weights printf("[%d] %lf\n", k, mlData->weights[k]); } @@ -163,18 +166,18 @@ int main( int argc, char **argv ) { mkFileName(fileName, sizeof(fileName), PURE_WEIGHTS); // Logfile weights FILE *fp0 = fopen(fileName, "w"); for (k = 0; k < mlData->windowSize; k++) { - fprintf(fp0, "[%d]%lf\n", k, mlData->weights[k]); + fprintf(fp0, "[%d]%lf\n", k, mlData->weights[k]); } fclose(fp0); - localMean ( mlData, points ); // math magic functions - directPredecessor ( mlData, points ); - differentialPredecessor( mlData, points ); + localMean(mlData, points); // math magic functions + directPredecessor(mlData, points); + differentialPredecessor(mlData, points); - if ( include == 1 ) { + if (include == 1) { mkSvgGraph(points, templatePath); // Graph building - - } + + } free(image); free(xSamples); @@ -192,56 +195,58 @@ Variant (1/3), substract local mean. ====================================================================================================== */ -void localMean ( mldata_t *mlData, point_t points[] ) { - double *localWeights = (double *) malloc ( sizeof(double) * mlData->windowSize + 1); +void localMean(mldata_t *mlData, point_t points[]) { + double *localWeights = (double *)malloc(sizeof(double) * mlData->windowSize + 1); localWeights = mlData->weights; char fileName[50]; - const unsigned xErrorLength = mlData->samplesCount; - double xError[xErrorLength]; - unsigned i, xCount = 0; // Runtime vars + unsigned xErrorLength = mlData->samplesCount; + double *xError = (double *)malloc(sizeof(double) * xErrorLength+1); + memset(xError, 0.0, sizeof(double) * xErrorLength); + + unsigned i, xCount = 0; // Runtime vars mkFileName(fileName, sizeof(fileName), LOCAL_MEAN); // Create Logfile and its filename - FILE* fp4 = fopen(fileName, "w"); - fprintf( fp4, fileHeader(LOCAL_MEAN_HEADER) ); - - mkFileName ( fileName, sizeof(fileName), USED_WEIGHTS_LOCAL_MEAN); + FILE* fp4 = fopen(fileName, "w"); + fprintf(fp4, fileHeader(LOCAL_MEAN_HEADER)); + + mkFileName(fileName, sizeof(fileName), USED_WEIGHTS_LOCAL_MEAN); FILE *fp9 = fopen(fileName, "w"); - + double xMean = xSamples[0]; double xSquared = 0.0; double xPredicted = 0.0; double xActual = 0.0; - for ( xCount = 1; xCount < mlData->samplesCount-1; xCount++ ) { // First value will not get predicted - unsigned _arrayLength = ( xCount > mlData->windowSize ) ? mlData->windowSize + 1 : xCount; // Ensures corect length at start - xMean = (xCount > 0) ? windowXMean(_arrayLength, xCount) : 0; + for (xCount = 1; xCount < mlData->samplesCount - 1; xCount++) { // First value will not get predicted + unsigned _arrayLength = (xCount > mlData->windowSize) ? mlData->windowSize + 1 : xCount; // Ensures corect length at start + xMean = (xCount > 0) ? windowXMean(_arrayLength, xCount) : 0; xPredicted = 0.0; xActual = xSamples[xCount]; - for ( i = 1; i < _arrayLength; i++ ) { // Get predicted value - xPredicted += ( localWeights[i - 1] * (xSamples[xCount - i] - xMean) ); + for (i = 1; i < _arrayLength; i++) { // Get predicted value + xPredicted += (localWeights[i - 1] * (xSamples[xCount - i] - xMean)); } - xPredicted += xMean; + xPredicted += xMean; xError[xCount] = xActual - xPredicted; // Get error value xSquared = 0.0; for (i = 1; i < _arrayLength; i++) { // Get xSquared xSquared += pow(xSamples[xCount - i] - xMean, 2); } - if ( xSquared == 0.0 ) { // Otherwise returns Pred: -1.#IND00 in some occassions + if (xSquared == 0.0) { // Otherwise returns Pred: -1.#IND00 in some occassions xSquared = 1.0; } - for ( i = 1; i < _arrayLength; i++ ) { // Update weights + for (i = 1; i < _arrayLength; i++) { // Update weights localWeights[i] = localWeights[i - 1] + mlData->learnrate * xError[xCount] // Substract localMean - * ( (xSamples[xCount - i] - xMean) / xSquared ); - fprintf( fp9, "%lf\n", localWeights[i] ); + * ((xSamples[xCount - i] - xMean) / xSquared); + fprintf(fp9, "%lf\n", localWeights[i]); } - + fprintf(fp4, "%d\t%f\t%f\t%f\n", xCount, xPredicted, xActual, xError[xCount]); // Write to logfile - + points[xCount].xVal[1] = xCount; // Save points so graph can be build later on - points[xCount].yVal[1] = xPredicted; + points[xCount].yVal[1] = xPredicted; points[xCount].xVal[4] = xCount; points[xCount].yVal[4] = xError[xCount]; @@ -271,33 +276,34 @@ substract direct predecessor ====================================================================================================== */ -void directPredecessor( mldata_t *mlData, point_t points[]) { - double *localWeights = ( double * ) malloc ( sizeof(double) * mlData->windowSize + 1 ); +void directPredecessor(mldata_t *mlData, point_t points[]) { + double *localWeights = (double *)malloc(sizeof(double) * mlData->windowSize + 1); localWeights = mlData->weights; char fileName[512]; - const unsigned xErrorLength = mlData->samplesCount; - double xError[xErrorLength]; - unsigned xCount = 0, i; + const unsigned xErrorLength = mlData->samplesCount; + double *xError = (double *)malloc(sizeof(double) * xErrorLength); + memset(xError, 0.0, sizeof(double) * xErrorLength); + unsigned xCount = 0, i; double xActual = 0.0; double xPredicted = 0.0; mkFileName(fileName, sizeof(fileName), DIRECT_PREDECESSOR); // Logfile and name handling FILE *fp3 = fopen(fileName, "w"); - fprintf( fp3, fileHeader(DIRECT_PREDECESSOR_HEADER) ); - - mkFileName ( fileName, sizeof(fileName), USED_WEIGHTS_DIR_PRED); + fprintf(fp3, fileHeader(DIRECT_PREDECESSOR_HEADER)); + + mkFileName(fileName, sizeof(fileName), USED_WEIGHTS_DIR_PRED); FILE *fp9 = fopen(fileName, "w"); - for (xCount = 1; xCount < mlData->samplesCount-1; xCount++) { // first value will not get predicted - unsigned _arrayLength = ( xCount > mlData->windowSize ) ? mlData->windowSize + 1 : xCount; + for (xCount = 1; xCount < mlData->samplesCount - 1; xCount++) { // first value will not get predicted + unsigned _arrayLength = (xCount > mlData->windowSize) ? mlData->windowSize + 1 : xCount; xPredicted = 0.0; xActual = xSamples[xCount]; - + for (i = 1; i < _arrayLength; i++) { - xPredicted += ( localWeights[i - 1] * (xSamples[xCount - 1] - xSamples[xCount - i - 1])); + xPredicted += (localWeights[i - 1] * (xSamples[xCount - 1] - xSamples[xCount - i - 1])); } - + xPredicted += xSamples[xCount - 1]; xError[xCount] = xActual - xPredicted; @@ -305,16 +311,16 @@ void directPredecessor( mldata_t *mlData, point_t points[]) { for (i = 1; i < _arrayLength; i++) { xSquared += pow(xSamples[xCount - 1] - xSamples[xCount - i - 1], 2); // substract direct predecessor } - if ( xSquared == 0.0 ) { // Otherwise returns Pred: -1.#IND00 in some occassions + if (xSquared == 0.0) { // Otherwise returns Pred: -1.#IND00 in some occassions xSquared = 1.0; } - for ( i = 1; i < _arrayLength; i++ ) { // Update weights - localWeights[i] = localWeights[i-1] + mlData->learnrate * xError[xCount] - * ( (xSamples[xCount - 1] - xSamples[xCount - i - 1]) / xSquared); - fprintf( fp9, "%lf\n", localWeights[i] ); + for (i = 1; i < _arrayLength; i++) { // Update weights + localWeights[i] = localWeights[i - 1] + mlData->learnrate * xError[xCount] + * ((xSamples[xCount - 1] - xSamples[xCount - i - 1]) / xSquared); + fprintf(fp9, "%lf\n", localWeights[i]); } - - fprintf(fp3, "%d\t%f\t%f\t%f\n", xCount, xPredicted, xActual, xError[xCount]); // Write to logfile + + fprintf(fp3, "%d\t%f\t%f\t%f\n", xCount, xPredicted, xActual, xError[xCount]); // Write to logfile points[xCount].xVal[2] = xCount; // Fill point_t array for graph building points[xCount].yVal[2] = xPredicted; points[xCount].xVal[5] = xCount; @@ -323,7 +329,7 @@ void directPredecessor( mldata_t *mlData, point_t points[]) { fclose(fp9); double mean = sum_array(xError, xErrorLength) / xErrorLength; // Mean - double deviation = 0.0; + double deviation = 0.0; for (i = 1; i < xErrorLength; i++) { @@ -345,12 +351,13 @@ differential predecessor. ====================================================================================================== */ -void differentialPredecessor ( mldata_t *mlData, point_t points[] ) { - double *localWeights = (double *) malloc ( sizeof(double) * mlData->windowSize + 1 ); +void differentialPredecessor(mldata_t *mlData, point_t points[]) { + double *localWeights = (double *)malloc(sizeof(double) * mlData->windowSize + 1); localWeights = mlData->weights; - const unsigned xErrorLength = mlData->samplesCount; + const unsigned xErrorLength = mlData->samplesCount; char fileName[512]; - double xError[xErrorLength]; + double *xError = (double *)malloc(sizeof(double) * xErrorLength); + memset(xError, 0.0, sizeof(double) * xErrorLength); unsigned xCount = 0, i; double xPredicted = 0.0; @@ -358,19 +365,19 @@ void differentialPredecessor ( mldata_t *mlData, point_t points[] ) { mkFileName(fileName, sizeof(fileName), DIFFERENTIAL_PREDECESSOR); // File handling FILE *fp6 = fopen(fileName, "w"); - fprintf(fp6, fileHeader(DIFFERENTIAL_PREDECESSOR_HEADER) ); + fprintf(fp6, fileHeader(DIFFERENTIAL_PREDECESSOR_HEADER)); - mkFileName ( fileName, sizeof(fileName), USED_WEIGHTS_DIFF_PRED); + mkFileName(fileName, sizeof(fileName), USED_WEIGHTS_DIFF_PRED); FILE *fp9 = fopen(fileName, "w"); - for (xCount = 1; xCount < mlData->samplesCount-1; xCount++) { // First value will not get predicted + for (xCount = 1; xCount < mlData->samplesCount - 1; xCount++) { // First value will not get predicted unsigned _arrayLength = (xCount > mlData->windowSize) ? mlData->windowSize + 1 : xCount; xPredicted = 0.0; xActual = xSamples[xCount]; for (i = 1; i < _arrayLength; i++) { - xPredicted += ( localWeights[i - 1] * (xSamples[xCount - i] - xSamples[xCount - i - 1])); + xPredicted += (localWeights[i - 1] * (xSamples[xCount - i] - xSamples[xCount - i - 1])); } xPredicted += xSamples[xCount - 1]; xError[xCount] = xActual - xPredicted; @@ -379,18 +386,18 @@ void differentialPredecessor ( mldata_t *mlData, point_t points[] ) { for (i = 1; i < _arrayLength; i++) { xSquared += pow(xSamples[xCount - i] - xSamples[xCount - i - 1], 2); // Substract direct predecessor } - if ( xSquared == 0.0 ) { // Otherwise returns Pred: -1.#IND00 in some occassions + if (xSquared == 0.0) { // Otherwise returns Pred: -1.#IND00 in some occassions xSquared = 1.0; } for (i = 1; i < _arrayLength; i++) { - localWeights[i] = localWeights[i-1] + mlData->learnrate * xError[xCount] + localWeights[i] = localWeights[i - 1] + mlData->learnrate * xError[xCount] * ((xSamples[xCount - i] - xSamples[xCount - i - 1]) / xSquared); - fprintf( fp9, "%lf\n", localWeights[i] ); + fprintf(fp9, "%lf\n", localWeights[i]); } - fprintf(fp6, "%d\t%f\t%f\t%f\n", xCount, xPredicted, xActual, xError[xCount]); // Write to logfile - + fprintf(fp6, "%d\t%f\t%f\t%f\n", xCount, xPredicted, xActual, xError[xCount]); // Write to logfile + points[xCount].xVal[3] = xCount; points[xCount].yVal[3] = xPredicted; points[xCount].xVal[6] = xCount; @@ -401,7 +408,6 @@ void differentialPredecessor ( mldata_t *mlData, point_t points[] ) { double mean = sum_array(xError, xErrorLength) / xErrorLength; double deviation = 0.0; - for (i = 1; i < xErrorLength; i++) { // Mean square deviation += pow(xError[i] - mean, 2); @@ -427,7 +433,7 @@ char *mkFileName(char* buffer, size_t max_len, int suffixId) { const char * format_str = "%Y-%m-%d_%H_%M_%S"; // Date formatting size_t date_len; const char * suffix = fileSuffix(suffixId); - time_t now = time(NULL); + time_t now = time(NULL); strftime(buffer, max_len, format_str, localtime(&now)); // Get Date date_len = strlen(buffer); @@ -444,16 +450,16 @@ Contains and returns every suffix for all existing filenames ====================================================================================================== */ -char * fileSuffix ( int id ) { - char * suffix[] = { "_weights_pure.txt", - "_weights_used_dir_pred_.txt", - "_direct_predecessor.txt", - "_ergebnisse.txt", - "_localMean.txt", - "_testvalues.txt", - "_differential_predecessor.txt", - "_weights_used_local_mean.txt", - "_weights_used_diff_pred.txt", +char * fileSuffix(int id) { + char * suffix[] = { (char*)"_weights_pure.txt", + (char*)"_weights_used_dir_pred_.txt", + (char*)"_direct_predecessor.txt", + (char*)"_ergebnisse.txt", + (char*)"_localMean.txt", + (char*)"_testvalues.txt", + (char*)"_differential_predecessor.txt", + (char*)"_weights_used_local_mean.txt", + (char*)"_weights_used_diff_pred.txt", }; return suffix[id]; } @@ -463,14 +469,14 @@ char * fileSuffix ( int id ) { fileHeader -Contains and returns header from logfiles +Contains and returns header from logfiles ====================================================================================================== */ -char * fileHeader ( int id ) { - char * header[] = { "\n=========================== Local Mean ===========================\nNo.\txPredicted\txAcutal\t\txError\n", - "\n=========================== Direct Predecessor ===========================\nNo.\txPredicted\txAcutal\t\txError\n", - "\n=========================== Differential Predecessor ===========================\nNo.\txPredicted\txAcutal\t\txError\n" +char * fileHeader(int id) { + char * header[] = { (char*)"\n=========================== Local Mean ===========================\nNo.\txPredicted\txAcutal\t\txError\n", + (char*)"\n=========================== Direct Predecessor ===========================\nNo.\txPredicted\txAcutal\t\txError\n", + (char*)"\n=========================== Differential Predecessor ===========================\nNo.\txPredicted\txAcutal\t\txError\n" }; return header[id]; } @@ -484,7 +490,7 @@ Logs used weights to logfile - not used right now ====================================================================================================== */ -void weightsLogger (double *weights, int val ) { +void weightsLogger(double *weights, int val) { char fileName[512]; unsigned i; mkFileName(fileName, sizeof(fileName), val); @@ -500,14 +506,14 @@ void weightsLogger (double *weights, int val ) { bufferLogger -formats output of mkSvgGraph -- Please open graphResults.html to see the output-- - [0] = xActual, - [1] = xPredicted from localMean, - [2] = xPredicted from directPredecessor, - [3] = xPredicted from differentialpredecessor, - [4] = xError from localMean, - [5] = xError from directPredecessor, - [6] = xError from differentialPredecessor +formats output of mkSvgGraph -- Please open graphResults.html to see the output-- +[0] = xActual, +[1] = xPredicted from localMean, +[2] = xPredicted from directPredecessor, +[3] = xPredicted from differentialpredecessor, +[4] = xError from localMean, +[5] = xError from directPredecessor, +[6] = xError from differentialPredecessor ====================================================================================================== */ @@ -594,28 +600,29 @@ parses template.svg and writes results in said template ====================================================================================================== */ void mkSvgGraph(point_t points[], char *templatePath) { - FILE* input = NULL; - FILE *target = fopen("graphResults.html", "w"); - if (templatePath){ - printf("\ngraph template src at: %s\n", templatePath); - input = fopen(templatePath, "r"); - } else { - input = fopen("graphResults_template.html", "r"); - } - + FILE* input = NULL; + FILE *target = fopen("graphResults.html", "w"); + if (templatePath) { + printf("\ngraph template src at: %s\n", templatePath); + input = fopen(templatePath, "r"); + } + else { + input = fopen("graphResults_template.html", "r"); + } + char line[512]; char firstGraph[15] = { " "firstGraph" bufferLogger(buffer, points); // write points @@ -663,30 +670,30 @@ static imagePixel_t *rdPPM(char *fileName) { c = getc(fp); } ungetc(c, fp); - if ( fscanf(fp, "%d %d", &image->x, &image->y) != 2 ) { + if (fscanf(fp, "%d %d", &image->x, &image->y) != 2) { fprintf(stderr, "Invalid image size in %s\n", fileName); exit(EXIT_FAILURE); } - if ( fscanf(fp, "%d", &rgbColor) != 1 ) { + if (fscanf(fp, "%d", &rgbColor) != 1) { fprintf(stderr, "Invalid rgb component in %s\n", fileName); } - if ( rgbColor != RGB_COLOR ) { + if (rgbColor != RGB_COLOR) { fprintf(stderr, "Invalid image color range in %s\n", fileName); exit(EXIT_FAILURE); } - while ( fgetc(fp) != '\n' ); + while (fgetc(fp) != '\n'); image->data = (colorChannel_t *)malloc(image->x * image->y * sizeof(imagePixel_t)); if (!image) { fprintf(stderr, "malloc() on image->data failed"); exit(EXIT_FAILURE); } - if ( (image->x * image->y) < mlData->samplesCount) { - printf("Changing \"-n\" to %d, image max data size\n", ( image->x * image->y ) ); - tmp = (double *) realloc ( xSamples, sizeof(double) * (image->x * image->y) ); + if ((image->x * image->y) < mlData->samplesCount) { + printf("Changing \"-n\" to %d, image max data size\n", (image->x * image->y)); + tmp = (double *)realloc(xSamples, sizeof(double) * (image->x * image->y)); xSamples = tmp; - mlData->samplesCount = (image->x * image->y ); + mlData->samplesCount = (image->x * image->y); } - if ( fread( image->data, 3 * image->x, image->y, fp) != image->y) { + if (fread(image->data, 3 * image->x, image->y, fp) != image->y) { fprintf(stderr, "Loading image failed"); exit(EXIT_FAILURE); } @@ -730,23 +737,26 @@ int ppmColorChannel(FILE* fp, imagePixel_t *image, char *colorChannel, mldata_t unsigned i = 0; printf("colorChannel : %s\n", colorChannel); - if ( image ) { // RGB channel can be set through args from cli - if ( strcmp(colorChannel, "green") == 0 ){ - for ( i = 0; i < mlData->samplesCount - 1; i++ ) { - fprintf ( fp, "%d\n", image->data[i].green ); + if (image) { // RGB channel can be set through args from cli + if (strcmp(colorChannel, "green") == 0) { + for (i = 0; i < mlData->samplesCount - 1; i++) { + fprintf(fp, "%d\n", image->data[i].green); } - } else if ( strcmp(colorChannel, "red") == 0 ){ - for ( i = 0; i < mlData->samplesCount - 1; i++ ) { - fprintf ( fp, "%d\n", image->data[i].red ); - } - - } else if ( strcmp(colorChannel, "blue") == 0 ) { - for ( i = 0; i < mlData->samplesCount - 1; i++ ) { - fprintf ( fp, "%d\n", image->data[i].blue ); + } + else if (strcmp(colorChannel, "red") == 0) { + for (i = 0; i < mlData->samplesCount - 1; i++) { + fprintf(fp, "%d\n", image->data[i].red); } - } else { + + } + else if (strcmp(colorChannel, "blue") == 0) { + for (i = 0; i < mlData->samplesCount - 1; i++) { + fprintf(fp, "%d\n", image->data[i].blue); + } + } + else { printf("Colorchannels are red, green and blue. Pick one of them!"); - exit( EXIT_FAILURE ); + exit(EXIT_FAILURE); } } fclose(fp); @@ -763,13 +773,13 @@ creating the SVG graph ====================================================================================================== */ -void colorSamples ( FILE* fp, mldata_t *mlData ) { +void colorSamples(FILE* fp, mldata_t *mlData) { int i = 0; - char *buffer = (char *) malloc(sizeof(char) * mlData->samplesCount + 1); + char *buffer = (char *)malloc(sizeof(char) * mlData->samplesCount + 1); while (!feof(fp)) { - if (fgets(buffer, mlData->samplesCount, fp) != NULL) { - sscanf(buffer, "%lf", &xSamples[i]); + if (fgets(buffer, mlData->samplesCount, fp) != NULL) { + sscanf(buffer, "%lf", &xSamples[i]); points[i].yVal[0] = xSamples[i]; // Fills points so actual input values can be seen as a graph points[i].xVal[0] = i; ++i; @@ -783,7 +793,7 @@ void colorSamples ( FILE* fp, mldata_t *mlData ) { windowXMean -returns mean value of given input +returns mean value of given input ====================================================================================================== */ @@ -792,7 +802,7 @@ double windowXMean(int _arraylength, int xCount) { double *ptr; for (ptr = &xSamples[xCount - _arraylength]; ptr != &xSamples[xCount]; ptr++) { // Set ptr to beginning of window and iterate through array - sum += *ptr; + sum += *ptr; } return sum / (double)_arraylength; } @@ -800,43 +810,43 @@ double windowXMean(int _arraylength, int xCount) { /* ====================================================================================================== - usage - - used in conjunction with the args parser. Returns help section of "-h" +usage + +used in conjunction with the args parser. Returns help section of "-h" ====================================================================================================== */ -void usage ( char **argv ) { +void usage(char **argv) { printf("Usage: %s [POSIX style options] -i file ...\n", &argv[0][0]); printf("POSIX options:\n"); printf("\t-h\t\t\tDisplay this information.\n"); printf("\t-i \t\tName of inputfile. Must be PPM image.\n"); - printf("\t-n \t\tAmount of input data used.\n"); + printf("\t-n \t\tAmount of input data used.\n"); printf("\t-c \t\tUse this color channel from inputfile.\n"); printf("\t-w \t\tCount of used weights (windowSize).\n"); - printf("\t-l \t\tLearnrate, 0 < learnrate < 1.\n"); + printf("\t-l \t\tLearnrate, 0 < learnrate < 1.\n"); printf("\t-g \t\t\tGraph building. If template is located in another folder use path, otherwise true.\n\t\t\t\tChoose for n < 1200.\n"); - printf("\t-s \t\tDigit for random seed generator.\n\t\t\t\tSame Digits produce same random values. Default is srand by time.\n"); + printf("\t-s \t\tDigit for random seed generator.\n\t\t\t\tSame Digits produce same random values. Default is srand by time.\n"); printf("\n\n"); - printf("%s compares prediction methods of least mean square filters.\nBy default it reads ppm file format and return logfiles as well\nas an svg graphs as an output of said least mean square methods.\n\nExample:\n\t%s -i myimage.ppm -w 3 -c green -s 5 -g true\n", &argv[0][0], &argv[0][0]); + printf("%s compares prediction methods of least mean square filters.\nBy default it reads ppm file format and return logfiles as well\nas an svg graphs as an output of said least mean square methods.\n\nExample:\n\t%s -i myimage.ppm -w 3 -c green -s 5 -g true\n", &argv[0][0], &argv[0][0]); exit(8); } /* ====================================================================================================== - init_mldata_t - - - Init meachine learning data +init_mldata_t + + +Init meachine learning data ====================================================================================================== */ mldata_t * init_mldata_t(unsigned windowSize, unsigned samplesCount, double learnrate) { - mlData = (mldata_t *) malloc( sizeof(mldata_t) ); + mlData = (mldata_t *)malloc(sizeof(mldata_t)); mlData->windowSize = windowSize; mlData->samplesCount = samplesCount; mlData->learnrate = learnrate; - mlData->weights = (double *) malloc ( sizeof(double) * windowSize + 1 ); + mlData->weights = (double *)malloc(sizeof(double) * windowSize + 1); return mlData; }