feat: the trigger can ignore a noise band and reject HF before comparing
This commit is contained in:
1 parent
d5a9b3c5d5
commit
d34bff3f03
9 files changed
+99
-16
No files matched your search
+59
-5
@@ -3,11 +3,22 @@
|
||||
|
||||
#include "condition.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace udpscope {
|
||||
|
||||
void EventDetector::configure(const EventCondition& c) noexcept {
|
||||
if (c == cond_) return;
|
||||
void EventDetector::configure(const EventCondition& c, double dt) noexcept {
|
||||
if (c == cond_ && dt == dt_) return;
|
||||
cond_ = c;
|
||||
dt_ = dt;
|
||||
// a = 1 - exp(-2*pi*fc*dt), clamped just under Nyquist so a never exceeds 1.
|
||||
// fc == 0 leaves a == 1, which is a pass-through.
|
||||
pole_a_ = 1.0;
|
||||
if (cond_.hf_fc > 0.0 && dt > 0.0) {
|
||||
const double nyquist = 0.5 / dt;
|
||||
const double fc = cond_.hf_fc < nyquist * 0.99 ? cond_.hf_fc : nyquist * 0.99;
|
||||
pole_a_ = 1.0 - std::exp(-2.0 * 3.14159265358979323846 * fc * dt);
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -20,9 +31,45 @@ void EventDetector::reset() noexcept {
|
||||
inside_ = false;
|
||||
last_cross_s_ = 0.0;
|
||||
dropped_ = false;
|
||||
pole_y_ = 0.0;
|
||||
pole_have_ = false;
|
||||
side_ = 0;
|
||||
}
|
||||
|
||||
double EventDetector::filter(double v) noexcept {
|
||||
// A NaN must stay a NaN and must not poison the state: a dropout is a real
|
||||
// reading here, not an error.
|
||||
if (!std::isfinite(v)) return v;
|
||||
if (!pole_have_) {
|
||||
pole_y_ = v;
|
||||
pole_have_ = true;
|
||||
return pole_y_;
|
||||
}
|
||||
pole_y_ += pole_a_ * (v - pole_y_);
|
||||
return pole_y_;
|
||||
}
|
||||
|
||||
void EventDetector::decide(double v, bool& up, bool& down) noexcept {
|
||||
up = false;
|
||||
down = false;
|
||||
if (cond_.noise_band <= 0.0) {
|
||||
up = crossed_up(v);
|
||||
down = crossed_down(v);
|
||||
return;
|
||||
}
|
||||
// A Schmitt trigger: a sample inside the band decides nothing, and a crossing
|
||||
// is a change between two *decided* sides. Seeding from the undecided side
|
||||
// would fire on a signal that starts inside the band and leaves it without
|
||||
// ever reaching `level`.
|
||||
const int was = side_;
|
||||
if (v >= cond_.level + cond_.noise_band) side_ = 1;
|
||||
else if (v <= cond_.level - cond_.noise_band) side_ = -1;
|
||||
up = was == -1 && side_ == 1;
|
||||
down = was == 1 && side_ == -1;
|
||||
}
|
||||
|
||||
double EventDetector::feed(double value, double t) noexcept {
|
||||
value = filter(value);
|
||||
if (!have_prev_) {
|
||||
prev_ = value;
|
||||
have_prev_ = true;
|
||||
@@ -57,8 +104,9 @@ double EventDetector::feed(double value, double t) noexcept {
|
||||
}
|
||||
|
||||
double EventDetector::feed_edge(double value, double t) noexcept {
|
||||
const bool up = crossed_up(value);
|
||||
const bool down = crossed_down(value);
|
||||
bool up = false;
|
||||
bool down = false;
|
||||
decide(value, up, down);
|
||||
const bool fired = (cond_.edge == TriggerEdge::Rising && up) ||
|
||||
(cond_.edge == TriggerEdge::Falling && down) ||
|
||||
(cond_.edge == TriggerEdge::Both && (up || down));
|
||||
@@ -115,7 +163,13 @@ double EventDetector::feed_pulse(double value, double t) noexcept {
|
||||
double EventDetector::feed_window(double value, double t) noexcept {
|
||||
const double lo = cond_.level < cond_.level2 ? cond_.level : cond_.level2;
|
||||
const double hi = cond_.level < cond_.level2 ? cond_.level2 : cond_.level;
|
||||
const bool inside = value >= lo && value <= hi;
|
||||
// The band is applied on the edge the signal must *leave*, and clamped to just
|
||||
// under half the window so `lo + band` can never pass `hi - band`.
|
||||
double band = cond_.noise_band > 0.0 ? cond_.noise_band : 0.0;
|
||||
const double room = 0.49 * (hi - lo);
|
||||
if (band > room) band = room;
|
||||
const bool inside = inside_ ? (value >= lo - band && value <= hi + band)
|
||||
: (value >= lo + band && value <= hi - band);
|
||||
if (inside == inside_) return kNoEvent;
|
||||
inside_ = inside;
|
||||
// The event is the *change of side*, so `Rising` reads as "into the band" and `Falling`
|
||||
|
||||
Reference in new issue
Block a user