master
Ondřej Hruška 7 years ago
parent 5e39064e5d
commit 26c94c9aef
  1. 9
      Makefile
  2. 9
      envelope-proj.pro
  3. 33
      main.c
  4. 24
      main.d
  5. 74
      src/vec_match.c
  6. 75
      src/vec_match.h

@ -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

@ -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

@ -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");

@ -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

@ -2,6 +2,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#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;
}

@ -3,23 +3,82 @@
#include <stdint.h>
#include <stdbool.h>
/* 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);

Loading…
Cancel
Save