Files
roro9stack/src/services/noise_test.cpp
T
twislaandClaude Opus 5.5 70fb37ebb5 The radio's noise: the GNSS receiver costs 8 dB; a setting pauses it (#20)
Debug Builds: `lora noise test` changes one thing at a time, Sweeps the
band, and reports the floor under each condition; it runs on the device
by itself, since one condition pauses Wi-Fi (not saved, so a restart
brings it back). Result, at 125 kHz: -117 dBm with the antenna switched
off, -106 with the GNSS receiver in standby, -98 with it running. The
receiver's serial line isn't it (one sentence a second changes nothing),
and neither are the main loop, the CPU frequency, Wi-Fi, the screen or
the radio's own regulator, all within 1 dB.

Settings > "Pause GNSS for LoRa", off by default: the receiver waits in
standby while the radio listens or sweeps, except during a Track, and
has a Fix again about 7 s after. The GNSS App says it's paused.

11 dB remain between the antenna with GNSS quiet and the chip alone,
untouched by anything that can be switched from the firmware.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
2026-10-06 03:41:15 +02:00

111 lines
3.5 KiB
C++

#ifdef RORO_DEBUG
#include "services/noise_test.h"
#include <Arduino.h>
#include <algorithm>
#include <cstdio>
#include "platform/console.h"
#include "sweep_view.h"
namespace roro {
void NoiseTest::start(std::vector<Condition> conditions, int passes) {
if (running()) return;
conditions_ = std::move(conditions);
results_.clear();
report_.clear();
passes_ = passes;
index_ = 0;
console.printf("noise test: %u conditions, %d passes each\n", (unsigned)conditions_.size(), passes_);
begin(millis());
}
void NoiseTest::begin(uint32_t nowMs) {
const Condition& c = conditions_[index_];
if (c.apply) c.apply();
radio_.sweep(true); // sets the radio up again, with whatever the condition changed
std::fill(std::begin(lowest_), std::end(lowest_), 0);
std::fill(std::begin(counts_), std::end(counts_), 0);
seen_ = 0;
phase_ = Phase::Settle;
phaseMs_ = nowMs;
}
void NoiseTest::step(uint32_t nowMs) {
if (phase_ == Phase::Idle) return;
const Condition& c = conditions_[index_];
if (phase_ == Phase::Settle) {
if (nowMs - phaseMs_ < c.settleMs) return;
lastSeq_ = radio_.sweeps();
phase_ = Phase::Sweep;
phaseMs_ = nowMs;
return;
}
SweepFrame f;
if (radio_.sweeps() != lastSeq_ && radio_.sweepFrame(f)) {
lastSeq_ = f.seq;
fromHz_ = f.fromHz, stepHz_ = f.stepHz, steps_ = f.steps;
for (uint16_t i = 0; i < f.steps; i++) {
lowest_[i] = seen_ ? std::min(lowest_[i], f.dbm[i]) : f.dbm[i];
counts_[std::clamp<int>(-f.dbm[i], 0, 127)]++;
}
seen_++;
}
bool stuck = nowMs - phaseMs_ > 20000; // the radio never swept: don't hang the test
if (seen_ < passes_ && !stuck) return;
Result r;
r.name = c.name;
if (seen_) {
// The floor: the median of every reading. The top and the peaks: from the lowest reading
// at each step, so a burst in one pass doesn't count and a steady carrier does.
uint32_t total = 0, half = static_cast<uint32_t>(seen_) * steps_ / 2;
for (int level = 127; level >= 0; level--) {
total += counts_[level];
if (total > half) {
r.floor = -level;
break;
}
}
lora::SweepStats st = lora::summarize(lowest_, steps_, fromHz_, stepHz_);
r.top = st.top;
char p[32];
for (auto& peak : st.peaks) {
std::snprintf(p, sizeof p, "%s%.1f %d", r.peaks.empty() ? "" : ", ", peak.hz / 1e6, peak.dbm);
r.peaks += p;
}
} else {
r.name += " (no sweep)";
}
results_.push_back(r);
radio_.sweep(false);
if (c.restore) c.restore();
if (++index_ < conditions_.size()) begin(nowMs);
else finish();
}
void NoiseTest::finish() {
phase_ = Phase::Idle;
char line[160];
report_.push_back("noise test: floor = median of every reading; top and peaks = steady (lowest of the passes), dBm at 125 kHz");
for (auto& r : results_) {
std::snprintf(line, sizeof line, "noise test: %-26s floor %4d top %4d %s", r.name.c_str(), r.floor, r.top,
r.peaks.empty() ? "no steady peak" : r.peaks.c_str());
report_.push_back(line);
}
report_.push_back("noise test: done");
printReport(console);
}
void NoiseTest::printReport(Print& out) const {
if (report_.empty()) return (void)out.println(running() ? "noise test: still running" : "noise test: none run yet");
for (auto& l : report_) out.println(l.c_str());
}
} // namespace roro
#endif // RORO_DEBUG