mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
#7 WIP - fixes critical error in pulse shaping filter design parameters to improve low-SNR signal decoding performance. Continues code cleanup.
This commit is contained in:
@@ -607,6 +607,22 @@ public class FilterFactory
|
||||
return cicArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Root Raised Cosine filter.
|
||||
* @param samplesPerSymbol
|
||||
* @param symbolCount
|
||||
* @param alpha
|
||||
* @return
|
||||
*/
|
||||
public static float[] getRRC(double samplesPerSymbol, int symbolCount, float alpha)
|
||||
{
|
||||
//TODO: this wraps the existing method which is reducing the samples per symbol value x2 internally and is likely
|
||||
// a mistake. This method is used by NXDN to correct that error until the DMR and P25 decoders can be updated to
|
||||
// ensure that the correction doesn't impact those decoders. Once the cleanup is complete, this method can be
|
||||
// deleted and the NXDN implementation can revert to using the future corrected version.
|
||||
return getRootRaisedCosine(samplesPerSymbol * 2, symbolCount, alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates root raised cosine filter coefficients with a tap count equal to the symbols x samplesPerSymbol + 1.
|
||||
*
|
||||
|
||||
@@ -151,7 +151,7 @@ public class NXDNDecoder extends FeedbackDecoder implements IByteBufferProvider,
|
||||
|
||||
int symbolLength = 26;
|
||||
float rrcAlpha = 0.2f;
|
||||
float[] rrcTaps = FilterFactory.getRootRaisedCosine(samplesPerSymbol, symbolLength, rrcAlpha);
|
||||
float[] rrcTaps = FilterFactory.getRRC(samplesPerSymbol, symbolLength, rrcAlpha);
|
||||
mPulseShapingFilter = new RealFIRFilter(rrcTaps);
|
||||
float[] basebandTaps = getBasebandFilter(decimatedSampleRate, mConfig);
|
||||
mBasebandFilterI = FilterFactory.getRealFilter(basebandTaps);
|
||||
@@ -349,9 +349,9 @@ public class NXDNDecoder extends FeedbackDecoder implements IByteBufferProvider,
|
||||
|
||||
//NXDN 4800 Channels
|
||||
config = new DecodeConfigNXDN(TransmissionMode.M4800);
|
||||
String file = directory + "20251128_052514_150845000_MobileTech-NXDN-48_Fulton_Control_47_baseband.wav";
|
||||
// String file = directory + "20251128_052514_150845000_MobileTech-NXDN-48_Fulton_Control_47_baseband.wav";
|
||||
//Lower SNR recordings
|
||||
// String file = directory + "20260430_023716_150867500_Mobiletech-Communications-(NXDN)_Pulaski_Pulaski_11_baseband.wav";
|
||||
String file = directory + "20260430_023716_150867500_Mobiletech-Communications-(NXDN)_Pulaski_Pulaski_11_baseband.wav";
|
||||
// String file = directory + "20260430_023556_152982500_Mobiletech-Communications-(NXDN)_Manlius_Manlius_15_baseband.wav";
|
||||
|
||||
//This traffic channel sample Has Sync Detects between 1,096,430 - 1,111,430 samples (decimated sample rate: 12,500 Hz)
|
||||
|
||||
@@ -43,17 +43,16 @@ import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
|
||||
*/
|
||||
public class NXDNSymbolProcessor
|
||||
{
|
||||
private static final float TIMING_LOOP_GAIN = 0.4f;
|
||||
private static final float SOFT_SYMBOL_QUADRANT_BOUNDARY = (float)(Math.PI / 2.0);
|
||||
private static final float SYNC_THRESHOLD_DETECTION = 37;
|
||||
private static final float SYNC_THRESHOLD_OPTIMIZED = 40;
|
||||
private static final float SYNC_THRESHOLD_EQUALIZED = 40;
|
||||
private static final float TWO_PI = (float)(Math.PI * 2.0);
|
||||
private static final float[] SYNC_SYMBOLS = NXDNSyncDetector.SYMBOLS;
|
||||
private static final int BUFFER_WORKSPACE_LENGTH = 1024;
|
||||
private static final int DIBIT_LENGTH_NID = 33; //32 dibits (64 bits) +1 status
|
||||
private static final int DIBIT_LENGTH_SYNC = 10;
|
||||
private static final Correction INVALID_SYNC_DETECTION = new Correction(0d, Double.MAX_VALUE, 0f, 0f, 0f, 0f, 0);
|
||||
private ISyncResultsListener mSyncResultsViewer;
|
||||
private static final DecimalFormat DF = new DecimalFormat("00.000");
|
||||
private static final Dibit[] SYNC_DIBITS = NXDNSyncDetector.DIBITS;
|
||||
private final DibitToByteBufferAssembler mDibitAssembler = new DibitToByteBufferAssembler(300);
|
||||
private final FeedbackDecoder mFeedbackDecoder;
|
||||
private final NXDNMessageFramer mMessageFramer;
|
||||
@@ -61,12 +60,8 @@ public class NXDNSymbolProcessor
|
||||
private final NXDNSoftSyncDetector mSyncDetectorLagging = NXDNSyncDetectorFactory.getStandardDetector();
|
||||
private final SampleEqualizer mSampleEqualizer = new SampleEqualizer();
|
||||
private final C4FMEqualizer mSymbolEqualizer;
|
||||
private final SyncTracker mSyncTracker = new SyncTracker(2400, 3);
|
||||
private double mNoiseStandardDeviationThreshold;
|
||||
private double mSamplePoint;
|
||||
private double mSamplePointAdjustment;
|
||||
private double mSamplePointAdjustmentIncrement;
|
||||
private double mSamplePointAdjustmentMax;
|
||||
private double mSamplesPerSymbol;
|
||||
private double mTimingCorrectionThreshold;
|
||||
private float[] mBuffer;
|
||||
@@ -80,11 +75,11 @@ public class NXDNSymbolProcessor
|
||||
private boolean mSynchronized = false;
|
||||
private boolean mDelayedSyncNotificationPending = false;
|
||||
private int mDelayedSyncNotificationSymbolsRemaining = 0;
|
||||
private ISyncResultsListener mSyncResultsViewer;
|
||||
private ReferenceSyncWaveform mReferenceSyncWaveform;
|
||||
private final boolean mVisualize = false;
|
||||
private final int mDebugSymbolStart = 200;
|
||||
private static final DecimalFormat DF = new DecimalFormat("00.000");
|
||||
|
||||
private final boolean mDebugVisualize = false;
|
||||
private final int mDebugSymbolStart = 0;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
@@ -98,6 +93,9 @@ public class NXDNSymbolProcessor
|
||||
DF.setPositivePrefix(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the symbol equalizer.
|
||||
*/
|
||||
public void resetEqualizer()
|
||||
{
|
||||
mSymbolEqualizer.reset();
|
||||
@@ -108,12 +106,6 @@ public class NXDNSymbolProcessor
|
||||
return mSymbolEqualizer.getTapsDescription();
|
||||
}
|
||||
|
||||
|
||||
public void log()
|
||||
{
|
||||
System.out.println("SAMPLES: " + mDebugSampleCounter + " SYMBOLS: " + mDebugSymbolCounter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize and prepare for shutdown.
|
||||
*/
|
||||
@@ -220,24 +212,22 @@ public class NXDNSymbolProcessor
|
||||
|
||||
if(scorePrimary > SYNC_THRESHOLD_DETECTION && scorePrimary > scoreLag)
|
||||
{
|
||||
correctionCandidate = mSampleEqualizer.optimize(mSyncDetector, 0, scorePrimary,
|
||||
(bufferPointer + samplePoint));
|
||||
correctionCandidate = mSampleEqualizer.optimize(0, scorePrimary, (bufferPointer + samplePoint));
|
||||
}
|
||||
else if(scoreLag > SYNC_THRESHOLD_DETECTION)
|
||||
{
|
||||
correctionCandidate = mSampleEqualizer.optimize(mSyncDetectorLagging, -mLaggingSyncOffset,
|
||||
scoreLag, (bufferPointer + samplePoint));
|
||||
correctionCandidate = mSampleEqualizer.optimize(-mLaggingSyncOffset, scoreLag, (bufferPointer + samplePoint));
|
||||
}
|
||||
|
||||
softSymbol = mSymbolEqualizer.process(softSymbolLag, softSymbol);
|
||||
|
||||
//Broadcast the decoded soft symbol to an optionally registered listener (ie Symbol view in channel panel).
|
||||
Dibit symbol = toSymbol(softSymbol);
|
||||
Dibit symbol = Dibit.fromSample(softSymbol);
|
||||
|
||||
//Equalizer processes current soft symbol and returns a delayed soft symbol that is equalized
|
||||
mFeedbackDecoder.broadcast(softSymbol);
|
||||
|
||||
if(mVisualize)
|
||||
if(mDebugVisualize)
|
||||
{
|
||||
getSyncResultsViewer().symbol(softSymbol);
|
||||
}
|
||||
@@ -390,13 +380,11 @@ public class NXDNSymbolProcessor
|
||||
public void setSamplesPerSymbol(float samplesPerSymbol)
|
||||
{
|
||||
mSamplesPerSymbol = samplesPerSymbol;
|
||||
mSamplePoint = samplesPerSymbol;
|
||||
mTimingCorrectionThreshold = samplesPerSymbol / 30;
|
||||
mNoiseStandardDeviationThreshold = .2;
|
||||
mSamplePoint = samplesPerSymbol;
|
||||
mSamplePointAdjustmentMax = samplesPerSymbol / 2;
|
||||
mSamplePointAdjustmentIncrement = samplesPerSymbol / 100.0;
|
||||
mOptimizeFineIncrement = samplesPerSymbol / 200f;
|
||||
mLaggingSyncOffset = samplesPerSymbol / 2;
|
||||
mOptimizeFineIncrement = samplesPerSymbol / 200.0f;
|
||||
mLaggingSyncOffset = samplesPerSymbol / 2.0f;
|
||||
int bufferLength = BUFFER_WORKSPACE_LENGTH + (int)(Math.ceil((DIBIT_LENGTH_SYNC + DIBIT_LENGTH_NID + 2) * samplesPerSymbol));
|
||||
mBuffer = new float[bufferLength];
|
||||
mBufferReloadThreshold = mBuffer.length - (int)Math.ceil(samplesPerSymbol * (DIBIT_LENGTH_NID + 1));
|
||||
@@ -405,23 +393,6 @@ public class NXDNSymbolProcessor
|
||||
mReferenceSyncWaveform = mSyncDetector.getReferenceWaveform(samplesPerSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the sample value to determine the correct QPSK quadrant and maps the value to a Dibit symbol.
|
||||
* @param sample in radians.
|
||||
* @return symbol decision.
|
||||
*/
|
||||
public static Dibit toSymbol(float sample)
|
||||
{
|
||||
if(sample > 0)
|
||||
{
|
||||
return sample > SOFT_SYMBOL_QUADRANT_BOUNDARY ? Dibit.D01_PLUS_3 : Dibit.D00_PLUS_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return sample < -SOFT_SYMBOL_QUADRANT_BOUNDARY ? Dibit.D11_MINUS_3 : Dibit.D10_MINUS_1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug viewer UI for visualizing sync detections in the sample stream/waveform.
|
||||
*/
|
||||
@@ -442,13 +413,11 @@ public class NXDNSymbolProcessor
|
||||
*/
|
||||
public void visualizeSyncDetect(float score, boolean primary, String tag, int bufferPointer, double samplePoint)
|
||||
{
|
||||
if(!mVisualize)
|
||||
if(!mDebugVisualize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// //Correct for the 1-symbol delay from the symbol equalizer
|
||||
// samplePoint -= mSamplesPerSymbol;
|
||||
int integral = (int)Math.floor(samplePoint);
|
||||
samplePoint -= integral;
|
||||
bufferPointer += integral;
|
||||
@@ -508,7 +477,12 @@ public class NXDNSymbolProcessor
|
||||
*/
|
||||
public void visualizeSymbols(int bufferPointer, double samplePoint)
|
||||
{
|
||||
if(!mVisualize)
|
||||
if(true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mDebugVisualize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -537,7 +511,7 @@ public class NXDNSymbolProcessor
|
||||
for(int x = 0; x < 10; x++)
|
||||
{
|
||||
symbols[x] = mSampleEqualizer.getEqualizedSymbol(mBuffer[symbolIntegral], mBuffer[symbolIntegral + 1], mu);
|
||||
decisions[x] = toSymbol(symbols[x]).getIdealPhase();
|
||||
decisions[x] = Dibit.fromSample(symbols[x]).getIdealPhase();
|
||||
symbolPointer += mSamplesPerSymbol;
|
||||
symbolIntegral = (int)Math.floor(symbolPointer);
|
||||
mu = symbolPointer - symbolIntegral;
|
||||
@@ -711,7 +685,7 @@ public class NXDNSymbolProcessor
|
||||
* Sample equalizer providing gain and balance (DC offset compensation).
|
||||
*
|
||||
* Note: equalizer is initialized with a gain value of 1.219, as determined through significant testing against
|
||||
* both P25 and DMR C4FM modulated samples that employ pulse shaping filters. Gain value is adjusted and
|
||||
* both P25 and DMR C4FM modulated samples that employ the same pulse shaping filters. Gain value is adjusted and
|
||||
* optimized with each sync detection.
|
||||
*/
|
||||
class SampleEqualizer
|
||||
@@ -788,7 +762,7 @@ public class NXDNSymbolProcessor
|
||||
* offset for the lagging sync detector.
|
||||
* @return optimized timing adjustment or NO_OPTIMIZATION sentinel value.
|
||||
*/
|
||||
public Correction optimize(NXDNSyncDetector syncDetector, double additionalOffset, float detectionScore, double bufferOffset)
|
||||
public Correction optimize(double additionalOffset, float detectionScore, double bufferOffset)
|
||||
{
|
||||
//Offset points to the final symbol/sample in the buffer for the detected sync pattern.
|
||||
double offset = bufferOffset + additionalOffset;
|
||||
@@ -815,13 +789,13 @@ public class NXDNSymbolProcessor
|
||||
double adjustmentMax = samplesPerSymbol / 2.0;
|
||||
double candidate = offset;
|
||||
|
||||
float scoreCenter = score(syncDetector, candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
float scoreCenter = score(candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
|
||||
candidate = offset - stepSize;
|
||||
float scoreLeft = score(syncDetector, candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
float scoreLeft = score(candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
|
||||
candidate = offset + stepSize;
|
||||
float scoreRight = score(syncDetector, candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
float scoreRight = score(candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
|
||||
while(stepSize > stepSizeMin && Math.abs(adjustment) <= adjustmentMax)
|
||||
{
|
||||
@@ -832,7 +806,7 @@ public class NXDNSymbolProcessor
|
||||
scoreCenter = scoreLeft;
|
||||
|
||||
candidate = offset + adjustment - stepSize;
|
||||
scoreLeft = score(syncDetector, candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
scoreLeft = score(candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
}
|
||||
else if(scoreRight > scoreLeft && scoreRight > scoreCenter)
|
||||
{
|
||||
@@ -841,7 +815,7 @@ public class NXDNSymbolProcessor
|
||||
scoreCenter = scoreRight;
|
||||
|
||||
candidate = offset + adjustment + stepSize;
|
||||
scoreRight = score(syncDetector, candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
scoreRight = score(candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -850,10 +824,10 @@ public class NXDNSymbolProcessor
|
||||
if(stepSize > stepSizeMin)
|
||||
{
|
||||
candidate = offset + adjustment - stepSize;
|
||||
scoreLeft = score(syncDetector, candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
scoreLeft = score(candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
|
||||
candidate = offset + adjustment + stepSize;
|
||||
scoreRight = score(syncDetector, candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
scoreRight = score(candidate, samplesPerSymbol, calculatedBalanceCorrection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -864,7 +838,7 @@ public class NXDNSymbolProcessor
|
||||
return INVALID_SYNC_DETECTION;
|
||||
}
|
||||
|
||||
return getCorrection(syncDetector, additionalOffset, adjustment, detectionScore, scoreCenter, bufferOffset,
|
||||
return getCorrection(additionalOffset, adjustment, detectionScore, scoreCenter, bufferOffset,
|
||||
calculatedBalanceCorrection);
|
||||
}
|
||||
|
||||
@@ -878,45 +852,6 @@ public class NXDNSymbolProcessor
|
||||
return symbol * mGain + mBalance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the symbol balance from the symbol error to address multi-path and fading between sync periods.
|
||||
*/
|
||||
public double getAdjustment(float softSymbol, Dibit symbol, int bufferPointer)
|
||||
{
|
||||
double adjustment;
|
||||
|
||||
if(softSymbol < symbol.getIdealPhase())
|
||||
{
|
||||
if(mBuffer[bufferPointer] > mBuffer[bufferPointer + 1])
|
||||
{
|
||||
adjustment = -mSamplePointAdjustmentIncrement;
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustment = mSamplePointAdjustmentIncrement;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mBuffer[bufferPointer] > mBuffer[bufferPointer + 1])
|
||||
{
|
||||
adjustment = mSamplePointAdjustmentIncrement;
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustment = -mSamplePointAdjustmentIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
if(Math.abs(mSamplePointAdjustment + adjustment) <= mSamplePointAdjustmentMax)
|
||||
{
|
||||
mSamplePointAdjustment += adjustment;
|
||||
return adjustment;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equalizes both samples with optional phase wrap detection and returns the interpolated value at the mu offset.
|
||||
*
|
||||
@@ -949,41 +884,6 @@ public class NXDNSymbolProcessor
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equalizes both samples using the candidate correction values and returns the interpolated value at the
|
||||
* mu offset.
|
||||
* @param sample1 to equalize
|
||||
* @param sample2 to equalize
|
||||
* @param mu interpolation between samples 1 and 2
|
||||
* @param correction to apply when equalizing samples 1 and 2
|
||||
* @return interpolated value.
|
||||
*/
|
||||
public float getEqualizedSymbol(float sample1, float sample2, double mu, Correction correction)
|
||||
{
|
||||
sample1 = (sample1 + mBalance + correction.getBalanceAdjustment()) * (mGain + correction.getGainAdjustment());
|
||||
sample2 = (sample2 + mBalance + correction.getBalanceAdjustment()) * (mGain + correction.getGainAdjustment());
|
||||
|
||||
if(sample1 > Math.PI)
|
||||
{
|
||||
sample1 -= TWO_PI;
|
||||
}
|
||||
else if(sample1 < -Math.PI)
|
||||
{
|
||||
sample1 += TWO_PI;
|
||||
}
|
||||
|
||||
if(sample2 > Math.PI)
|
||||
{
|
||||
sample2 -= TWO_PI;
|
||||
}
|
||||
else if(sample2 < -Math.PI)
|
||||
{
|
||||
sample2 += TWO_PI;
|
||||
}
|
||||
|
||||
return LinearInterpolator.calculate(sample1, sample2, mu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the sync correlation score at the specified offset and samples per symbol interval using the
|
||||
* current equalizer balance and gain values.
|
||||
@@ -992,9 +892,9 @@ public class NXDNSymbolProcessor
|
||||
* @param samplesPerSymbol spacing to test for.
|
||||
* @return correlation score.
|
||||
*/
|
||||
public float score(NXDNSyncDetector syncDetector, double offset, double samplesPerSymbol, float balance)
|
||||
public float score(double offset, double samplesPerSymbol, float balance)
|
||||
{
|
||||
return score(syncDetector, offset, samplesPerSymbol, balance, mGain);
|
||||
return score(offset, samplesPerSymbol, balance, mGain);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1003,19 +903,20 @@ public class NXDNSymbolProcessor
|
||||
* @param samplesPerSymbol spacing to test for.
|
||||
* @return correlation score.
|
||||
*/
|
||||
public float score(NXDNSyncDetector syncDetector, double offset, double samplesPerSymbol, float balance, float gain)
|
||||
public float score(double offset, double samplesPerSymbol, float balance, float gain)
|
||||
{
|
||||
int maxPointer = mBuffer.length - 1;
|
||||
float softSymbol;
|
||||
|
||||
double pointer = offset - (samplesPerSymbol * (syncDetector.getSyncPatternDibitLength() - 1));
|
||||
double pointer = offset - (samplesPerSymbol * 9);
|
||||
int bufferPointer = (int)Math.floor(pointer);
|
||||
double fractional = pointer - bufferPointer;
|
||||
|
||||
float score = 0;
|
||||
float sample1, sample2;
|
||||
float idealSymbol;
|
||||
|
||||
for(int x = 0; x < syncDetector.getSyncPatternDibitLength(); x++)
|
||||
for(int x = 0; x < 10; x++)
|
||||
{
|
||||
if(bufferPointer < maxPointer)
|
||||
{
|
||||
@@ -1028,7 +929,19 @@ public class NXDNSymbolProcessor
|
||||
softSymbol = 0.0f;
|
||||
}
|
||||
|
||||
score += softSymbol * syncDetector.getSyncSymbols()[x];
|
||||
idealSymbol = SYNC_SYMBOLS[x];
|
||||
|
||||
//Constrain the contribution of the soft symbol to +/- the ideal symbol value.
|
||||
if(idealSymbol > 0)
|
||||
{
|
||||
softSymbol = Math.clamp(softSymbol, -idealSymbol, idealSymbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
softSymbol = Math.clamp(softSymbol, idealSymbol, -idealSymbol);
|
||||
}
|
||||
|
||||
score += softSymbol * idealSymbol;
|
||||
pointer += samplesPerSymbol;
|
||||
bufferPointer = (int)Math.floor(pointer);
|
||||
fractional = pointer - bufferPointer;
|
||||
@@ -1079,25 +992,25 @@ public class NXDNSymbolProcessor
|
||||
* sync detection, the equalizer settings are applied to the samples in the buffer allowing the symbols to be
|
||||
* resampled during coarse sync acquisition.
|
||||
*/
|
||||
public Correction getCorrection(NXDNSyncDetector syncDetector, double additionalOffset, double timingCorrection,
|
||||
public Correction getCorrection(double additionalOffset, double timingCorrection,
|
||||
float detectionScore, float optimizationScore, double offset, float balanceCorrection)
|
||||
{
|
||||
double resampleStart = offset + additionalOffset + timingCorrection - (mSamplesPerSymbol * (syncDetector.getSyncPatternDibitLength() - 1));
|
||||
double resampleStart = offset + additionalOffset + timingCorrection - (mSamplesPerSymbol * 9);
|
||||
int resampleStartIntegral = (int)Math.floor(resampleStart);
|
||||
float symbol, gainAccumulator = 0, resampledSoftSymbol;
|
||||
Dibit resampledDibit;
|
||||
int bitErrorCount = 0;
|
||||
|
||||
for(int x = 0; x < syncDetector.getSyncPatternDibitLength(); x++)
|
||||
for(int x = 0; x < 10; x++)
|
||||
{
|
||||
if(resampleStartIntegral >= 0)
|
||||
{
|
||||
symbol = syncDetector.getSyncSymbols()[x];
|
||||
symbol = SYNC_SYMBOLS[x];
|
||||
resampledSoftSymbol = LinearInterpolator.calculate(mBuffer[resampleStartIntegral],
|
||||
mBuffer[resampleStartIntegral + 1], resampleStart - resampleStartIntegral);
|
||||
resampledSoftSymbol = resampledSoftSymbol * mGain + balanceCorrection;
|
||||
resampledDibit = toSymbol(resampledSoftSymbol);
|
||||
bitErrorCount += syncDetector.getSyncDibits()[x].getBitErrorFrom(resampledDibit);
|
||||
resampledDibit = Dibit.fromSample(resampledSoftSymbol);
|
||||
bitErrorCount += SYNC_DIBITS[x].getBitErrorFrom(resampledDibit);
|
||||
gainAccumulator += Math.abs(symbol) - Math.abs(resampledSoftSymbol);
|
||||
}
|
||||
|
||||
@@ -1105,15 +1018,14 @@ public class NXDNSymbolProcessor
|
||||
resampleStartIntegral = (int)Math.floor(resampleStart);
|
||||
}
|
||||
|
||||
gainAccumulator /= syncDetector.getSyncPatternDibitLength();
|
||||
gainAccumulator /= 10;
|
||||
|
||||
//Recalculate the optimization score using the adjusted equalizer settings
|
||||
if(!mSynchronized)
|
||||
{
|
||||
double optimizedFinalSymbol = offset + additionalOffset + timingCorrection;
|
||||
balanceCorrection = -getBalance(optimizedFinalSymbol);
|
||||
optimizationScore = score(syncDetector, optimizedFinalSymbol, mSamplesPerSymbol,
|
||||
balanceCorrection, mGain + gainAccumulator);
|
||||
optimizationScore = score(optimizedFinalSymbol, mSamplesPerSymbol, balanceCorrection, mGain + gainAccumulator);
|
||||
}
|
||||
|
||||
return new Correction(additionalOffset, timingCorrection, balanceCorrection, gainAccumulator, detectionScore,
|
||||
|
||||
@@ -33,8 +33,8 @@ public abstract class NXDNSyncDetector
|
||||
public static final long SYNC_PATTERN = 0xCDF59;
|
||||
public static final long SYNC_MASK = 0xFFFFF;
|
||||
public static final int SYNC_DIBIT_LENGTH = 10;
|
||||
private static final Dibit[] DIBITS = toDibits(SYNC_PATTERN, SYNC_DIBIT_LENGTH);
|
||||
protected static final float[] SYMBOLS = toSymbols(DIBITS);
|
||||
public static final Dibit[] DIBITS = toDibits(SYNC_PATTERN, SYNC_DIBIT_LENGTH);
|
||||
public static final float[] SYMBOLS = toSymbols(DIBITS);
|
||||
private static Map<Integer,ReferenceSyncWaveform> sReferenceWaveformMap = new TreeMap<>();
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user