mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(dmr): calibrate slicer from sync symbols
This commit is contained in:
+45
-7
@@ -108,12 +108,15 @@ type
|
|||||||
FOuterLevel: array[0..DMR_SAMPLES_PER_SYM - 1] of Double;
|
FOuterLevel: array[0..DMR_SAMPLES_PER_SYM - 1] of Double;
|
||||||
FDibitHistory: array[0..DMR_SAMPLES_PER_SYM - 1,
|
FDibitHistory: array[0..DMR_SAMPLES_PER_SYM - 1,
|
||||||
0..DMR_SYNC_END_DIBIT] of Byte;
|
0..DMR_SYNC_END_DIBIT] of Byte;
|
||||||
|
FSymbolHistory: array[0..DMR_SAMPLES_PER_SYM - 1,
|
||||||
|
0..DMR_SYNC_END_DIBIT] of Double;
|
||||||
FHistoryPos: array[0..DMR_SAMPLES_PER_SYM - 1] of Integer;
|
FHistoryPos: array[0..DMR_SAMPLES_PER_SYM - 1] of Integer;
|
||||||
FHistoryCount: array[0..DMR_SAMPLES_PER_SYM - 1] of Integer;
|
FHistoryCount: array[0..DMR_SAMPLES_PER_SYM - 1] of Integer;
|
||||||
FMagHistory: array[0..DMR_SAMPLES_PER_SYM - 1, 0..23] of Double;
|
FMagHistory: array[0..DMR_SAMPLES_PER_SYM - 1, 0..23] of Double;
|
||||||
FMagPos: array[0..DMR_SAMPLES_PER_SYM - 1] of Integer;
|
FMagPos: array[0..DMR_SAMPLES_PER_SYM - 1] of Integer;
|
||||||
FMagSum: array[0..DMR_SAMPLES_PER_SYM - 1] of Double;
|
FMagSum: array[0..DMR_SAMPLES_PER_SYM - 1] of Double;
|
||||||
FBestSyncQuality: Double;
|
FBestSyncQuality: Double;
|
||||||
|
FFixedOuterLevel: Double;
|
||||||
FTrackPhase: Integer;
|
FTrackPhase: Integer;
|
||||||
FCurrentBurst: TDMRDibitBurst;
|
FCurrentBurst: TDMRDibitBurst;
|
||||||
FCurrentBurstPos: Integer;
|
FCurrentBurstPos: Integer;
|
||||||
@@ -150,6 +153,8 @@ type
|
|||||||
procedure NoteSync(Phase: Integer; Kind: TDMRSyncKind; Inverted: Boolean);
|
procedure NoteSync(Phase: Integer; Kind: TDMRSyncKind; Inverted: Boolean);
|
||||||
procedure LoseSync;
|
procedure LoseSync;
|
||||||
function Digitize(Phase: Integer; Symbol: Double): Byte;
|
function Digitize(Phase: Integer; Symbol: Double): Byte;
|
||||||
|
function SliceSymbol(Symbol, OuterLevel: Double): Byte;
|
||||||
|
function SyncEyeOpening(Phase: Integer): Double;
|
||||||
procedure StartBurstTracking(Phase: Integer);
|
procedure StartBurstTracking(Phase: Integer);
|
||||||
procedure CompleteBurst;
|
procedure CompleteBurst;
|
||||||
procedure DecodeVoiceBurst;
|
procedure DecodeVoiceBurst;
|
||||||
@@ -302,12 +307,14 @@ begin
|
|||||||
FillChar(FSyncShift, SizeOf(FSyncShift), 0);
|
FillChar(FSyncShift, SizeOf(FSyncShift), 0);
|
||||||
FillChar(FOuterLevel, SizeOf(FOuterLevel), 0);
|
FillChar(FOuterLevel, SizeOf(FOuterLevel), 0);
|
||||||
FillChar(FDibitHistory, SizeOf(FDibitHistory), 0);
|
FillChar(FDibitHistory, SizeOf(FDibitHistory), 0);
|
||||||
|
FillChar(FSymbolHistory, SizeOf(FSymbolHistory), 0);
|
||||||
FillChar(FHistoryPos, SizeOf(FHistoryPos), 0);
|
FillChar(FHistoryPos, SizeOf(FHistoryPos), 0);
|
||||||
FillChar(FHistoryCount, SizeOf(FHistoryCount), 0);
|
FillChar(FHistoryCount, SizeOf(FHistoryCount), 0);
|
||||||
FillChar(FMagHistory, SizeOf(FMagHistory), 0);
|
FillChar(FMagHistory, SizeOf(FMagHistory), 0);
|
||||||
FillChar(FMagPos, SizeOf(FMagPos), 0);
|
FillChar(FMagPos, SizeOf(FMagPos), 0);
|
||||||
FillChar(FMagSum, SizeOf(FMagSum), 0);
|
FillChar(FMagSum, SizeOf(FMagSum), 0);
|
||||||
FBestSyncQuality := 0;
|
FBestSyncQuality := 0;
|
||||||
|
FFixedOuterLevel := 0;
|
||||||
FillChar(FCurrentBurst, SizeOf(FCurrentBurst), 0);
|
FillChar(FCurrentBurst, SizeOf(FCurrentBurst), 0);
|
||||||
FillChar(FLastBurst, SizeOf(FLastBurst), 0);
|
FillChar(FLastBurst, SizeOf(FLastBurst), 0);
|
||||||
FillChar(FLastBurstInfo, SizeOf(FLastBurstInfo), 0);
|
FillChar(FLastBurstInfo, SizeOf(FLastBurstInfo), 0);
|
||||||
@@ -456,6 +463,7 @@ begin
|
|||||||
// Keep the 90 dibits ending at sync. Once the timing phase is selected this
|
// Keep the 90 dibits ending at sync. Once the timing phase is selected this
|
||||||
// supplies burst positions 0..89 without waiting for another frame.
|
// supplies burst positions 0..89 without waiting for another frame.
|
||||||
FDibitHistory[Phase, FHistoryPos[Phase]] := Dibit;
|
FDibitHistory[Phase, FHistoryPos[Phase]] := Dibit;
|
||||||
|
FSymbolHistory[Phase, FHistoryPos[Phase]] := V;
|
||||||
FHistoryPos[Phase] := (FHistoryPos[Phase] + 1) mod (DMR_SYNC_END_DIBIT + 1);
|
FHistoryPos[Phase] := (FHistoryPos[Phase] + 1) mod (DMR_SYNC_END_DIBIT + 1);
|
||||||
if FHistoryCount[Phase] < DMR_SYNC_END_DIBIT + 1 then Inc(FHistoryCount[Phase]);
|
if FHistoryCount[Phase] < DMR_SYNC_END_DIBIT + 1 then Inc(FHistoryCount[Phase]);
|
||||||
|
|
||||||
@@ -571,21 +579,33 @@ begin
|
|||||||
end;
|
end;
|
||||||
FTrackPhase := -1;
|
FTrackPhase := -1;
|
||||||
FCurrentBurstPos := 0;
|
FCurrentBurstPos := 0;
|
||||||
|
FFixedOuterLevel := 0;
|
||||||
FMobileActiveBurst := True;
|
FMobileActiveBurst := True;
|
||||||
DMRMbeReset(FMbe);
|
DMRMbeReset(FMbe);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDMRDecoder.Digitize(Phase: Integer; Symbol: Double): Byte;
|
function TDMRDecoder.Digitize(Phase: Integer; Symbol: Double): Byte;
|
||||||
var
|
var
|
||||||
A, Threshold: Double;
|
A: Double;
|
||||||
begin
|
begin
|
||||||
|
if (Phase = FTrackPhase) and (FFixedOuterLevel > 1.0e-9) then
|
||||||
|
Exit(SliceSymbol(Symbol, FFixedOuterLevel));
|
||||||
|
|
||||||
A := Abs(Symbol);
|
A := Abs(Symbol);
|
||||||
if FOuterLevel[Phase] <= 1.0e-9 then FOuterLevel[Phase] := A
|
if FOuterLevel[Phase] <= 1.0e-9 then FOuterLevel[Phase] := A
|
||||||
else if A > FOuterLevel[Phase] then
|
else if A > FOuterLevel[Phase] then
|
||||||
FOuterLevel[Phase] := A
|
FOuterLevel[Phase] := A
|
||||||
else
|
else
|
||||||
FOuterLevel[Phase] := FOuterLevel[Phase] + 0.001 * (A - FOuterLevel[Phase]);
|
FOuterLevel[Phase] := FOuterLevel[Phase] + 0.001 * (A - FOuterLevel[Phase]);
|
||||||
Threshold := 0.625 * FOuterLevel[Phase];
|
Result := SliceSymbol(Symbol, FOuterLevel[Phase]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDMRDecoder.SliceSymbol(Symbol, OuterLevel: Double): Byte;
|
||||||
|
var
|
||||||
|
A, Threshold: Double;
|
||||||
|
begin
|
||||||
|
A := Abs(Symbol);
|
||||||
|
Threshold := (2.0 / 3.0) * OuterLevel;
|
||||||
if Symbol >= 0 then
|
if Symbol >= 0 then
|
||||||
begin
|
begin
|
||||||
if A >= Threshold then Result := 1 else Result := 0; // +3 / +1
|
if A >= Threshold then Result := 1 else Result := 0; // +3 / +1
|
||||||
@@ -596,6 +616,15 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDMRDecoder.SyncEyeOpening(Phase: Integer): Double;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := 1.0e300;
|
||||||
|
for i := 0 to 23 do
|
||||||
|
Result := Min(Result, FMagHistory[Phase, i]);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDMRDecoder.StartBurstTracking(Phase: Integer);
|
procedure TDMRDecoder.StartBurstTracking(Phase: Integer);
|
||||||
var
|
var
|
||||||
i, P: Integer;
|
i, P: Integer;
|
||||||
@@ -605,7 +634,10 @@ begin
|
|||||||
P := FHistoryPos[Phase]; // oldest item; ring is exactly 90 dibits full
|
P := FHistoryPos[Phase]; // oldest item; ring is exactly 90 dibits full
|
||||||
for i := 0 to DMR_SYNC_END_DIBIT do
|
for i := 0 to DMR_SYNC_END_DIBIT do
|
||||||
begin
|
begin
|
||||||
FCurrentBurst[i] := FDibitHistory[Phase, P];
|
// All 24 DMR sync dibits are known outer levels. Once they calibrate the
|
||||||
|
// eye, re-slice the already buffered pre-sync payload with the same level.
|
||||||
|
FCurrentBurst[i] := SliceSymbol(FSymbolHistory[Phase, P],
|
||||||
|
FFixedOuterLevel);
|
||||||
P := (P + 1) mod (DMR_SYNC_END_DIBIT + 1);
|
P := (P + 1) mod (DMR_SYNC_END_DIBIT + 1);
|
||||||
end;
|
end;
|
||||||
FCurrentBurstPos := DMR_SYNC_END_DIBIT + 1;
|
FCurrentBurstPos := DMR_SYNC_END_DIBIT + 1;
|
||||||
@@ -718,11 +750,13 @@ begin
|
|||||||
if (FLastSyncSample <> 0) and
|
if (FLastSyncSample <> 0) and
|
||||||
(FSampleNo - FLastSyncSample <= DMR_SAMPLES_PER_SYM * 2) then
|
(FSampleNo - FLastSyncSample <= DMR_SAMPLES_PER_SYM * 2) then
|
||||||
begin
|
begin
|
||||||
if FMagSum[Phase] > FBestSyncQuality then
|
if SyncEyeOpening(Phase) > FBestSyncQuality then
|
||||||
begin
|
begin
|
||||||
FBestSyncQuality := FMagSum[Phase];
|
FBestSyncQuality := SyncEyeOpening(Phase);
|
||||||
FSyncKind := Kind;
|
FSyncKind := Kind;
|
||||||
FInverted := Inverted;
|
FInverted := Inverted;
|
||||||
|
FFixedOuterLevel := FMagSum[Phase] / 24.0;
|
||||||
|
FOuterLevel[Phase] := FFixedOuterLevel;
|
||||||
StartBurstTracking(Phase);
|
StartBurstTracking(Phase);
|
||||||
end;
|
end;
|
||||||
Exit;
|
Exit;
|
||||||
@@ -732,7 +766,9 @@ begin
|
|||||||
Inc(FSyncCount);
|
Inc(FSyncCount);
|
||||||
FLastSyncTick := NowTick;
|
FLastSyncTick := NowTick;
|
||||||
FLastSyncSample := FSampleNo;
|
FLastSyncSample := FSampleNo;
|
||||||
FBestSyncQuality := FMagSum[Phase];
|
FBestSyncQuality := SyncEyeOpening(Phase);
|
||||||
|
FFixedOuterLevel := FMagSum[Phase] / 24.0;
|
||||||
|
FOuterLevel[Phase] := FFixedOuterLevel;
|
||||||
if Kind in [dskMSData, dskMSVoice] then FMobileActiveBurst := True;
|
if Kind in [dskMSData, dskMSVoice] then FMobileActiveBurst := True;
|
||||||
StartBurstTracking(Phase);
|
StartBurstTracking(Phase);
|
||||||
finally
|
finally
|
||||||
@@ -795,7 +831,9 @@ begin
|
|||||||
S.BestSyncDistance := FBestSyncDistance;
|
S.BestSyncDistance := FBestSyncDistance;
|
||||||
S.BestSyncPhase := FBestSyncPhase;
|
S.BestSyncPhase := FBestSyncPhase;
|
||||||
S.BestCandidateKind := FBestCandidateKind;
|
S.BestCandidateKind := FBestCandidateKind;
|
||||||
if FBestSyncPhase >= 0 then
|
if FFixedOuterLevel > 0 then
|
||||||
|
S.SymbolOuterLevel := FFixedOuterLevel
|
||||||
|
else if FBestSyncPhase >= 0 then
|
||||||
S.SymbolOuterLevel := FOuterLevel[FBestSyncPhase];
|
S.SymbolOuterLevel := FOuterLevel[FBestSyncPhase];
|
||||||
S.SignalMean := FSignalMean;
|
S.SignalMean := FSignalMean;
|
||||||
finally
|
finally
|
||||||
|
|||||||
Reference in New Issue
Block a user