Public Access
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
111 lines
3.5 KiB
C++
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
|