1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-30 00:00:11 +01:00

signal-generator: add support for configuring different paramenters for each generated signal value

This commit is contained in:
Steffen Vogel 2020-08-19 14:14:40 +02:00
parent d96afb3b13
commit bfe60465f5
2 changed files with 121 additions and 47 deletions

View file

@ -55,10 +55,10 @@ struct signal_generator {
} type; /**< Signal type */
double rate; /**< Sampling rate. */
double frequency; /**< Frequency of the generated signals. */
double amplitude; /**< Amplitude of the generated signals. */
double stddev; /**< Standard deviation of random signals (normal distributed). */
double offset; /**< A constant bias. */
double *frequency; /**< Frequency of the generated signals. */
double *amplitude; /**< Amplitude of the generated signals. */
double *stddev; /**< Standard deviation of random signals (normal distributed). */
double *offset; /**< A constant bias. */
int monitor_missed; /**< Boolean, if set, node counts missed steps and warns user. */
double *last; /**< The values from the previous period which are required for random walk. */

View file

@ -21,6 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <list>
#include <cmath>
#include <cstring>
@ -86,6 +87,47 @@ static const char * signal_generator_type_str(enum signal_generator::SignalType
}
}
int signal_generator_init(struct node *n)
{
struct signal_generator *s = (struct signal_generator *) n->_vd;
new (&s->task) Task(CLOCK_MONOTONIC);
s->rt = 1;
s->limit = -1;
s->values = 1;
s->rate = 10;
s->monitor_missed = 1;
s->frequency = nullptr;
s->amplitude = nullptr;
s->stddev = nullptr;
s->offset = nullptr;
return 0;
}
int signal_generator_destroy(struct node *n)
{
struct signal_generator *s = (struct signal_generator *) n->_vd;
s->task.~Task();
if (s->frequency)
delete s->frequency;
if (s->amplitude)
delete s->amplitude;
if (s->stddev)
delete s->stddev;
if (s->offset)
delete s->offset;
return 0;
}
int signal_generator_prepare(struct node *n)
{
struct signal_generator *s = (struct signal_generator *) n->_vd;
@ -112,31 +154,82 @@ int signal_generator_parse(struct node *n, json_t *cfg)
json_error_t err;
s->rt = 1;
s->limit = -1;
s->values = 1;
s->rate = 10;
s->frequency = 1;
s->amplitude = 1;
s->stddev = 0.2;
s->offset = 0;
s->monitor_missed = 1;
json_t *json_amplitude = nullptr;
json_t *json_offset = nullptr;
json_t *json_frequency = nullptr;
json_t *json_stddev = nullptr;
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: i, s?: F, s?: F, s?: F, s?: F, s?: F, s?: b}",
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: i, s?: F, s?: o, s?: o, s?: o, s?: o, s?: b }",
"signal", &type,
"realtime", &s->rt,
"limit", &s->limit,
"values", &s->values,
"rate", &s->rate,
"frequency", &s->frequency,
"amplitude", &s->amplitude,
"stddev", &s->stddev,
"offset", &s->offset,
"frequency", &json_frequency,
"amplitude", &json_amplitude,
"stddev", &json_stddev,
"offset", &json_offset,
"monitor_missed", &s->monitor_missed
);
if (ret)
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
struct desc {
json_t *json;
double **array;
double def_value;
const char *name;
};
std::list<struct desc> arrays = {
{ json_frequency, &s->frequency, 1, "frequency" },
{ json_amplitude, &s->amplitude, 1, "amplitude" },
{ json_stddev, &s->stddev, 0.2, "stddev" },
{ json_offset, &s->offset, 0, "offset" }
};
for (auto &a : arrays) {
if (*a.array)
delete *a.array;
*a.array = new double[s->values];
if (a.json) {
switch (json_typeof(a.json)) {
case JSON_ARRAY:
if (json_array_size(a.json) != s->values)
throw ConfigError(a.json, "node-config-node-signal", "Length of values must match");
size_t i;
json_t *json_value;
json_array_foreach(a.json, i, json_value) {
if (!json_is_real(json_value))
throw ConfigError(json_value, "node-config-node-signal", "Values must gives as array of float values!");
(*a.array)[i] = json_real_value(json_value);
}
break;
case JSON_REAL:
if (!json_is_real(a.json))
throw ConfigError(a.json, "node-config-node-signal", "Values must gives as array of float values!");
for (size_t i = 0; i < s->values; i++)
(*a.array)[i] = json_real_value(a.json);
break;
default:
throw ConfigError(a.json, "node-config-node-signal", "Values must given as array or scalar float value!");
}
}
else {
for (size_t i = 0; i < s->values; i++)
(*a.array)[i] = a.def_value;
}
}
if (type)
s->type = signal_generator_lookup_type(type);
else
@ -157,7 +250,7 @@ int signal_generator_start(struct node *n)
throw MemoryAllocationError();
for (unsigned i = 0; i < s->values; i++)
s->last[i] = s->offset;
s->last[i] = s->offset[i];
/* Setup task */
if (s->rt)
@ -223,31 +316,31 @@ int signal_generator_read(struct node *n, struct sample *smps[], unsigned cnt, u
switch (rtype) {
case signal_generator::SignalType::CONSTANT:
t->data[i].f = s->offset + s->amplitude;
t->data[i].f = s->offset[i] + s->amplitude[i];
break;
case signal_generator::SignalType::SINE:
t->data[i].f = s->offset + s->amplitude * sin(running * s->frequency * 2 * M_PI);
t->data[i].f = s->offset[i] + s->amplitude[i] * sin(running * s->frequency[i] * 2 * M_PI);
break;
case signal_generator::SignalType::TRIANGLE:
t->data[i].f = s->offset + s->amplitude * (fabs(fmod(running * s->frequency, 1) - .5) - 0.25) * 4;
t->data[i].f = s->offset[i] + s->amplitude[i] * (fabs(fmod(running * s->frequency[i], 1) - .5) - 0.25) * 4;
break;
case signal_generator::SignalType::SQUARE:
t->data[i].f = s->offset + s->amplitude * ( (fmod(running * s->frequency, 1) < .5) ? -1 : 1);
t->data[i].f = s->offset[i] + s->amplitude[i] * ( (fmod(running * s->frequency[i], 1) < .5) ? -1 : 1);
break;
case signal_generator::SignalType::RAMP:
t->data[i].f = s->offset + s->amplitude * fmod(running, s->frequency);
t->data[i].f = s->offset[i] + s->amplitude[i] * fmod(running, s->frequency[i]);
break;
case signal_generator::SignalType::COUNTER:
t->data[i].f = s->offset + s->amplitude * s->counter;
t->data[i].f = s->offset[i] + s->amplitude[i] * s->counter;
break;
case signal_generator::SignalType::RANDOM:
s->last[i] += box_muller(0, s->stddev);
s->last[i] += box_muller(0, s->stddev[i]);
t->data[i].f = s->last[i];
break;
@ -275,8 +368,8 @@ char * signal_generator_print(struct node *n)
char *buf = nullptr;
const char *type = signal_generator_type_str(s->type);
strcatf(&buf, "signal=%s, rt=%s, rate=%.2f, values=%d, frequency=%.2f, amplitude=%.2f, stddev=%.2f, offset=%.2f",
type, s->rt ? "yes" : "no", s->rate, s->values, s->frequency, s->amplitude, s->stddev, s->offset);
strcatf(&buf, "signal=%s, rt=%s, rate=%.2f, values=%d",
type, s->rt ? "yes" : "no", s->rate, s->values);
if (s->limit > 0)
strcatf(&buf, ", limit=%d", s->limit);
@ -293,24 +386,6 @@ int signal_generator_poll_fds(struct node *n, int fds[])
return 1;
}
int signal_generator_init(struct node *n)
{
struct signal_generator *s = (struct signal_generator *) n->_vd;
new (&s->task) Task(CLOCK_MONOTONIC);
return 0;
}
int signal_generator_destroy(struct node *n)
{
struct signal_generator *s = (struct signal_generator *) n->_vd;
s->task.~Task();
return 0;
}
static struct plugin p;
__attribute__((constructor(110)))
@ -332,7 +407,6 @@ static void register_plugin() {
p.node.read = signal_generator_read;
p.node.poll_fds = signal_generator_poll_fds;
vlist_init(&p.node.instances);
vlist_push(&plugins, &p);
}