mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(web): детализация спектра/водопада — честный размер кадра, поток 'W', настройка разрешения
Веб-пульт рисовал заметно грубее десктопа, и часть причин копилась давно. Клиент вообще не разбирал бинарный фрейм 0x57: водопад рисовался из кадра СПЕКТРА, а собственный поток водопада (свой детектор и усреднение wf_avg_time_ms) уходил в никуда, занимая половину трафика. Теперь водопад идёт из своего потока. Адаптер слал константу 1024 вместо реального числа точек. Разрешение анализатора = ширина панадаптера, и при узкой панели (грид из двух колонок, маленькое окно) кадр короче — хвост буфера, нули = 0 dBm, уезжал клиенту белой полосой, а частотная шкала сжималась. В демоне это обходили DAEMON_SPEC_WIDTH. Длина фрейма теперь равна числу заполненных точек; клиент и так считал N из byteLength. Децимация под потолок протокола делила «i*Count div N» — на нецелом отношении соседние группы получались по 1 и 2 точки, а смещение max-детектора зависит от размера группы: по спектру шла гребёнка ±3 дБ, в водопаде — вертикальная рябь. Заменено на целочисленный фактор (группы одинаковой ширины). Водопад терял 2 кадра из 3: анализатор даёт до 60 кадров/с, web шлёт 20 строк/с, а бралась просто «последняя». Введено двухступенчатое накопление max-hold (DSP-поток → PushState → PushLoop) по идиоме TWaterfallView.SetWaterfallData — короткие посылки CW/FT8 больше не проваливаются между строками. Отдельно исправлено в headless: PushState демона (20 Гц) и PushLoop (20 Гц) идут вразнобой, и на дрейфе фаз одна и та же строка уезжала клиенту дважды (водопад двоил и полз рывками), а на остановленном RX прокручивалась застывшая строка. Фрейм 'W' теперь отправляется только при реально пришедшем от DSP кадре (FWfAccumFresh → WfNew → FWfFresh). Спектр так не гейтится — это живая кривая. Рендер в браузере: значение бина для пикселя берётся максимумом по диапазону вместо «ближайшего» (узкие сигналы мерцали и пропадали на узком экране), при бинах реже пикселей — интерполяция; сглаживание спектра вынесено отдельным проходом по всем бинам (в цикле по пикселям часть бинов не обновлялась вовсе); строка водопада рисуется из сырых бинов, IIR ~200 мс остался только для слежения за уровнями AGC — он размазывал водопад по вертикали. Потолок точек кадра вынесен в настройку web.spec_pixels (Settings → Advanced → Web Server → Spectrum: 1024/2048/4096, дефолт 1024). Буферы кадра и WS-фреймы выросли под 4096 (WEB_SPEC_MAX, синхронно с WDSPEngine.SPECTRUM_PIXELS). В демоне эта же настройка задаёт ширину анализатора — рендера там нет, поэтому DAEMON_SPEC_WIDTH убран. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+17
-8
@@ -26,12 +26,11 @@ program ewsdrd;
|
||||
|
||||
uses
|
||||
{$IFDEF UNIX}cthreads, BaseUnix,{$ENDIF}
|
||||
Classes, SysUtils,
|
||||
RadioController, WebServer, WebAdapter,
|
||||
Classes, SysUtils, Math,
|
||||
RadioController, WebServer, WebAdapter, WDSPEngine,
|
||||
HPSDRNetwork, Settings, WDSP, PlatformUtils, DeviceStore, BoardUtils;
|
||||
|
||||
const
|
||||
DAEMON_SPEC_WIDTH = 1024; // ширина спектра для StartRunning (web-буфер = 1024)
|
||||
PUSH_INTERVAL_MS = 50; // период исходящего web-зеркала (как GUI-таймер)
|
||||
|
||||
type
|
||||
@@ -52,6 +51,9 @@ type
|
||||
procedure OnState(Sender: TObject; Field: TRadioField);
|
||||
// WDSP открываем лениво и синхронно (нет UI — блокировать главный поток ок).
|
||||
function EnsureWDSP: Boolean;
|
||||
// Ширина анализатора в демоне: рендера нет, поэтому её задаёт потолок
|
||||
// web-кадра (web.spec_pixels) — ровно столько точек и уйдёт клиенту.
|
||||
function DaemonSpecWidth: Integer;
|
||||
procedure ConnectTo(const Dev: THPSDRDevice);
|
||||
procedure PushDeviceList;
|
||||
procedure PushXvtr;
|
||||
@@ -148,6 +150,7 @@ begin
|
||||
|
||||
// --- Веб-сервер + адаптер ---
|
||||
FCtrl.FSettings.LoadWebSettings(WebCfg);
|
||||
FCtrl.FWebSpecPixels := EnsureRange(WebCfg.SpecPixels, 256, SPECTRUM_PIXELS);
|
||||
FWeb := TWebServer.Create(WebCfg.User, WebCfg.Pass, Word(WebCfg.Port), WebCfg.BindAddr);
|
||||
FWebAd := TWebAdapter.Create(FCtrl, FWeb, nil);
|
||||
// RX-аудио веб-клиенту — через route-хук контроллера (D1).
|
||||
@@ -231,10 +234,16 @@ begin
|
||||
Exit;
|
||||
end;
|
||||
// Ширина анализатора спектра. Без UI её никто не выставляет (GUI зовёт
|
||||
// SetSpectrumWidth(панель) каждый тик), и анализатор отдаёт дефолтные 64 пикселя
|
||||
// → web рисует лишь ~6% ширины, остальное белым. Ставим ровно под web-буфер
|
||||
// (SPECTRUM_PIXELS=1024). FLastSpectrumW переживает пересоздание канала.
|
||||
FCtrl.FDSPEngine.SetSpectrumWidth(DAEMON_SPEC_WIDTH);
|
||||
// SetSpectrumWidth(панель) каждый тик), и анализатор отдал бы дефолтные 64
|
||||
// пикселя. Ставим ровно под потолок web-кадра (web.spec_pixels) — больше
|
||||
// демону не нужно, меньше — обрезало бы настройку.
|
||||
// FLastSpectrumW переживает пересоздание канала.
|
||||
FCtrl.FDSPEngine.SetSpectrumWidth(DaemonSpecWidth);
|
||||
end;
|
||||
|
||||
function THeadlessHost.DaemonSpecWidth: Integer;
|
||||
begin
|
||||
Result := EnsureRange(FCtrl.FWebSpecPixels, 256, SPECTRUM_PIXELS);
|
||||
end;
|
||||
|
||||
procedure THeadlessHost.ConnectTo(const Dev: THPSDRDevice);
|
||||
@@ -242,7 +251,7 @@ begin
|
||||
if FCtrl.FNetwork.Connected then Exit;
|
||||
if not EnsureWDSP then Exit;
|
||||
Log('Connecting to ' + Dev.IPAddress + '...');
|
||||
if FCtrl.ConnectAndRun(Dev, DAEMON_SPEC_WIDTH) then
|
||||
if FCtrl.ConnectAndRun(Dev, DaemonSpecWidth) then
|
||||
Log('Running. Board=' + IntToStr(FCtrl.FNetwork.Device.BoardType))
|
||||
else
|
||||
Log('Connect FAILED: ' + FCtrl.FNetwork.LastError);
|
||||
|
||||
Reference in New Issue
Block a user