#include <array>
#include <deque>
#include <cmath>
#include <stdexcept>
// ── Configuration ────────────────────────────────────────────────
static constexpr int NUM_SENSORS = 4;
// ── Types ────────────────────────────────────────────────────────
// One timestep: one scalar reading per sensor
struct SensorFrame {
std::array<double, NUM_SENSORS> values;
};
// Sliding window of the N most recent frames
using SensorWindow = std::deque<SensorFrame>;
// ── Core: push a new frame, keeping window size <= N ─────────────
void push_frame(SensorWindow& window, const SensorFrame& frame, int N) {
if (N <= 0) throw std::invalid_argument("N must be positive");
window.push_back(frame);
while (static_cast<int>(window.size()) > N)
window.pop_front();
}
// ── Geometric mean of all values across the entire window ────────
//
// Treats every scalar in the window (all sensors × all timesteps)
// as one flat list and returns the Nth-root product, where
// N = window_size × NUM_SENSORS.
//
// Uses the log-sum trick to avoid overflow/underflow.
double geometric_mean_all(const SensorWindow& window) {
if (window.empty()) throw std::runtime_error("Window is empty");
double log_sum = 0.0;
int count = 0;
for (const auto& frame : window) {
for (double v : frame.values) {
if (v <= 0.0)
throw std::domain_error("Geometric mean requires positive values");
log_sum += std::log(v);
++count;
}
}
return std::exp(log_sum / count);
}
// ── Per-sensor geometric mean across the window ──────────────────
//
// Returns one geometric mean per sensor channel, computed over
// the N timesteps in the window.
std::array<double, NUM_SENSORS>
geometric_mean_per_sensor(const SensorWindow& window) {
if (window.empty()) throw std::runtime_error("Window is empty");
std::array<double, NUM_SENSORS> log_sums{};
log_sums.fill(0.0);
for (const auto& frame : window) {
for (int s = 0; s < NUM_SENSORS; ++s) {
if (frame.values[s] <= 0.0)
throw std::domain_error("Geometric mean requires positive values");
log_sums[s] += std::log(frame.values[s]);
}
}
std::array<double, NUM_SENSORS> result{};
double n = static_cast<double>(window.size());
for (int s = 0; s < NUM_SENSORS; ++s)
result[s] = std::exp(log_sums[s] / n);
return result;
}
int main() {
const int N = 5; // keep last 5 measurements
SensorWindow window;
// Simulate incoming sensor readings
push_frame(window, {{ 1.2, 3.4, 2.1, 0.9 }}, N);
push_frame(window, {{ 1.5, 3.1, 2.4, 1.0 }}, N);
push_frame(window, {{ 1.1, 3.6, 2.0, 1.2 }}, N);
// Global geometric mean (single pseudo-fusion scalar)
double global = geometric_mean_all(window);
// Per-sensor geometric mean (one value per sensor)
auto per_sensor = geometric_mean_per_sensor(window);
return 0;
}