diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2c9c101 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +all: main.out + +main.out: main.c vec_match.c vec_match.h + gcc -o main.out main.c vec_match.c -I. diff --git a/envelope-proj.pro b/envelope-proj.pro index dda002f..d291228 100644 --- a/envelope-proj.pro +++ b/envelope-proj.pro @@ -3,7 +3,11 @@ CONFIG += console CONFIG -= app_bundle CONFIG -= qt -SOURCES += main.c +SOURCES += main.c \ + vec_match.c DISTFILES += \ style.astylerc + +HEADERS += \ + vec_match.h diff --git a/main.c b/main.c index e32124f..e3a20b1 100644 --- a/main.c +++ b/main.c @@ -1,161 +1,44 @@ #include #include -#include #include -#include -#include -#include -#define DATA_LEN 11 - -#define SQUARE(a) ((a)*(a)) +#include "vec_match.h" +#define DATA_LEN 11 static float reference[DATA_LEN] = { 0, 10, 20, 30, 40, 50, 40, 30, 20, 10, 0 }; - static float data[DATA_LEN] = { - 0, 10, 20, 30, 40, 50, 40, 30, 20, 10, 0 + 0, 10, 20, 30, 40, 50, 50, 40, 30, 30, 10 }; - -/** - * Calculate fuzzy envelope - * - * @param data source data - * @param envelope envelope (same length as source data) - * @param length data length - * @param drift_x horizontal offset (left/right growth) - * @param drift_y vertical offset (vertical growth) - */ -void calc_envelope(const float *data, float *envelope, uint32_t length, uint8_t drift_x, float drift_y) -{ - int a, b, i, j; - - for (i = 0; i < (int)length; i++) { - float peak = FLT_MIN; - - // find highest value in the surrounding drift_x points - a = i - drift_x; - b = i + drift_x; - if (a < 0) a = 0; - if (b >= (int)length) b = length - 1; - - for (j = a; j <= b; j++) { - if (peak < data[j]) peak = data[j]; - } - - // apply drift_y - peak += drift_y; - envelope[i] = peak; - } -} - - - -/** - * Match signal to reference, allowing for some offser and noise - * - * @param data matched data - * @param ref reference data - * @param length data length (data & ref length must be equal) - * @param drift_x allowed horizontal drift (Hz drift if values are 1 Hz FFT bins) - * @param offset_y allowed vertical offset (bin amplitude, positive or negative) - * @param envl_match_error error metric calculated with allowed drift and offset - * @param abs_match_error error metric calculated from raw data (can be used if envelope match passes) - * @return envelope match status (match using drift and offset) - */ -bool match_envelope(const float *data, - const float *ref, - uint32_t length, - uint8_t drift_x, - float offset_y, - float *envl_match_error, - float *abs_match_error) -{ - int a, b; - - int err_cnt = 0; - float env_err = 0; - float abs_err = 0; - - for (int i = 0; i < (int)length; i++) { - float peak = FLT_MIN; - float base = FLT_MAX; - - // find highest value in the surrounding drift_x points - a = i - drift_x; - b = i + drift_x; - if (a < 0) a = 0; - if (b >= (int)length) b = length - 1; - - for (int j = a; j <= b; j++) { - if (peak < ref[j]) peak = ref[j]; - if (base > ref[j]) base = ref[j]; - } - - // apply drift_y - peak += offset_y; - base -= offset_y; - - abs_err += SQUARE(ref[i] - data[i]); - - - if (data[i] >= base && data[i] <= peak) { - // within limits - continue; - } else { - printf("data[%d] out of range: %f, [%f ; %f]\n", i, data[i], base, peak); - - if (data[i] < base) env_err += SQUARE(base - data[i]); - if (data[i] > peak) env_err += SQUARE(data[i] - peak); - - err_cnt++; - } - } - - // write error values to provided fields - if (envl_match_error != NULL) *envl_match_error = env_err; - if (abs_match_error != NULL) *abs_match_error = abs_err; - - return err_cnt == 0; -} - - - - int main() { + // example + printf("REF: "); for (int i = 0; i < DATA_LEN; i++) { printf("%.0f, ", reference[i]); } printf("\n"); + printf("MEAS: "); for (int i = 0; i < DATA_LEN; i++) { printf("%.0f, ", data[i]); } printf("\n"); + + // error metric fields float env_e, abs_e; - bool ok = match_envelope(data, reference, DATA_LEN, 1, 5, &env_e, &abs_e); + bool ok = vec_match(data, reference, DATA_LEN, 1, 5, &env_e, &abs_e); printf("%s", ok ? "MATCH OK" : "MATCH FAILED"); printf("\n"); printf("Error rate: ENV %.2f, ABS %.2f\n", env_e, abs_e); - - /* - calc_envelope(data, envelope, 20, 1, 5); - - - for (int i = 0; i < 20; i++) { - printf("%.0f, ", envelope[i]); - } - printf("\n"); - */ } diff --git a/vec_match.c b/vec_match.c new file mode 100644 index 0000000..353b664 --- /dev/null +++ b/vec_match.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include "vec_match.h" + +#define SQUARE(a) ((a)*(a)) + +bool vec_match(const float *data, + const float *ref, + uint32_t length, + uint8_t drift_x, + float offset_y, + float *envl_match_error, + float *abs_match_error) +{ + int a, b; + + int err_cnt = 0; + float env_err = 0; + float abs_err = 0; + + for (int i = 0; i < (int)length; i++) { + float peak = FLT_MIN; + float base = FLT_MAX; + + // find highest value in the surrounding drift_x points + a = i - drift_x; + b = i + drift_x; + if (a < 0) a = 0; + if (b >= (int)length) b = length - 1; + + for (int j = a; j <= b; j++) { + if (peak < ref[j]) peak = ref[j]; + if (base > ref[j]) base = ref[j]; + } + + // apply drift_y + peak += offset_y; + base -= offset_y; + + abs_err += SQUARE(ref[i] - data[i]); + + + if (data[i] >= base && data[i] <= peak) { + // within limits + continue; + } else { + //printf("data[%d] out of range: %f, [%f ; %f]\n", i, data[i], base, peak); + + if (data[i] < base) env_err += SQUARE(base - data[i]); + if (data[i] > peak) env_err += SQUARE(data[i] - peak); + + err_cnt++; + } + } + + // write error values to provided fields + if (envl_match_error != NULL) *envl_match_error = env_err; + if (abs_match_error != NULL) *abs_match_error = abs_err; + + return err_cnt == 0; +} diff --git a/vec_match.h b/vec_match.h new file mode 100644 index 0000000..2bb9f18 --- /dev/null +++ b/vec_match.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + + +/** + * Match signal to reference, allowing for some offser and noise + * + * @param data matched data + * @param ref reference data + * @param length data length (data & ref length must be equal) + * @param drift_x allowed horizontal drift (Hz drift if values are 1 Hz FFT bins) + * @param offset_y allowed vertical offset (bin amplitude, positive or negative) + * @param envl_match_error error metric calculated with allowed drift and offset + * @param abs_match_error error metric calculated from raw data (can be used if envelope match passes) + * @return envelope match status (match using drift and offset) + */ +bool vec_match(const float *data, + const float *ref, + uint32_t length, + uint8_t drift_x, + float offset_y, + float *envl_match_error, + float *abs_match_error);