#include "fgc/SettleRule.h" #include namespace fgc { SettleRule::Verdict SettleRule::add(const FrameStats& f) { if (f.brightness < 0) { window_.clear(); return Verdict::Waiting; } window_.push_back(f); const size_t n = p_.frames < 1 ? 1 : static_cast(p_.frames); while (window_.size() > n) window_.pop_front(); if (window_.size() < n || !steady()) return Verdict::Waiting; bool in_band = true; for (const auto& w : window_) in_band = in_band && w.brightness >= bandLow() && w.brightness <= bandHigh(); if (in_band) return Verdict::Settled; return atLimit() ? Verdict::AtLimit : Verdict::Waiting; } bool SettleRule::steady() const { for (size_t i = 1; i < window_.size(); ++i) { const double a = window_[i - 1].brightness, b = window_[i].brightness; if (std::fabs(b - a) > p_.steady * std::fmax(a, 1.0)) return false; } return true; } bool SettleRule::atLimit() const { const FrameStats& f = window_.back(); if (f.exposure_us < 0 || f.gain_db < 0) return false; // A hair of slack: the camera reports quantised exposure and gain. if (f.brightness < bandLow() && p_.exposure_max_us > 0 && p_.gain_max_db >= 0) return f.exposure_us >= p_.exposure_max_us * 0.99 && f.gain_db >= p_.gain_max_db - 0.1; if (f.brightness > bandHigh() && p_.exposure_min_us > 0 && p_.gain_min_db >= 0) return f.exposure_us <= p_.exposure_min_us * 1.01 && f.gain_db <= p_.gain_min_db + 0.1; return false; } } // namespace fgc