From 26c94c9aef2f0aa212e6f29421923a9a8a3ee97e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 25 Dec 2015 19:37:05 +0100 Subject: [PATCH] progress --- Makefile | 9 +++++- envelope-proj.pro | 9 ++++-- main.c | 33 +++++++++++++++++++-- main.d | 24 +++++++++++++++ src/vec_match.c | 74 ++++++++++++++++++++++++++++++++++++++-------- src/vec_match.h | 75 ++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 197 insertions(+), 27 deletions(-) create mode 100644 main.d diff --git a/Makefile b/Makefile index bdc443c..b4eec43 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,14 @@ +CFLAGS += -Os -ggdb -std=gnu99 -Wfatal-errors +CFLAGS += -Wall -Wextra -Wshadow +CFLAGS += -Wwrite-strings -Wold-style-definition -Winline -Wmissing-noreturn -Wstrict-prototypes +CFLAGS += -Wredundant-decls -Wfloat-equal -Wsign-compare +CFLAGS += -Wunused-function +CFLAGS += -MD -lm + all: main.out main.out: main.c src/vec_match.c src/vec_match.h - gcc -o main.out main.c src/vec_match.c -Isrc + gcc $(CFLAGS) -o main.out main.c src/vec_match.c -Isrc run: main.out ./main.out diff --git a/envelope-proj.pro b/envelope-proj.pro index d291228..e1c9132 100644 --- a/envelope-proj.pro +++ b/envelope-proj.pro @@ -4,10 +4,13 @@ CONFIG -= app_bundle CONFIG -= qt SOURCES += main.c \ - vec_match.c + vec_match.c \ + src/vec_match.c DISTFILES += \ - style.astylerc + style.astylerc \ + Makefile HEADERS += \ - vec_match.h + vec_match.h \ + src/vec_match.h diff --git a/main.c b/main.c index a481e5c..6025363 100644 --- a/main.c +++ b/main.c @@ -15,8 +15,37 @@ static float data[DATA_LEN] = { }; -int main() +static float data_cprs[16] = { + 0, 15.7, 0, 0, 0.1, 0.2, 0.1, 10, 24.242, 0, 0, 0.1, 0.2, 0.4, 0.5, 0 +}; + +static float data_cprs2[16]; + +int main(void) { + for (int i = 0; i < 16; i++) { + printf("%.1f, ", data_cprs[i]); + } + printf("\n"); + + int len = vec_pack(data_cprs2, 16, data_cprs, 16, 2); + printf("compressed len = %d\n", len); + + for (int i = 0; i < len; i++) { + printf("%.1f, ", data_cprs2[i]); + } + printf("\n"); + + + return 0; + + vec_match_cfg_t cfg = { + .length = DATA_LEN, + .drift_x = 1, + .offset_y = 5, + .abs_threshold = 0.1 + }; + // example printf("REF: "); @@ -36,7 +65,7 @@ int main() // error metric fields float env_e, abs_e; - bool ok = vec_match(data, reference, DATA_LEN, 1, 5, &env_e, &abs_e); + bool ok = vec_match(data, reference, &cfg, &env_e, &abs_e); printf("%s", ok ? "MATCH OK" : "MATCH FAILED"); printf("\n"); diff --git a/main.d b/main.d new file mode 100644 index 0000000..75b34af --- /dev/null +++ b/main.d @@ -0,0 +1,24 @@ +main.out: src/vec_match.c /usr/include/stdc-predef.h \ + /usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h /usr/include/bits/wchar.h \ + /usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/include/stdbool.h \ + /usr/include/stdlib.h \ + /usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/include/stddef.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/bits/types.h \ + /usr/include/bits/typesizes.h /usr/include/bits/byteswap-16.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/sigset.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h \ + /usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/include/float.h \ + /usr/include/math.h /usr/include/bits/math-vector.h \ + /usr/include/bits/libm-simd-decl-stubs.h /usr/include/bits/huge_val.h \ + /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ + /usr/include/bits/inf.h /usr/include/bits/nan.h \ + /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ + src/vec_match.h diff --git a/src/vec_match.c b/src/vec_match.c index eb48a4f..08b7749 100644 --- a/src/vec_match.c +++ b/src/vec_match.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "vec_match.h" @@ -9,10 +10,8 @@ bool vec_match(const float *data, const float *ref, - uint32_t length, - uint8_t drift_x, - float offset_y, - float *envl_match_error, + const vec_match_cfg_t *cfg, + float *fuzzy_match_error, float *abs_match_error) { int a, b; @@ -21,15 +20,15 @@ bool vec_match(const float *data, float env_err = 0; float abs_err = 0; - for (int i = 0; i < (int)length; i++) { + for (int i = 0; i < (int)cfg->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; + a = i - cfg->drift_x; + b = i + cfg->drift_x; if (a < 0) a = 0; - if (b >= (int)length) b = length - 1; + if (b >= (int)cfg->length) b = cfg->length - 1; for (int j = a; j <= b; j++) { if (peak < ref[j]) peak = ref[j]; @@ -37,13 +36,16 @@ bool vec_match(const float *data, } // apply drift_y - peak += offset_y; - base -= offset_y; + peak += cfg->offset_y; // add abs threshold on top + base -= cfg->offset_y; - abs_err += SQUARE(ref[i] - data[i]); + // ignore abs threshold difference (float precision error) + if (fabs(ref[i] - data[i]) > cfg->abs_threshold) { + abs_err += SQUARE(ref[i] - data[i]); + } - if (data[i] >= base && data[i] <= peak) { + if (data[i] >= (base - cfg->abs_threshold) && data[i] <= (peak + cfg->abs_threshold)) { // within limits continue; } else { @@ -57,8 +59,54 @@ bool vec_match(const float *data, } // write error values to provided fields - if (envl_match_error != NULL) *envl_match_error = env_err; + if (fuzzy_match_error != NULL) *fuzzy_match_error = env_err; if (abs_match_error != NULL) *abs_match_error = abs_err; return err_cnt == 0; } + + + + +uint32_t vec_pack(float *result, uint32_t result_capacity, const float *data, uint32_t data_length, float threshold) +{ + uint32_t result_len = 0; + uint32_t zeroes = 0; + + for (uint32_t i = 0; i < data_length; i++) { + if (data[i] < threshold) { + zeroes++; + } else { + // write zero marker to result + if (zeroes) { + if (result_len < result_capacity) { + result[result_len] = 0.0f - zeroes; // float and negative + } + + zeroes = 0; + result_len++; //length is increased even if buffer full + } + + if (result_len < result_capacity) { + result[result_len] = data[i]; + } + + result_len++; + } + } + + // handle trailing zeroes + if (zeroes) { + if (result_len < result_capacity) { + result[result_len] = 0.0f - zeroes; + } + + result_len++; + } + + return result_len; +} + + + + diff --git a/src/vec_match.h b/src/vec_match.h index 2bb9f18..a98a2a1 100644 --- a/src/vec_match.h +++ b/src/vec_match.h @@ -3,23 +3,82 @@ #include #include +/* Example: drift_x 1, offset_y 10, abs_threshold 0.1 */ +typedef struct { + uint32_t length; // data length (data & ref length must be equal) + uint32_t drift_x; // allowed horizontal drift (Hz drift if values are 1 Hz FFT bins) + float offset_y; // allowed vertical offset (bin amplitude, positive or negative) + float abs_threshold; // absolute threshold (to fix preccision errors, also added to offset_y) +} vec_match_cfg_t; + /** * 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 cfg config struct + * @param fuzzy_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, + const vec_match_cfg_t *cfg, + float *fuzzy_match_error, float *abs_match_error); + + +/** + * Match vectors of positive numbers. + * Negative number indicates how many consecutive elements are zero (hence the compression). + * + * 1024-long vector [12, 0, ...] would be [12, -1023] + * + * Params otherwise the same as vec_match() + */ +bool vec_match_packed(const float *data, + const float *ref, + const vec_match_cfg_t *cfg, + float *fuzzy_match_error, + float *abs_match_error); + + +/** + * Compress a vector by replacing sequence of zeroes with a negative value indicating their count. + * + * Returned length may exceed result_capacity, but the buffer is never overrun. + * That can be used to gradually increase the threshold until the compressed data fits in the result buffer. + * + * The compression is by definition lossy. + * + * @param result result vector (can be the same as data vector for in-place operation) + * @param result_capacity size of result buffer. + * @param data data vector + * @param length data legth + * @param threshold max value to be considered zero in the compression + * @return length of result vector + */ +uint32_t vec_pack(float *result, + uint32_t result_capacity, + const float *data, + uint32_t length, + float threshold); + + +/** + * Unpack a vector compressed with vec_pack(). + * + * If returned length exceeds provided buffer capacity, it's an indication that you need to enlarge your buffer. + * The buffer is never overrun, though. + * + * @param result result buffer + * @param result_capacity result buffer size + * @param compr_data compressed data vector + * @param compr_length compressed data vector length + * @return + */ +uint32_t vec_unpack(float *result, + uint32_t result_capacity, + const float *compr_data, + uint32_t compr_length);