From f0da62b8f0239cb374217b7db4eb593b03111dd9 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Tue, 13 Jul 2021 11:22:40 +0200 Subject: [PATCH 1/7] stats: fix initialization of sub-hooks --- lib/hook.cpp | 1 + lib/hooks/stats.cpp | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/hook.cpp b/lib/hook.cpp index 287ca87aa..7072a9b91 100644 --- a/lib/hook.cpp +++ b/lib/hook.cpp @@ -39,6 +39,7 @@ using namespace villas; using namespace villas::node; Hook::Hook(struct vpath *p, struct vnode *n, int fl, int prio, bool en) : + logger(logging.get("hook")), state(State::INITIALIZED), flags(fl), priority(prio), diff --git a/lib/hooks/stats.cpp b/lib/hooks/stats.cpp index 9d4799ecf..01c8ea694 100644 --- a/lib/hooks/stats.cpp +++ b/lib/hooks/stats.cpp @@ -48,16 +48,17 @@ public: Hook(p, n, fl, prio, en), parent(pa) { - state = State::CHECKED; + /* This hook has no config. We never call parse() for it */ + state = State::PARSED; } - virtual Hook::Reason process(sample *smp); + virtual Hook::Reason process(struct sample *smp); }; class StatsReadHook : public Hook { protected: - sample *last; + struct sample *last; StatsHook *parent; @@ -67,7 +68,8 @@ public: last(nullptr), parent(pa) { - state = State::CHECKED; + /* This hook has no config. We never call parse() for it */ + state = State::PARSED; } virtual void start() @@ -238,7 +240,7 @@ public: } }; -Hook::Reason StatsWriteHook::process(sample *smp) +Hook::Reason StatsWriteHook::process(struct sample *smp) { timespec now = time_now(); @@ -247,7 +249,7 @@ Hook::Reason StatsWriteHook::process(sample *smp) return Reason::OK; } -Hook::Reason StatsReadHook::process(sample *smp) +Hook::Reason StatsReadHook::process(struct sample *smp) { if (last) { if (smp->flags & last->flags & (int) SampleFlags::HAS_TS_RECEIVED) From b73a45e580140f571ae7a89b858f738cf88cb082 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 9 Jul 2021 15:33:42 +0200 Subject: [PATCH 2/7] update VILLAScommon submodule --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index d818bcab5..dd9304ca0 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit d818bcab55d47dbd30ccd59f63d467b2786323be +Subproject commit dd9304ca059efffe053b74159ca32b16a5eb4597 From 5645753879775477176de5ea9a427261a0c4e925 Mon Sep 17 00:00:00 2001 From: Manuel Pitz Date: Mon, 12 Jul 2021 17:51:09 +0200 Subject: [PATCH 3/7] fix mapping of dft output values --- lib/hooks/dft.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/hooks/dft.cpp b/lib/hooks/dft.cpp index 1d822be77..3853b11a0 100644 --- a/lib/hooks/dft.cpp +++ b/lib/hooks/dft.cpp @@ -180,9 +180,9 @@ public: struct signal *rocofSig; /* Add signals */ - freqSig = signal_create("amplitude", "V", SignalType::FLOAT); - amplSig = signal_create("phase", "rad", SignalType::FLOAT); - phaseSig = signal_create("frequency", "Hz", SignalType::FLOAT); + freqSig = signal_create("frequency", "Hz", SignalType::FLOAT); + amplSig = signal_create("amplitude", "V", SignalType::FLOAT); + phaseSig = signal_create("phase", "rad", SignalType::FLOAT); rocofSig = signal_create("rocof", "Hz/s", SignalType::FLOAT); if (!freqSig || !amplSig || !phaseSig || !rocofSig) From b7f00fe18bfd2d0d93e6b17f1c79205d81d8a367 Mon Sep 17 00:00:00 2001 From: Manuel Pitz Date: Mon, 12 Jul 2021 17:52:27 +0200 Subject: [PATCH 4/7] revert to very simple pps time sync --- lib/hooks/pps_ts.cpp | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/hooks/pps_ts.cpp b/lib/hooks/pps_ts.cpp index 5f7c9463e..2aa18d9f3 100644 --- a/lib/hooks/pps_ts.cpp +++ b/lib/hooks/pps_ts.cpp @@ -85,9 +85,12 @@ public: SingleSignalHook::parse(json); double fSmps = 0; - ret = json_unpack_ex(json, &err, 0, "{ s?: f, s: F }", + ret = json_unpack_ex(json, &err, 0, "{ s?: f, s: F, s?: i, s?: i }", "threshold", &threshold, - "expected_smp_rate", &fSmps + "expected_smp_rate", &fSmps, + "horizon_estimation", &horizonEstimation, + "horizon_compensation", &horizonCompensation + ); if (ret) throw ConfigError(json, err, "node-config-hook-pps_ts"); @@ -99,7 +102,42 @@ public: state = State::PARSED; } + virtual villas::node::Hook::Reason process(sample *smp) + { + assert(state == State::STARTED); + /* Get value of PPS signal */ + float value = smp->data[signalIndex].f; // TODO check if it is really float + /* Detect Edge */ + bool isEdge = lastValue < threshold && value > threshold; + lastValue = value; + if (isEdge) { + tsVirt.tv_sec = time(nullptr); + tsVirt.tv_nsec = 0; + period = 1.0 / cntSmps; + cntSmps = 0; + cntEdges++; + } else { + struct timespec tsPeriod = time_from_double(period); + tsVirt = time_add(&tsVirt, &tsPeriod); + } + + cntSmps++; + + if (cntEdges < 5) + return Hook::Reason::SKIP_SAMPLE; + + smp->ts.origin = tsVirt; + smp->flags |= (int) SampleFlags::HAS_TS_ORIGIN; + + if ((smp->sequence - lastSequence) > 1) + logger->warn("Samples missed: {} sampled missed", smp->sequence - lastSequence); + + lastSequence = smp->sequence; + return Hook::Reason::OK; + } + + virtual villas::node::Hook::Reason process_bak(sample *smp) { assert(state == State::STARTED); From 7a61f509ea820abe75d1d76ac140d62bb58c9c38 Mon Sep 17 00:00:00 2001 From: Manuel Pitz Date: Mon, 19 Jul 2021 12:09:07 +0200 Subject: [PATCH 5/7] dft: add angle unit select (degree/rad) --- lib/hooks/dft.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/hooks/dft.cpp b/lib/hooks/dft.cpp index 3853b11a0..2a76adb48 100644 --- a/lib/hooks/dft.cpp +++ b/lib/hooks/dft.cpp @@ -122,6 +122,8 @@ protected: Dumper phasorAmplitude; Dumper phasorFreq; + double angleUnitFactor; + public: DftHook(struct vpath *p, struct vnode *n, int fl, int prio, bool en = true) : MultiSignalHook(p, n, fl, prio, en), @@ -164,7 +166,8 @@ public: phasorRocof(dumperPrefix + "phasorRocof"), phasorPhase(dumperPrefix + "phasorPhase"), phasorAmplitude(dumperPrefix + "phasorAmplitude"), - phasorFreq(dumperPrefix + "phasorFreq") + phasorFreq(dumperPrefix + "phasorFreq"), + angleUnitFactor(1) { } virtual void prepare() @@ -242,6 +245,7 @@ public: const char *paddingTypeC = nullptr; const char *windowTypeC = nullptr; const char *freqEstimateTypeC = nullptr; + const char *angleUnitC = nullptr; json_error_t err; @@ -249,7 +253,7 @@ public: Hook::parse(json); - ret = json_unpack_ex(json, &err, 0, "{ s?: i, s?: F, s?: F, s?: F, s?: i , s?: i, s?: s, s?: s, s?: s, s?: b, s?: i }", + ret = json_unpack_ex(json, &err, 0, "{ s?: i, s?: F, s?: F, s?: F, s?: i , s?: i, s?: s, s?: s, s?: s, s?: b, s?: i, s?: s}", "sample_rate", &sampleRate, "start_freqency", &startFrequency, "end_freqency", &endFreqency, @@ -260,7 +264,8 @@ public: "padding_type", &paddingTypeC, "freq_estimate_type", &freqEstimateTypeC, "sync", &sync, - "pps_index", &ppsIndex + "pps_index", &ppsIndex, + "angle_unit", &angleUnitC ); if (ret) throw ConfigError(json, err, "node-config-hook-dft"); @@ -279,6 +284,15 @@ public: else throw ConfigError(json, "node-config-hook-dft-window-type", "Invalid window type: {}", windowTypeC); + if (!angleUnitC) + logger->info("No angle type given, assume rad"); + else if (strcmp(angleUnitC, "rad") == 0) + angleUnitFactor = 1; + else if (strcmp(angleUnitC, "degree") == 0) + angleUnitFactor = 180 / M_PI; + else + throw ConfigError(json, "node-config-hook-dft-angle-unit", "Angle unit {} not recognized", angleUnitC); + if (!paddingTypeC) logger->info("No Padding type given, assume no zeropadding"); else if (strcmp(paddingTypeC, "signal_repeat") == 0) @@ -384,7 +398,7 @@ public: smp->data[i * 4 + 0].f = currentResult.frequency; /* Frequency */ smp->data[i * 4 + 1].f = (currentResult.amplitude / pow(2, 0.5)); /* Amplitude */ - smp->data[i * 4 + 2].f = atan2(results[i][maxPos].imag(), results[i][maxPos].real()); /* Phase */ + smp->data[i * 4 + 2].f = atan2(results[i][maxPos].imag(), results[i][maxPos].real()) * angleUnitFactor; /* Phase */ smp->data[i * 4 + 3].f = (currentResult.frequency - lastResult.frequency) / (double)rate; /* RoCof */ } From 1509939a408e7d1542bf07cd4edb85fddf132a0c Mon Sep 17 00:00:00 2001 From: Manuel Pitz Date: Mon, 19 Jul 2021 12:09:37 +0200 Subject: [PATCH 6/7] dft: add missing padding type --- lib/hooks/dft.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/hooks/dft.cpp b/lib/hooks/dft.cpp index 2a76adb48..b23869f19 100644 --- a/lib/hooks/dft.cpp +++ b/lib/hooks/dft.cpp @@ -295,6 +295,8 @@ public: if (!paddingTypeC) logger->info("No Padding type given, assume no zeropadding"); + else if (strcmp(paddingTypeC, "zero") == 0) + paddingType = PaddingType::ZERO; else if (strcmp(paddingTypeC, "signal_repeat") == 0) paddingType = PaddingType::SIG_REPEAT; else From 2fc0781811f80cbe5fd35b78d16bbe2bde384c93 Mon Sep 17 00:00:00 2001 From: Manuel Pitz Date: Mon, 19 Jul 2021 12:12:26 +0200 Subject: [PATCH 7/7] formats: add specific json format for edgeFlex --- include/villas/formats/json_edgeflex.hpp | 40 +++++++++++++++ lib/formats/CMakeLists.txt | 1 + lib/formats/json_edgeflex.cpp | 62 ++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 include/villas/formats/json_edgeflex.hpp create mode 100644 lib/formats/json_edgeflex.cpp diff --git a/include/villas/formats/json_edgeflex.hpp b/include/villas/formats/json_edgeflex.hpp new file mode 100644 index 000000000..5a83f26aa --- /dev/null +++ b/include/villas/formats/json_edgeflex.hpp @@ -0,0 +1,40 @@ +/** JSON serializtion for edgeFlex project. + * + * @author Manuel Pitz + * @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#pragma once + +#include + +namespace villas { +namespace node { + +class JsonEdgeflexFormat : public JsonFormat { + +protected: + int packSample(json_t **j, const struct sample *smp); + +public: + using JsonFormat::JsonFormat; +}; + +} /* namespace node */ +} /* namespace villas */ diff --git a/lib/formats/CMakeLists.txt b/lib/formats/CMakeLists.txt index 8200305b2..8b973764b 100644 --- a/lib/formats/CMakeLists.txt +++ b/lib/formats/CMakeLists.txt @@ -62,6 +62,7 @@ endif() list(APPEND FORMAT_SRC column.cpp iotagent_ul.cpp + json_edgeflex.cpp json_kafka.cpp json_reserve.cpp json.cpp diff --git a/lib/formats/json_edgeflex.cpp b/lib/formats/json_edgeflex.cpp new file mode 100644 index 000000000..6e3c8cdab --- /dev/null +++ b/lib/formats/json_edgeflex.cpp @@ -0,0 +1,62 @@ +/** JSON serializtion for edgeFlex project. + * + * @author Manuel Pitz + * @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include + +#include +#include + +using namespace villas::node; + +int JsonEdgeflexFormat::packSample(json_t **json_smp, const struct sample *smp) +{ + json_error_t err; + json_t *json_value; + json_t *json_created = nullptr; + + if (smp->flags & (int) SampleFlags::HAS_TS_ORIGIN) + json_created = json_integer(time_to_double(&smp->ts.origin) * 1e3); + + + struct signal *sig = (struct signal *) vlist_at_safe(smp->signals, 0); + if (!sig) + return -1; + + + json_value = json_pack_ex(&err, 0, "{ s: f }", + "value", smp->data[0].f + ); + + if (json_created) + json_object_set_new(json_value, "created", json_created); + + if (json_value == nullptr) + return -1; + + *json_smp = json_value; + + return 0; +} + +static char n[] = "json.edgeflex"; +static char d[] = "EdgeFlex JSON format"; +static FormatPlugin p;