diff --git a/lib/hooks/CMakeLists.txt b/lib/hooks/CMakeLists.txt index c9b2f1de7..afc12824d 100644 --- a/lib/hooks/CMakeLists.txt +++ b/lib/hooks/CMakeLists.txt @@ -33,7 +33,7 @@ set(HOOK_SRC limit_rate.c scale.c fix.c -# cast.c + cast.c average.c dump.c dp.c diff --git a/lib/hooks/average.c b/lib/hooks/average.c index f50f8a982..338c03005 100644 --- a/lib/hooks/average.c +++ b/lib/hooks/average.c @@ -29,43 +29,129 @@ #include #include #include +#include struct average { - int mask; int offset; + + struct bitset mask; + struct vlist signal_names; }; +static int average_init(struct hook *h) +{ + int ret; + struct average *a = (struct average *) h->_vd; + + ret = vlist_init(&a->signal_names); + if (ret) + return ret; + + ret = bitset_init(&a->mask, 128); + if (ret) + return ret; + + bitset_clear_all(&a->mask); + + return 0; +} + +static int average_destroy(struct hook *h) +{ + int ret; + struct average *a = (struct average *) h->_vd; + + ret = vlist_destroy(&a->signal_names, NULL, true); + if (ret) + return ret; + + ret = bitset_destroy(&a->mask); + if (ret) + return ret; + + return 0; +} + +static int average_prepare(struct hook *h) +{ + int ret; + struct average *a = (struct average *) h->_vd; + struct signal *avg_sig; + + /* Setup mask */ + for (size_t i = 0; i < vlist_length(&a->signal_names); i++) { + char *signal_name = (char *) vlist_at_safe(&a->signal_names, i); + + int index = vlist_lookup_index(&a->signal_names, signal_name); + if (index < 0) + return -1; + + bitset_set(&a->mask, index); + } + + /* Add averaged signal */ + avg_sig = signal_create("average", NULL, SIGNAL_TYPE_FLOAT); + if (!avg_sig) + return -1; + + ret = vlist_insert(&h->signals, a->offset, avg_sig); + if (ret) + return ret; + + return 0; +} + static int average_parse(struct hook *h, json_t *cfg) { - struct average *p = (struct average *) h->_vd; + struct average *a = (struct average *) h->_vd; int ret; + size_t i; json_error_t err; + json_t *json_signals, *json_signal; - ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i }", - "offset", &p->offset, - "mask", &p->mask + ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: o }", + "offset", &a->offset, + "signals", &json_signals ); if (ret) jerror(&err, "Failed to parse configuration of hook '%s'", hook_type_name(h->_vt)); + if (!json_is_array(json_signals)) + error("Setting 'signals' of hook '%s' must be a list of signal names", hook_type_name(h->_vt)); + + json_array_foreach(json_signals, i, json_signal) { + switch (json_typeof(json_signal)) { + case JSON_STRING: + vlist_push(&a->signal_names, strdup(json_string_value(json_signal))); + break; + + case JSON_INTEGER: + bitset_set(&a->mask, json_integer_value(json_signal)); + break; + + default: + error("Invalid value for setting 'signals' in hook '%s'", hook_type_name(h->_vt)); + } + } + return 0; } static int average_process(struct hook *h, struct sample *smps[], unsigned *cnt) { - struct average *p = (struct average *) h->_vd; + struct average *a = (struct average *) h->_vd; for (int i = 0; i < *cnt; i++) { struct sample *smp = smps[i]; - double sum = 0; + double avg, sum = 0; int n = 0; for (int k = 0; k < smp->length; k++) { - if (!(p->mask & (1 << k))) + if (!bitset_test(&a->mask, k)) continue; - switch (sample_format(smps[i], k)) { + switch (sample_format(smp, k)) { case SIGNAL_TYPE_INTEGER: sum += smp->data[k].i; break; @@ -84,7 +170,9 @@ static int average_process(struct hook *h, struct sample *smps[], unsigned *cnt) n++; } - smp->data[p->offset].f = sum / n; + avg = n == 0 ? 0 : sum / n; + sample_data_insert(smp, (union signal_data *) &avg, a->offset, 1); + smp->signals = &h->signals; } return 0; @@ -99,6 +187,9 @@ static struct plugin p = { .priority = 99, .parse = average_parse, .process = average_process, + .init = average_init, + .init_signals = average_prepare, + .destroy = average_destroy, .size = sizeof(struct average) } }; diff --git a/lib/hooks/cast.c b/lib/hooks/cast.c index 886cee9e6..7d5382815 100644 --- a/lib/hooks/cast.c +++ b/lib/hooks/cast.c @@ -29,38 +29,58 @@ #include #include -#include -#include #include struct cast { - int index; + int signal_index; + char *signal_name; + + enum signal_type new_type; + char *new_name; + char *new_unit; }; -static int cast_init(struct hook *h) +static int cast_prepare(struct hook *h) { - int ret; + struct signal *orig_sig, *new_sig; struct cast *c = (struct cast *) h->_vd; - struct vlist *orig_signals; - if (h->node) - orig_signals = &h->node->in.signals; - else if (h->path) - orig_signals = &h->path->signals; - else - return -1; + if (c->signal_name) { + c->signal_index = vlist_lookup_index(&h->signals, c->signal_name); + if (c->signal_index < 0) + return -1; + } - struct signal *orig_sig = vlist_at(orig_signals, i); - struct signal *new_sig = signal_copy(orig_sig); + char *name, *unit; + enum signal_type type; + + orig_sig = vlist_at_safe(&h->signals, c->signal_index); + + type = c->new_type != SIGNAL_TYPE_AUTO ? c->new_type : orig_sig->type; + name = c->new_name ? c->new_name : orig_sig->name; + unit = c->new_unit ? c->new_unit : orig_sig->unit; + + new_sig = signal_create(name, unit, type); + + vlist_set(&h->signals, c->signal_index, new_sig); + signal_decref(orig_sig); return 0; } static int cast_destroy(struct hook *h) { - int ret; struct cast *c = (struct cast *) h->_vd; + if (c->signal_name) + free(c->signal_name); + + if (c->new_name) + free(c->new_name); + + if (c->new_unit) + free(c->new_unit); + return 0; } @@ -68,67 +88,50 @@ static int cast_parse(struct hook *h, json_t *cfg) { int ret; struct cast *c = (struct cast *) h->_vd; - struct signal *sig; - size_t i; json_error_t err; - - int index = -1; - const char *name = NULL; + json_t *json_signal; const char *new_name = NULL; const char *new_unit = NULL; - const char *new_format = NULL; + const char *new_type = NULL; - ret = json_unpack_ex(cfg, &err, "{ s?: s, s?: i, s?: s, s?: s, s?: s }", - "name", &name, - "index", &index, - "new_format", &new_format, + ret = json_unpack_ex(cfg, &err, 0, "{ s: o, s?: s, s?: s, s?: s }", + "signal", &json_signal, + "new_type", &new_type, "new_name", &new_name, "new_unit", &new_unit ); if (ret) return ret; - /* Find matching original signal descriptor */ - if (index >= 0 && name != NULL) - return -1; + switch (json_typeof(json_signal)) { + case JSON_STRING: + c->signal_name = strdup(json_string_value(json_signal)); + break; - if (index < 0 && name == NULL) - return -1; + case JSON_INTEGER: + c->signal_name = NULL; + c->signal_index = json_integer_value(json_signal); + break; - sig = name - ? vlist_lookup(&c->signals, name) - : vlist_at_safe(&c->signals, index); - if (!sig) - return -1; + default: + error("Invalid value for setting 'signal' in hook '%s'", hook_type_name(h->_vt)); + } - /* Cast to new format */ - if (new_format) { - enum signal_type fmt; - - fmt = signal_type_from_str(new_format); - if (fmt == SIGNAL_TYPE_INVALID) + if (new_type) { + c->new_type = signal_type_from_str(new_type); + if (c->new_type == SIGNAL_TYPE_INVALID) return -1; - - sig->type = fmt; } + else + c->new_type = SIGNAL_TYPE_AUTO; // We use this constant to indicate that we dont want to change the type - /* Set new name */ - if (new_name) { - if (sig->name) - free(sig->name); + if (new_name) + c->new_name = strdup(new_name); - sig->name = strdup(new_name); - } - - /* Set new unit */ - if (new_unit) { - if (sig->unit) - free(sig->unit); - - sig->unit = strdup(new_unit); - } + if (new_unit) + c->new_unit = strdup(new_unit); return 0; } @@ -140,15 +143,13 @@ static int cast_process(struct hook *h, struct sample *smps[], unsigned *cnt) for (int i = 0; i < *cnt; i++) { struct sample *smp = smps[i]; - for (int j = 0; j < smp->length; j++) { - struct signal *orig_sig = vlist_at(smp->signals, j); - struct signal *new_sig = vlist_at(&c->signals, j); + struct signal *orig_sig = vlist_at(smp->signals, c->signal_index); + struct signal *new_sig = vlist_at(&h->signals, c->signal_index); - signal_data_cast(&smp->data[j], orig_sig, new_sig); - } + signal_data_cast(&smp->data[c->signal_index], orig_sig, new_sig); /* Replace signal descriptors of sample */ - smp->signals = &c->signals; + smp->signals = &h->signals; } return 0; @@ -161,8 +162,8 @@ static struct plugin p = { .hook = { .flags = HOOK_NODE_READ | HOOK_PATH, .priority = 99, - .init = cast_init, .destroy = cast_destroy, + .init_signals = cast_prepare, .parse = cast_parse, .process = cast_process, .size = sizeof(struct cast) diff --git a/lib/hooks/dp.c b/lib/hooks/dp.c index e727b2452..d540b6332 100644 --- a/lib/hooks/dp.c +++ b/lib/hooks/dp.c @@ -36,7 +36,10 @@ #define J _Complex_I struct dp { - int index; + char *signal_name; + int signal_index; + + int offset; int inverse; double f0; @@ -48,30 +51,31 @@ struct dp { int fharmonics_len; struct window window; - - struct vlist *signals; }; static void dp_step(struct dp *d, double *in, float complex *out) { + int n = d->window.steps; + double r = 0.9999999999; + double complex om, corr; double newest = *in; double oldest = window_update(&d->window, newest); for (int i = 0; i < d->fharmonics_len; i++) { - double pi_fharm = 2.0 * M_PI * d->fharmonics[i]; + om = 2.0 * M_PI * J * d->fharmonics[i] / n; /* Recursive update */ - d->coeffs[i] = (d->coeffs[i] + (newest - oldest)) * cexp(pi_fharm); + //d->coeffs[i] = cexp(om) * (d->coeffs[i] + (newest - oldest)); + d->coeffs[i] = d->coeffs[i] * r * cexp(om) - powf(r, n) * oldest + newest; /* Correction for stationary phasor */ - double complex correction = cexp(pi_fharm * (d->t - (d->window.steps + 1))); - double complex result = 2.0 / d->window.steps * d->coeffs[i] / correction; + corr = cexp(-om * (d->t - (d->window.steps + 1))); + + out[i] = (2.0 / d->window.steps) * (d->coeffs[i] * corr); /* DC component */ - if (i == 0) - result /= 2.0; - - out[i] = result; + if (d->fharmonics[i] == 0) + out[i] /= 2.0; } } @@ -96,7 +100,6 @@ static int dp_start(struct hook *h) struct dp *d = (struct dp *) h->_vd; d->t = 0; - d->signals = NULL; for (int i = 0; i < d->fharmonics_len; i++) d->coeffs[i] = 0; @@ -138,6 +141,9 @@ static int dp_destroy(struct hook *h) free(d->fharmonics); free(d->coeffs); + if (d->signal_name) + free(d->signal_name); + return 0; } @@ -147,13 +153,13 @@ static int dp_parse(struct hook *h, json_t *cfg) int ret; json_error_t err; - json_t *json_harmonics, *json_harmonic; + json_t *json_harmonics, *json_harmonic, *json_signal; size_t i; double rate = -1, dt = -1; - ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: F, s?: F, s?: F, s: o, s?: b }", - "index", &d->index, + ret = json_unpack_ex(cfg, &err, 0, "{ s: o, s: F, s?: F, s?: F, s: o, s?: b }", + "signal", &json_signal, "f0", &d->f0, "dt", &dt, "rate", &rate, @@ -173,6 +179,20 @@ static int dp_parse(struct hook *h, json_t *cfg) if (!json_is_array(json_harmonics)) error("Setting 'harmonics' of hook '%s' must be a list of integers", plugin_name(h->_vt)); + switch (json_typeof(json_signal)) { + case JSON_STRING: + d->signal_name = strdup(json_string_value(json_signal)); + break; + + case JSON_INTEGER: + d->signal_name = NULL; + d->signal_index = json_integer_value(json_signal); + break; + + default: + error("Invalid value for setting 'signal' in hook '%s'", hook_type_name(h->_vt)); + } + d->fharmonics_len = json_array_size(json_harmonics); d->fharmonics = alloc(d->fharmonics_len * sizeof(double)); d->coeffs = alloc(d->fharmonics_len * sizeof(double complex)); @@ -183,7 +203,79 @@ static int dp_parse(struct hook *h, json_t *cfg) if (!json_is_integer(json_harmonic)) error("Setting 'harmonics' of hook '%s' must be a list of integers", plugin_name(h->_vt)); - d->fharmonics[i] = d->f0 * json_integer_value(json_harmonic); + d->fharmonics[i] = json_integer_value(json_harmonic); + } + + return 0; +} + +static int dp_prepare(struct hook *h) +{ + int ret; + struct dp *d = (struct dp *) h->_vd; + + char *new_sig_name; + struct signal *orig_sig, *new_sig; + + if (d->signal_name) { + d->signal_index = vlist_lookup_index(&h->signals, d->signal_name); + if (d->signal_index < 0) + return -1; + } + + if (d->inverse) { + /* Remove complex-valued coefficient signals */ + for (int i = 0; i < d->fharmonics_len; i++) { + orig_sig = vlist_at_safe(&h->signals, d->signal_index + i); + if (!orig_sig) + return -1; + + /** @todo: SIGNAL_TYPE_AUTO is bad here */ + if (orig_sig->type != SIGNAL_TYPE_COMPLEX && orig_sig->type != SIGNAL_TYPE_AUTO) + return -1; + + ret = vlist_remove(&h->signals, d->signal_index + i); + if (ret) + return -1; + + signal_decref(orig_sig); + } + + /* Add new real-valued reconstructed signals */ + new_sig = signal_create("dp", "idp", SIGNAL_TYPE_FLOAT); + if (!new_sig) + return -1; + + ret = vlist_insert(&h->signals, d->offset, new_sig); + if (ret) + return -1; + } + else { + orig_sig = vlist_at_safe(&h->signals, d->signal_index); + if (!orig_sig) + return -1; + + /** @todo: SIGNAL_TYPE_AUTO is bad here */ + if (orig_sig->type != SIGNAL_TYPE_FLOAT && orig_sig->type != SIGNAL_TYPE_AUTO) + return -1; + + ret = vlist_remove(&h->signals, d->signal_index); + if (ret) + return -1; + + for (int i = 0; i < d->fharmonics_len; i++) { + new_sig_name = strf("%s_harm%d", orig_sig->name, i); + + new_sig = signal_create(new_sig_name, orig_sig->unit, SIGNAL_TYPE_COMPLEX); + if (!new_sig) + return -1; + + ret = vlist_insert(&h->signals, d->offset + i, new_sig); + if (ret) + return -1; + } + + signal_decref(orig_sig); } return 0; @@ -196,50 +288,29 @@ static int dp_process(struct hook *h, struct sample *smps[], unsigned *cnt) for (unsigned j = 0; j < *cnt; j++) { struct sample *smp = smps[j]; - if (d->index > smp->length) + if (d->signal_index > smp->length) continue; - if (!d->signals) { - struct signal *orig_sig, *new_sig; + if (d->inverse) { + double signal; + float complex *coeffs = &smp->data[d->signal_index].z; - d->signals = alloc(sizeof(struct vlist)); - d->signals->state = STATE_DESTROYED; + dp_istep(d, coeffs, &signal); - vlist_copy(d->signals, smp->signals); + sample_data_remove(smp, d->signal_index, d->fharmonics_len); + sample_data_insert(smp, (union signal_data *) &signal, d->offset, 1); + } + else { + double signal = smp->data[d->signal_index].f; + float complex coeffs[d->fharmonics_len]; - orig_sig = vlist_at(smp->signals, d->index); - if (!orig_sig) - return -1; + dp_step(d, &signal, coeffs); - if (d->inverse) { - if (orig_sig->type != SIGNAL_TYPE_COMPLEX) - return -1; - } - else { - if (orig_sig->type != SIGNAL_TYPE_FLOAT) - return -1; - } - - new_sig = signal_copy(orig_sig); - if (!new_sig) - return -1; - - if (d->inverse) - new_sig->type = SIGNAL_TYPE_FLOAT; - else - new_sig->type = SIGNAL_TYPE_COMPLEX; - - int ret = vlist_set(d->signals, d->index, new_sig); - if (ret) - return ret; + sample_data_remove(smp, d->signal_index, 1); + sample_data_insert(smp, (union signal_data *) coeffs, d->offset, d->fharmonics_len); } - smp->signals = d->signals; - - if (d->inverse) - dp_istep(d, &smp->data[d->index].z, &smp->data[d->index].f); - else - dp_step(d, &smp->data[d->index].f, &smp->data[d->index].z); + smp->signals = &h->signals; } d->t += d->dt; @@ -252,9 +323,10 @@ static struct plugin p = { .description = "Transform to/from dynamic phasor domain", .type = PLUGIN_TYPE_HOOK, .hook = { - .flags = HOOK_PATH, + .flags = HOOK_PATH | HOOK_NODE_READ | HOOK_NODE_WRITE, .priority = 99, .init = dp_init, + .init_signals = dp_prepare, .destroy = dp_destroy, .start = dp_start, .stop = dp_stop, diff --git a/lib/hooks/print.c b/lib/hooks/print.c index ce930ff00..a88a541db 100644 --- a/lib/hooks/print.c +++ b/lib/hooks/print.c @@ -56,18 +56,7 @@ static int print_start(struct hook *h) struct print *p = (struct print *) h->_vd; int ret; - struct vlist *signals; - - if (h->node) - signals = &h->node->in.signals; - else if (h->path) - signals = &h->path->signals; - else - signals = NULL; - - ret = signals - ? io_init(&p->io, p->format, signals, SAMPLE_HAS_ALL) - : io_init_auto(&p->io, p->format, DEFAULT_SAMPLE_LENGTH, SAMPLE_HAS_ALL); + ret = io_init(&p->io, p->format, &h->signals, SAMPLE_HAS_ALL); if (ret) return ret; diff --git a/lib/hooks/scale.c b/lib/hooks/scale.c index 343b54f49..3b8b7e59f 100644 --- a/lib/hooks/scale.c +++ b/lib/hooks/scale.c @@ -31,63 +31,105 @@ #include struct scale { + char *signal_name; + int signal_index; + double scale; double offset; }; static int scale_init(struct hook *h) { - struct scale *p = (struct scale *) h->_vd; + struct scale *s = (struct scale *) h->_vd; - p->scale = 1; - p->offset = 0; + s->scale = 1; + s->offset = 0; + + return 0; +} + +static int scale_prepare(struct hook *h) +{ + struct scale *s = (struct scale *) h->_vd; + + if (s->signal_name) { + s->signal_index = vlist_lookup_index(&h->signals, s->signal_name); + if (s->signal_index < 0) + return -1; + } + + return 0; +} + +static int scale_destroy(struct hook *h) +{ + struct scale *s = (struct scale *) h->_vd; + + if (s->signal_name) + free(s->signal_name); return 0; } static int scale_parse(struct hook *h, json_t *cfg) { - struct scale *p = (struct scale *) h->_vd; + struct scale *s = (struct scale *) h->_vd; int ret; + json_t *json_signal; json_error_t err; - ret = json_unpack_ex(cfg, &err, 0, "{ s?: F, s?: F }", - "scale", &p->scale, - "offset", &p->offset + ret = json_unpack_ex(cfg, &err, 0, "{ s?: F, s?: F, s: o }", + "scale", &s->scale, + "offset", &s->offset, + "signal", &json_signal ); if (ret) jerror(&err, "Failed to parse configuration of hook '%s'", hook_type_name(h->_vt)); + switch (json_typeof(json_signal)) { + case JSON_STRING: + s->signal_name = strdup(json_string_value(json_signal)); + break; + + case JSON_INTEGER: + s->signal_name = NULL; + s->signal_index = json_integer_value(json_signal); + break; + + default: + error("Invalid value for setting 'signal' in hook '%s'", hook_type_name(h->_vt)); + } + return 0; } static int scale_process(struct hook *h, struct sample *smps[], unsigned *cnt) { - struct scale *p = (struct scale *) h->_vd; + struct scale *s = (struct scale *) h->_vd; for (int i = 0; i < *cnt; i++) { - for (int k = 0; k < smps[i]->length; k++) { + struct sample *smp = smps[i]; + int k = s->signal_index; - switch (sample_format(smps[i], k)) { - case SIGNAL_TYPE_INTEGER: - smps[i]->data[k].i = smps[i]->data[k].i * p->scale + p->offset; - break; + switch (sample_format(smp, k)) { + case SIGNAL_TYPE_INTEGER: + smp->data[k].i = smp->data[k].i * s->scale + s->offset; + break; - case SIGNAL_TYPE_FLOAT: - smps[i]->data[k].f = smps[i]->data[k].f * p->scale + p->offset; - break; + case SIGNAL_TYPE_FLOAT: + smp->data[k].f = smp->data[k].f * s->scale + s->offset; + break; - case SIGNAL_TYPE_COMPLEX: - smps[i]->data[k].z = smps[i]->data[k].z * p->scale + p->offset; - break; + case SIGNAL_TYPE_COMPLEX: + smp->data[k].z = smp->data[k].z * s->scale + s->offset; + break; - case SIGNAL_TYPE_BOOLEAN: - smps[i]->data[k].b = smps[i]->data[k].b * p->scale + p->offset; - break; + case SIGNAL_TYPE_BOOLEAN: + smp->data[k].b = smp->data[k].b * s->scale + s->offset; + break; - default: { } - } + default: { } } } @@ -102,6 +144,8 @@ static struct plugin p = { .flags = HOOK_PATH, .priority = 99, .init = scale_init, + .init_signals = scale_prepare, + .destroy = scale_destroy, .parse = scale_parse, .process = scale_process, .size = sizeof(struct scale)