[fix](trx-frontend-http): measure auto squelch from the meter
Auto took the spectrum's noise floor and added 6 dB, but the threshold is compared against the channel level the meter reports, and the two sit a long way apart: the gap is set by the FFT size and window, the channel bandwidth, the decimation, and peak-versus-mean statistics. Measured on white noise it runs +22.1 dB at 48k/8k/3k, +18.7 dB at 240k/24k/12k and -1.2 dB at 1.92M/24k/12k — a 23 dB swing across ordinary configurations. Only the last of those is anywhere near right, so on a narrow span Auto set the gate some 20 dB below the noise and it never closed. It now reads the same number the DSP compares: the 20th percentile of the meter over the last ten seconds, plus 5 dB. The percentile keeps a burst of traffic inside the window from dragging the estimate up, and 5 dB clears the meter's own jitter, which measured 0.9-1.6 dB. Nothing in it converts between scales, so no part of the signal chain can put it out again. With no history yet — a fresh connection, a rig switch — it listens for a moment rather than refusing. The fixture gained a streaming /meter, without which there is nothing to measure, and the spectrum test pins auto to the meter it serves. Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -35,11 +35,16 @@ const BANDPLAN = {
|
||||
const BAND_WITH_CONTENT = 7074000;
|
||||
const BAND_WITHOUT_CONTENT = 14074000;
|
||||
|
||||
// The meter sits well away from the spectrum's noise floor, so a squelch that
|
||||
// took its level from the plot would land somewhere else entirely.
|
||||
const METER_DB = -70;
|
||||
|
||||
const fixture = await startWebFixture({
|
||||
spectrum: true,
|
||||
bookmarks: BOOKMARKS,
|
||||
bandplan: BANDPLAN,
|
||||
bandplanEnabled: true,
|
||||
meterDb: METER_DB,
|
||||
});
|
||||
const { browser, page, runtimeErrors } = await startBrowser(chromium);
|
||||
|
||||
@@ -125,10 +130,14 @@ try {
|
||||
// row, with nothing on screen to relate the number to.
|
||||
await page.locator("summary", { hasText: "Audio controls" }).click();
|
||||
await page.locator("#sdr-squelch-toggle").click();
|
||||
// Auto parks it just above the noise, which is mid-axis and leaves room to
|
||||
// drag in either direction.
|
||||
// Auto parks it just above the noise the meter reports — not above the
|
||||
// spectrum's noise floor, which sits anywhere from 1 dB below to 22 dB above
|
||||
// the meter depending on span, bandwidth and decimation.
|
||||
await page.locator("#sdr-squelch-auto").click();
|
||||
await page.waitForTimeout(300);
|
||||
await page.waitForTimeout(400);
|
||||
const auto = await page.evaluate(() => Number(document.getElementById("sdr-squelch-db").value));
|
||||
assert.ok(Math.abs(auto - (METER_DB + 5)) <= 1,
|
||||
`auto put the threshold at ${auto} dB with the meter at ${METER_DB} dB`);
|
||||
const squelchOn = await page.evaluate(() => {
|
||||
const line = document.getElementById("spectrum-squelch-line");
|
||||
return {
|
||||
|
||||
@@ -64,6 +64,7 @@ function assetPath(urlPath) {
|
||||
export async function startWebFixture({
|
||||
spectrum = false,
|
||||
tx = false,
|
||||
meterDb = -70,
|
||||
bookmarks = [],
|
||||
bandplan = {},
|
||||
bandplanEnabled = false,
|
||||
@@ -111,7 +112,7 @@ export async function startWebFixture({
|
||||
signal_meter: spectrum,
|
||||
},
|
||||
},
|
||||
status: { freq: { hz: 100_000_000 }, mode: "FM", tx_en: false, vfo: null, tx: null, rx: { sig: -70 }, lock: null },
|
||||
status: { freq: { hz: 100_000_000 }, mode: "FM", tx_en: false, vfo: null, tx: null, rx: { sig: meterDb }, lock: null },
|
||||
// Reported only by SDR backends, and what makes the client show the
|
||||
// squelch control at all.
|
||||
filter: spectrum
|
||||
@@ -213,6 +214,20 @@ export async function startWebFixture({
|
||||
request.on("close", () => clearInterval(timer));
|
||||
return;
|
||||
}
|
||||
// The meter streams like the server's does: the squelch reads its noise
|
||||
// level from here, so a static snapshot would leave it nothing to measure.
|
||||
if (url.pathname === "/meter") {
|
||||
response.writeHead(200, {
|
||||
"cache-control": "no-cache",
|
||||
connection: "keep-alive",
|
||||
"content-type": "text/event-stream",
|
||||
});
|
||||
const timer = setInterval(() => {
|
||||
response.write(`data: ${JSON.stringify({ sig: meterDb })}\n\n`);
|
||||
}, 120);
|
||||
request.on("close", () => clearInterval(timer));
|
||||
return;
|
||||
}
|
||||
if (["/events", "/decode", "/spectrum", "/meter"].includes(url.pathname)) {
|
||||
response.writeHead(200, {
|
||||
"cache-control": "no-cache",
|
||||
|
||||
Reference in New Issue
Block a user