feat(dmr): add diagnostic capture probes

This commit is contained in:
2026-07-14 19:09:35 +03:00
parent 70486d901b
commit 39b4627c2b
9 changed files with 662 additions and 3 deletions
+45 -1
View File
@@ -31,6 +31,7 @@ const
type
TDMRAudioEvent = procedure(const PCM: array of Single; Count: Integer) of object;
TDMRBurstEvent = procedure(const Dibits: array of Byte; Count: Integer) of object;
TDMRSyncKind = (
dskNone,
@@ -68,6 +69,11 @@ type
SelectedSlot: Integer;
VoiceFrameCount: QWord;
VoiceErrorCount: QWord;
BestSyncDistance: Integer;
BestSyncPhase: Integer;
BestCandidateKind: TDMRSyncKind;
SymbolOuterLevel: Single;
SignalMean: Single;
end;
TDMRDecoder = class;
@@ -121,8 +127,12 @@ type
FLastSelectedVoiceTick: QWord;
FVoiceFrameCount, FVoiceErrorCount: QWord;
FOnAudio: TDMRAudioEvent;
FOnBurst: TDMRBurstEvent;
FBurstCount: QWord;
FRMSSq: Double;
FSignalMean: Double;
FBestSyncDistance, FBestSyncPhase: Integer;
FBestCandidateKind: TDMRSyncKind;
FSyncKind: TDMRSyncKind;
FInputInverted: Boolean;
@@ -152,6 +162,7 @@ type
class function SyncKindName(Kind: TDMRSyncKind): string; static;
property Enabled: Boolean read FEnabled;
property OnAudio: TDMRAudioEvent read FOnAudio write FOnAudio;
property OnBurst: TDMRBurstEvent read FOnBurst write FOnBurst;
end;
implementation
@@ -191,6 +202,17 @@ begin
end;
end;
function PopCount24(V: LongWord): Integer;
begin
V := V and DMR_SYNC_MASK;
Result := 0;
while V <> 0 do
begin
V := V and (V - 1);
Inc(Result);
end;
end;
constructor TDMRDecoderThread.Create(AOwner: TDMRDecoder);
begin
inherited Create(True);
@@ -300,6 +322,10 @@ begin
FWindowSum := 0;
FSampleNo := 0;
FRMSSq := 0;
FSignalMean := 0;
FBestSyncDistance := 25;
FBestSyncPhase := -1;
FBestCandidateKind := dskNone;
FStatusLock.Enter;
try
FSyncKind := dskNone;
@@ -379,6 +405,7 @@ var
Sym: Double;
begin
FRMSSq := FRMSSq + 0.001 * (S * S - FRMSSq);
FSignalMean := FSignalMean + 0.001 * (S - FSignalMean);
FWindowSum := FWindowSum - FSampleWindow[FWindowPos] + S;
FSampleWindow[FWindowPos] := S;
FWindowPos := (FWindowPos + 1) mod DMR_SAMPLES_PER_SYM;
@@ -395,7 +422,7 @@ end;
procedure TDMRDecoder.ProcessSymbol(Phase: Integer; Symbol: Double);
var
i: Integer;
i, Distance: Integer;
Pat: LongWord;
Dibit: Byte;
V: Double;
@@ -430,6 +457,16 @@ begin
for i := 0 to High(SYNC_TEXT) do
begin
Pat := SyncBits(SYNC_TEXT[i]);
if FHistoryCount[Phase] >= 24 then
begin
Distance := PopCount24(FSyncShift[Phase] xor Pat);
if Distance < FBestSyncDistance then
begin
FBestSyncDistance := Distance;
FBestSyncPhase := Phase;
FBestCandidateKind := SYNC_KIND[i];
end;
end;
if FSyncShift[Phase] = Pat then
begin
NoteSync(Phase, SYNC_KIND[i], FInputInverted);
@@ -478,6 +515,7 @@ procedure TDMRDecoder.CompleteBurst;
begin
Move(FCurrentBurst[0], FLastBurst[0], SizeOf(FLastBurst));
DMRParseBurst(FLastBurst, FLastBurstInfo);
if Assigned(FOnBurst) then FOnBurst(FLastBurst, Length(FLastBurst));
if FLastBurstInfo.SlotType.Valid and
(FSyncKind in [dskBSData, dskMSData, dskDirectTS1Data,
dskDirectTS2Data]) then
@@ -644,6 +682,12 @@ begin
S.SelectedSlot := FSelectedSlot;
S.VoiceFrameCount := FVoiceFrameCount;
S.VoiceErrorCount := FVoiceErrorCount;
S.BestSyncDistance := FBestSyncDistance;
S.BestSyncPhase := FBestSyncPhase;
S.BestCandidateKind := FBestCandidateKind;
if FBestSyncPhase >= 0 then
S.SymbolOuterLevel := FOuterLevel[FBestSyncPhase];
S.SignalMean := FSignalMean;
finally
FStatusLock.Leave;
end;