mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 01:27:34 -05:00
#2120 DMR Decoder resolves index out of bounds error and also updates Hamming 16/17 decoders to correctly identify multi-bit errors when the hamming parity bit is the syndrome. (#2121)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* *****************************************************************************
|
* *****************************************************************************
|
||||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
* Copyright (C) 2014-2025 Dennis Sheirer
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -47,6 +47,13 @@ public class Hamming16 implements IHamming
|
|||||||
return NO_ERRORS;
|
return NO_ERRORS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If the syndrome indicates the error is in the final parity bit position, and we already have odd parity, then
|
||||||
|
//flag it as invalid for multiple errors.
|
||||||
|
if(syndrome == 1 && message.getSubMessage(offset, offset + 16).cardinality() % 2 == 1) //check final parity bit
|
||||||
|
{
|
||||||
|
return MULTIPLE_ERRORS;
|
||||||
|
}
|
||||||
|
|
||||||
for(int index = 0; index < CHECKSUMS.length; index++)
|
for(int index = 0; index < CHECKSUMS.length; index++)
|
||||||
{
|
{
|
||||||
if(syndrome == CHECKSUMS[index])
|
if(syndrome == CHECKSUMS[index])
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* *****************************************************************************
|
* *****************************************************************************
|
||||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
* Copyright (C) 2014-2025 Dennis Sheirer
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -46,6 +46,13 @@ public class Hamming17 implements IHamming
|
|||||||
return NO_ERRORS;
|
return NO_ERRORS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If the syndrome indicates the error is in the final parity bit position, and we already have odd parity, then
|
||||||
|
//flag it as invalid for multiple errors.
|
||||||
|
if(syndrome == 1 && message.getSubMessage(offset, offset + 17).cardinality() % 2 == 1) //check final parity bit
|
||||||
|
{
|
||||||
|
return MULTIPLE_ERRORS;
|
||||||
|
}
|
||||||
|
|
||||||
for(int index = 0; index < CHECKSUMS.length; index++)
|
for(int index = 0; index < CHECKSUMS.length; index++)
|
||||||
{
|
{
|
||||||
if(syndrome == CHECKSUMS[index])
|
if(syndrome == CHECKSUMS[index])
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* *****************************************************************************
|
* *****************************************************************************
|
||||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
* Copyright (C) 2014-2025 Dennis Sheirer
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -58,6 +58,7 @@ public class DMRSoftSymbolProcessor
|
|||||||
private static final int BUFFER_LENGTH_DIBITS = BUFFER_PROTECTED_REGION_DIBITS + BUFFER_WORKSPACE_LENGTH_DIBITS;
|
private static final int BUFFER_LENGTH_DIBITS = BUFFER_PROTECTED_REGION_DIBITS + BUFFER_WORKSPACE_LENGTH_DIBITS;
|
||||||
private static final float MAX_POSITIVE_SOFT_SYMBOL = Dibit.D01_PLUS_3.getIdealPhase();
|
private static final float MAX_POSITIVE_SOFT_SYMBOL = Dibit.D01_PLUS_3.getIdealPhase();
|
||||||
private static final float MAX_NEGATIVE_SOFT_SYMBOL = Dibit.D11_MINUS_3.getIdealPhase();
|
private static final float MAX_NEGATIVE_SOFT_SYMBOL = Dibit.D11_MINUS_3.getIdealPhase();
|
||||||
|
private static final float SAMPLES_PER_SYMBOL_ALLOWABLE_DEVIATION = 0.005f; //.5%
|
||||||
private static final float SYMBOL_QUADRANT_BOUNDARY = (float)(Math.PI / 2.0);
|
private static final float SYMBOL_QUADRANT_BOUNDARY = (float)(Math.PI / 2.0);
|
||||||
private static final float SYNC_DETECTION_THRESHOLD = 60;
|
private static final float SYNC_DETECTION_THRESHOLD = 60;
|
||||||
private DMRSyncModeMonitor mSyncModeMonitor = new DMRSyncModeMonitor();
|
private DMRSyncModeMonitor mSyncModeMonitor = new DMRSyncModeMonitor();
|
||||||
@@ -73,11 +74,14 @@ public class DMRSoftSymbolProcessor
|
|||||||
private float mLaggingSyncOffset2;
|
private float mLaggingSyncOffset2;
|
||||||
private float mObservedSamplesPerSymbol;
|
private float mObservedSamplesPerSymbol;
|
||||||
private float mSamplesPerSymbol;
|
private float mSamplesPerSymbol;
|
||||||
|
private float mMaxSamplesPerSymbol;
|
||||||
|
private float mMinSamplesPerSymbol;
|
||||||
private float mSamplePoint;
|
private float mSamplePoint;
|
||||||
private float[] mBuffer;
|
private float[] mBuffer;
|
||||||
private int mBufferLoadPointer;
|
private int mBufferLoadPointer;
|
||||||
private int mBufferPointer;
|
private int mBufferPointer;
|
||||||
private int mBufferWorkspaceLength;
|
private int mBufferWorkspaceLength;
|
||||||
|
private int mBufferInterpolatorReservedRegion;
|
||||||
private int mSymbolsSinceLastSync = 0;
|
private int mSymbolsSinceLastSync = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,7 +162,7 @@ public class DMRSoftSymbolProcessor
|
|||||||
samplesPointer += copyLength;
|
samplesPointer += copyLength;
|
||||||
mBufferLoadPointer += copyLength;
|
mBufferLoadPointer += copyLength;
|
||||||
|
|
||||||
while(mBufferPointer < (mBufferLoadPointer - 7)) //Interpolator needs 1 and optimizer needs 6 pad spaces
|
while(mBufferPointer < (mBufferLoadPointer - mBufferInterpolatorReservedRegion))
|
||||||
{
|
{
|
||||||
mBufferPointer++;
|
mBufferPointer++;
|
||||||
mSamplePoint--;
|
mSamplePoint--;
|
||||||
@@ -253,7 +257,7 @@ public class DMRSoftSymbolProcessor
|
|||||||
float offset = (mBufferPointer + mSamplePoint) + additionalOffset - (mObservedSamplesPerSymbol * 23);
|
float offset = (mBufferPointer + mSamplePoint) + additionalOffset - (mObservedSamplesPerSymbol * 23);
|
||||||
|
|
||||||
//Find the optimal symbol timing
|
//Find the optimal symbol timing
|
||||||
float stepSize = mObservedSamplesPerSymbol / 10.0f;
|
float stepSize = mSyncLock ? (mObservedSamplesPerSymbol / 40.0f) : (mObservedSamplesPerSymbol / 10.0f);
|
||||||
float stepSizeMin = 0.03f;
|
float stepSizeMin = 0.03f;
|
||||||
float adjustment = 0.0f;
|
float adjustment = 0.0f;
|
||||||
float adjustmentMax = mObservedSamplesPerSymbol / 2.0f;
|
float adjustmentMax = mObservedSamplesPerSymbol / 2.0f;
|
||||||
@@ -343,9 +347,18 @@ public class DMRSoftSymbolProcessor
|
|||||||
|
|
||||||
//Adjust the observed samples per symbol using the timing error measured across one or two bursts when we're in
|
//Adjust the observed samples per symbol using the timing error measured across one or two bursts when we're in
|
||||||
//fine sync mode and the timing error is not excessive.
|
//fine sync mode and the timing error is not excessive.
|
||||||
if(mSyncLock && adjustment < 0.5 && mSymbolsSinceLastSync > 143 && mSymbolsSinceLastSync < 289)
|
if(mSyncLock && Math.abs(adjustment) < 0.5 && mSymbolsSinceLastSync > 143 && mSymbolsSinceLastSync < 289)
|
||||||
{
|
{
|
||||||
mObservedSamplesPerSymbol += (float)((double)adjustment / (double)mSymbolsSinceLastSync * 0.2);
|
mObservedSamplesPerSymbol += (float)((double)adjustment / (double)mSymbolsSinceLastSync * 0.2);
|
||||||
|
|
||||||
|
if(mObservedSamplesPerSymbol > mMaxSamplesPerSymbol)
|
||||||
|
{
|
||||||
|
mObservedSamplesPerSymbol = mMaxSamplesPerSymbol;
|
||||||
|
}
|
||||||
|
else if(mObservedSamplesPerSymbol < mMinSamplesPerSymbol)
|
||||||
|
{
|
||||||
|
mObservedSamplesPerSymbol = mMinSamplesPerSymbol;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the timing error adjustment is high enough, resample the symbols. Otherwise, overwrite the captured sync
|
//If the timing error adjustment is high enough, resample the symbols. Otherwise, overwrite the captured sync
|
||||||
@@ -402,15 +415,22 @@ public class DMRSoftSymbolProcessor
|
|||||||
{
|
{
|
||||||
float score = 0;
|
float score = 0;
|
||||||
float[] symbols = pattern.toSymbols();
|
float[] symbols = pattern.toSymbols();
|
||||||
float[] softSymbols = new float[24];
|
int integral, maxPointer = mBuffer.length - 1;
|
||||||
int integral;
|
float softSymbol = 0.0f;
|
||||||
|
|
||||||
for(int x = 0; x < 24; x++)
|
for(int x = 0; x < 24; x++)
|
||||||
{
|
{
|
||||||
float softSymbol = PhaseAwareLinearInterpolator.calculate(mBuffer[bufferPointer], mBuffer[bufferPointer + 1], fractional);
|
if(bufferPointer < maxPointer)
|
||||||
softSymbol = Math.min(softSymbol, MAX_POSITIVE_SOFT_SYMBOL);
|
{
|
||||||
softSymbol = Math.max(softSymbol, MAX_NEGATIVE_SOFT_SYMBOL);
|
softSymbol = PhaseAwareLinearInterpolator.calculate(mBuffer[bufferPointer], mBuffer[bufferPointer + 1], fractional);
|
||||||
softSymbols[x] = softSymbol;
|
softSymbol = Math.min(softSymbol, MAX_POSITIVE_SOFT_SYMBOL);
|
||||||
|
softSymbol = Math.max(softSymbol, MAX_NEGATIVE_SOFT_SYMBOL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
softSymbol = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
score += softSymbol * symbols[x];
|
score += softSymbol * symbols[x];
|
||||||
fractional += samplesPerSymbol;
|
fractional += samplesPerSymbol;
|
||||||
integral = (int)Math.floor(fractional);
|
integral = (int)Math.floor(fractional);
|
||||||
@@ -428,6 +448,10 @@ public class DMRSoftSymbolProcessor
|
|||||||
public void setSamplesPerSymbol(float samplesPerSymbol)
|
public void setSamplesPerSymbol(float samplesPerSymbol)
|
||||||
{
|
{
|
||||||
mSamplesPerSymbol = samplesPerSymbol;
|
mSamplesPerSymbol = samplesPerSymbol;
|
||||||
|
mMaxSamplesPerSymbol = samplesPerSymbol * (1.0f + SAMPLES_PER_SYMBOL_ALLOWABLE_DEVIATION);
|
||||||
|
mMinSamplesPerSymbol = samplesPerSymbol * (1.0f - SAMPLES_PER_SYMBOL_ALLOWABLE_DEVIATION);
|
||||||
|
//Protected region for score() method to avoid IndexOutOfBounds = Max Adjustment + Max Step Size for Max SPS
|
||||||
|
mBufferInterpolatorReservedRegion = (int)Math.ceil((mMaxSamplesPerSymbol / 2.0f) + (mMaxSamplesPerSymbol / 10.0f));
|
||||||
mObservedSamplesPerSymbol = mSamplesPerSymbol;
|
mObservedSamplesPerSymbol = mSamplesPerSymbol;
|
||||||
mSamplePoint = mSamplesPerSymbol;
|
mSamplePoint = mSamplesPerSymbol;
|
||||||
mLaggingSyncOffset1 = mSamplesPerSymbol / 3;
|
mLaggingSyncOffset1 = mSamplesPerSymbol / 3;
|
||||||
|
|||||||
Reference in New Issue
Block a user