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:
parent
d96afb3b13
commit
bfe60465f5
2 changed files with 121 additions and 47 deletions
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue