mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +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:
+12
-3
@@ -232,6 +232,7 @@ type
|
||||
FWebBindAddr: string;
|
||||
FWebUser: string;
|
||||
FWebPass: string;
|
||||
FWebSpecPixels: Integer; // потолок точек кадра спектра/водопада для web
|
||||
// --- CAT ---
|
||||
FCATAdapter: TCATAdapter; // адаптер CAT поверх контроллера (движок+транспорты+контекст)
|
||||
FCATLastGlobal: TGlobalSettings; // текущие CAT-настройки (UI/persist; ApplySettings → адаптер)
|
||||
@@ -753,7 +754,7 @@ type
|
||||
procedure ApplyWfAGCNF(WfAGC, WfNF: Boolean);
|
||||
procedure ApplyADCSettings(Dither, Random: Boolean);
|
||||
procedure ApplyWebSettings(Enabled: Boolean; Port: Integer;
|
||||
const BindAddr, User, Pass: string);
|
||||
const BindAddr, User, Pass: string; SpecPixels: Integer);
|
||||
procedure ApplyGridParams(RefLevel, Range, GridStep: Double);
|
||||
// Пушит активные grid-параметры (RX или TX в зависимости от FTransmitting)
|
||||
// в FSpecView и сбрасывает кэш сетки. Вызывается при смене RX↔TX и при
|
||||
@@ -1064,6 +1065,8 @@ begin
|
||||
FWebBindAddr := WebCfg.BindAddr;
|
||||
FWebUser := WebCfg.User;
|
||||
FWebPass := WebCfg.Pass;
|
||||
FWebSpecPixels := EnsureRange(WebCfg.SpecPixels, 256, SPECTRUM_PIXELS);
|
||||
FController.FWebSpecPixels := FWebSpecPixels;
|
||||
FWebServer := TWebServer.Create(FWebUser, FWebPass, Word(FWebPort), FWebBindAddr);
|
||||
// Вынесенные в TWebAdapter чистые-контроллерные команды (host=nil: их хендлеры
|
||||
// ещё не нужны хосту; host-зависимые WebOnXxx пока на MainForm — переедут в WA2).
|
||||
@@ -5691,7 +5694,7 @@ begin
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyWebSettings(Enabled: Boolean; Port: Integer;
|
||||
const BindAddr, User, Pass: string);
|
||||
const BindAddr, User, Pass: string; SpecPixels: Integer);
|
||||
var W: TWebSettings;
|
||||
begin
|
||||
FWebEnabled := Enabled;
|
||||
@@ -5699,6 +5702,10 @@ begin
|
||||
FWebBindAddr := BindAddr;
|
||||
FWebUser := User;
|
||||
FWebPass := Pass;
|
||||
// Потолок точек кадра для web — применяется сразу, следующий же кадр DSP
|
||||
// снимается с новым разрешением (переарм анализатора не нужен).
|
||||
FWebSpecPixels := EnsureRange(SpecPixels, 256, SPECTRUM_PIXELS);
|
||||
FController.FWebSpecPixels := FWebSpecPixels;
|
||||
FWebServer.Reconfigure(User, Pass, BindAddr, Word(Port));
|
||||
if Enabled then FWebServer.Start;
|
||||
W.Enabled := Enabled;
|
||||
@@ -5706,6 +5713,7 @@ begin
|
||||
W.BindAddr := BindAddr;
|
||||
W.User := User;
|
||||
W.Pass := Pass;
|
||||
W.SpecPixels := FWebSpecPixels;
|
||||
FController.FSettings.SaveWebSettings(W);
|
||||
end;
|
||||
|
||||
@@ -8559,7 +8567,8 @@ begin
|
||||
FController.FDisplayPixels, FController.FWfSpeedDiv);
|
||||
SF.LoadSpecMSAA(FController.FSpecMSAA);
|
||||
SF.LoadADCSettings(FController.FDitherEnabled, FController.FRandomEnabled);
|
||||
SF.LoadWebSettings(FWebEnabled, FWebPort, FWebBindAddr, FWebUser, FWebPass);
|
||||
SF.LoadWebSettings(FWebEnabled, FWebPort, FWebBindAddr, FWebUser, FWebPass,
|
||||
FWebSpecPixels);
|
||||
SF.LoadFPS(FDisplayFPS);
|
||||
SF.LoadLightTheme(FLightTheme);
|
||||
SF.LoadFreqMhzDigits(FFreqMhzDigits);
|
||||
|
||||
Reference in New Issue
Block a user