fix fft, waterfall

This commit is contained in:
2026-04-22 22:09:42 +03:00
parent ae532a33cd
commit 77d380acfd
7 changed files with 1016 additions and 396 deletions
+65 -23
View File
@@ -6,7 +6,7 @@ unit Settings;
}
{$mode objfpc}{$H+}
interface
uses SysUtils, Classes, fpJSON, jsonparser, jsonscanner;
uses SysUtils, Classes, Math, fpJSON, jsonparser, jsonscanner;
const
SETTINGS_FILE = 'hpsdr_settings.json';
@@ -53,12 +53,13 @@ type
WindowType: Integer; // 0=Rect,1=BH4,2=Hann,3=FlatTop,4=Hamming,5=Kaiser,6=BH7
SpecDetector: Integer; // 0=Peak,1=Rosenfell,2=Average,3=Sample,4=RMS
SpecAvgMode: Integer; // 0=None,1=Recursive,2=TimeWindow,3=LogRecursive
SpecAvgCount: Integer; // frames to average
SpecBackmult: Double; // 0.0..1.0 recursive averaging multiplier
SpecAvgTimeMS: Double; // averaging time in milliseconds
WfDetector: Integer; // waterfall detector
WfAvgMode: Integer; // waterfall average mode
WfAvgCount: Integer; // waterfall average count
WfBackmult: Double; // waterfall backmult
WfAvgTimeMS: Double; // waterfall averaging time in milliseconds
WfManualHigh: Double; // manual waterfall high threshold
WfManualLow: Double; // manual waterfall low threshold
WfAGCOffset: Double; // AGC offset in dB
SpecRefLevel: Double; // dBm reference (top of scale), e.g. -20
SpecRange: Double; // dB range, e.g. 110 (bottom = ref - range)
SpecGridStep: Double; // grid step in dB, e.g. 10
@@ -70,7 +71,7 @@ type
ShowSpectrum: Boolean; // True = draw spectrum on main form
ShowWaterfall: Boolean; // True = draw waterfall on main form
// --- Display FPS ---
DisplayFPS: Integer; // spectrum/waterfall timer fps (5..30)
DisplayFPS: Integer; // spectrum/waterfall timer fps (1..100)
// --- PA (Power Amplifier) settings ---
PAMaxPower: Double; // максимальная выходная мощность, Вт (5..200)
PABandCal: array[0..CFG_BAND_COUNT-1] of Double; // калибровка на диапазон 38.8..100.0
@@ -117,6 +118,26 @@ type
implementation
function LegacyAverageTimeMS(FPS, AvgMode, AvgCount: Integer;
Backmult, DefaultMS: Double): Double;
var
FPSv: Integer;
begin
if AvgMode <= 0 then
Exit(0.0);
FPSv := EnsureRange(FPS, 1, 100);
if (Backmult > 0.0) and (Backmult < 1.0) then
Result := -1000.0 / (FPSv * Ln(Backmult))
else
Result := (1000.0 * Max(1, AvgCount)) / FPSv;
if IsNan(Result) or IsInfinite(Result) or (Result <= 0.0) then
Result := DefaultMS;
Result := EnsureRange(Result, 10.0, 5000.0);
end;
class function TSettingsManager.MacToStr(const MAC: array of Byte): string;
begin
Result := Format('%02X:%02X:%02X:%02X:%02X:%02X',
@@ -144,20 +165,23 @@ begin
G.Volume := 70; G.DriveLevel := 50; G.ActiveVfo := 0;
G.NRMode := 0; G.NBMode := 0; G.SNBEnabled := False; G.ANFEnabled := False;
G.AGCSlope := 0; G.AGCHangThreshold := 100; G.LastBand := 5;
G.WfAGCEnabled := True;
G.WfNFEnabled := False;
G.SampleRate := 192000;
G.PAMaxPower := 100.0;
for i := 0 to CFG_BAND_COUNT-1 do G.PABandCal[i] := 100.0;
// Display defaults
G.FFTSize := 4096;
G.WindowType := 5; // Kaiser
G.WindowType := 2; // Hann
G.SpecDetector := 0; // Peak
G.SpecAvgMode := 3; // Log Recursive
G.SpecAvgCount := 2;
G.SpecBackmult := 0.45;
G.WfDetector := 2; // Average
G.SpecAvgTimeMS := 30.0;
G.WfDetector := 0; // Peak
G.WfAvgMode := 3; // Log Recursive
G.WfAvgCount := 2;
G.WfBackmult := 0.45;
G.WfAvgTimeMS := 120.0;
G.WfManualHigh := -80.0;
G.WfManualLow := -130.0;
G.WfAGCOffset := 0.0;
G.SpecRefLevel := -20.0;
G.SpecRange := 110.0;
G.SpecGridStep := 10.0;
@@ -307,7 +331,7 @@ begin
G.ANFEnabled := JB(GObj,'anf_enabled',False);
G.AGCSlope := JI(GObj,'agc_slope',0);
G.AGCHangThreshold := JI(GObj,'agc_hang_threshold',100);
G.WfAGCEnabled := JB(GObj,'wf_agc_enabled',False);
G.WfAGCEnabled := JB(GObj,'wf_agc_enabled',True);
G.WfNFEnabled := JB(GObj,'wf_nf_enabled',False);
G.LastBand := JI(GObj,'last_band',5);
G.SampleRate := JI(GObj,'sample_rate',192000);
@@ -315,13 +339,30 @@ begin
G.FFTSize := JI(GObj,'fft_size',4096);
G.WindowType := JI(GObj,'win_type',5);
G.SpecDetector := JI(GObj,'spec_detector',0);
G.SpecAvgMode := JI(GObj,'spec_avg_mode',3);
G.SpecAvgCount := JI(GObj,'spec_avg_count',2);
G.SpecBackmult := JD(GObj,'spec_backmult',0.45);
G.SpecAvgMode := JI(GObj,'spec_avg_mode',0);
if GObj.Find('spec_avg_time_ms') <> nil then
G.SpecAvgTimeMS := JD(GObj,'spec_avg_time_ms',120.0)
else
G.SpecAvgTimeMS := LegacyAverageTimeMS(
JI(GObj,'display_fps',20),
G.SpecAvgMode,
JI(GObj,'spec_avg_count',1),
JD(GObj,'spec_backmult',0.0),
120.0);
G.WfDetector := JI(GObj,'wf_detector',2);
G.WfAvgMode := JI(GObj,'wf_avg_mode',3);
G.WfAvgCount := JI(GObj,'wf_avg_count',2);
G.WfBackmult := JD(GObj,'wf_backmult',0.45);
G.WfAvgMode := JI(GObj,'wf_avg_mode',1);
if GObj.Find('wf_avg_time_ms') <> nil then
G.WfAvgTimeMS := JD(GObj,'wf_avg_time_ms',120.0)
else
G.WfAvgTimeMS := LegacyAverageTimeMS(
JI(GObj,'display_fps',20),
G.WfAvgMode,
JI(GObj,'wf_avg_count',2),
JD(GObj,'wf_backmult',0.25),
120.0);
G.WfManualHigh := JD(GObj,'wf_manual_high',-80.0);
G.WfManualLow := JD(GObj,'wf_manual_low',-130.0);
G.WfAGCOffset := JD(GObj,'wf_agc_offset',0.0);
G.SpecRefLevel := JD(GObj,'spec_ref_level',-20.0);
G.SpecRange := JD(GObj,'spec_range',110.0);
G.SpecGridStep := JD(GObj,'spec_grid_step',10.0);
@@ -376,12 +417,13 @@ begin
JW(O,'win_type',G.WindowType);
JW(O,'spec_detector',G.SpecDetector);
JW(O,'spec_avg_mode',G.SpecAvgMode);
JW(O,'spec_avg_count',G.SpecAvgCount);
JW(O,'spec_backmult',G.SpecBackmult);
JW(O,'spec_avg_time_ms',G.SpecAvgTimeMS);
JW(O,'wf_detector',G.WfDetector);
JW(O,'wf_avg_mode',G.WfAvgMode);
JW(O,'wf_avg_count',G.WfAvgCount);
JW(O,'wf_backmult',G.WfBackmult);
JW(O,'wf_avg_time_ms',G.WfAvgTimeMS);
JW(O,'wf_manual_high',G.WfManualHigh);
JW(O,'wf_manual_low',G.WfManualLow);
JW(O,'wf_agc_offset',G.WfAGCOffset);
JW(O,'spec_ref_level',G.SpecRefLevel);
JW(O,'spec_range',G.SpecRange);
JW(O,'spec_grid_step',G.SpecGridStep);