mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
* Uses same shared architecture and symbol processor pattern as other C4FM decoders. * Adds soft symbol processing and sync detection. * Removes RRC filter and replaces with improved channel filter. * Viterbi soft symbol decoding with demodulator reliability weighting * Improved sync reacquisition in low SNR * Improved handling for phase wrapping and interpolation * NAC Tracker updated to track by NAC count * Native buffers returning partial buffers * Message processor uses only valid LDU1 words * Reduced phantom TDU messages * Tuner/Channe frequency error corrections don't reset the symbol trackers and fix possible divide by zero error * LSM timing error detector now updates per symbol block size instead of sample buffer size - faster convergence * New unit tests * Resolves several issues, including a lagging sync detect offset issue in the recently updated P25P1 C4FM decoder. * Consolidate filter designers for each protocol back into the FilterFactory class. * DMR, P25 Phase 1 C4FM and LSM, and P25 Phase 2 decoders design the baseband filter once and share the taps across the I and Q filters. Co-authored-by: denny <dennis.sheirer@gmail.com>
This commit is contained in:
@@ -260,7 +260,7 @@ public class MixerReader<T>
|
||||
{
|
||||
while(bytesRead < buffer.length)
|
||||
{
|
||||
bytesRead += mTargetDataLine.read(buffer, bytesRead, buffer.length);
|
||||
bytesRead += mTargetDataLine.read(buffer, bytesRead, buffer.length - bytesRead);
|
||||
}
|
||||
}
|
||||
catch(ArrayIndexOutOfBoundsException aioobe)
|
||||
|
||||
@@ -42,6 +42,7 @@ public class ChannelFrequencyErrorManager implements ISourceEventListener, Liste
|
||||
private final TunerChannelSource mTunerChannelSource;
|
||||
private final TunerFrequencyErrorManager mParent;
|
||||
private ScheduledFuture<?> mScheduledFuture;
|
||||
//Guarded by this instance: updated by this manager's timer and by the tuner's PPM change notifications
|
||||
private long mAppliedFrequencyCorrection = 0;
|
||||
private long mAverageRequestedCorrection = 0;
|
||||
private boolean mCurrentForTunerProcessing = false;
|
||||
@@ -73,7 +74,7 @@ public class ChannelFrequencyErrorManager implements ISourceEventListener, Liste
|
||||
* Snapshot of the current applied frequency correction for the channel.
|
||||
* @return total frequency error in Hertz.
|
||||
*/
|
||||
public long getFrequencyError()
|
||||
public synchronized long getFrequencyError()
|
||||
{
|
||||
return mAppliedFrequencyCorrection;
|
||||
}
|
||||
@@ -81,12 +82,22 @@ public class ChannelFrequencyErrorManager implements ISourceEventListener, Liste
|
||||
/**
|
||||
* Receive a notification from the parent tuner is updating the PPM and frequency correction change value.
|
||||
*
|
||||
* Note: on receiving this change notification, the tuner manager will expose the current PPM and correction values.
|
||||
* The tuner PPM change shifts every channel by the change: a positive PPM change lowers the tuned frequency, which
|
||||
* raises each channel's signal frequency by the change, the same as a positive channel frequency correction. The
|
||||
* tuner absorbs the change from the average of the channel corrections, so remove the change from this channel's
|
||||
* applied correction to keep the channel's net correction (and the decoder's view of the signal) unchanged.
|
||||
* Otherwise, each PPM change appears to the decoder as a sudden carrier offset step that the channel correction
|
||||
* removes over the following correction intervals, while the tuner continues to absorb the stale channel
|
||||
* correction.
|
||||
*
|
||||
* Note: invoked by the tuner's frequency error manager while holding the tuner controller lock, so this method
|
||||
* must not call back into the tuner.
|
||||
* @param change in Hertz resulting from the tuner's PPM update.
|
||||
*/
|
||||
public void receive(long change)
|
||||
public synchronized void receive(long change)
|
||||
{
|
||||
//The TunerFrequencyErrorManager notifies this channel of the correction applied at the tuner
|
||||
mAppliedFrequencyCorrection -= change;
|
||||
mTunerChannelSource.setFrequencyCorrection(mAppliedFrequencyCorrection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,16 +144,25 @@ public class ChannelFrequencyErrorManager implements ISourceEventListener, Liste
|
||||
if(mCurrentForChannelProcessing)
|
||||
{
|
||||
long partialCorrection = Math.clamp(mAverageRequestedCorrection, -MAXIMUM_CHANNEL_ERROR_CORRECTION_PER_INTERVAL, MAXIMUM_CHANNEL_ERROR_CORRECTION_PER_INTERVAL);
|
||||
long appliedFrequencyCorrection;
|
||||
|
||||
if(partialCorrection != 0)
|
||||
//receive(long change) holds the tuner controller lock while it locks this instance, so the status
|
||||
//notification below, which calls into the tuner, is created outside of this block to avoid a lock order
|
||||
//inversion.
|
||||
synchronized(this)
|
||||
{
|
||||
mAppliedFrequencyCorrection += (long)(partialCorrection * ERROR_PROCESSING_GAIN);
|
||||
mTunerChannelSource.setFrequencyCorrection(mAppliedFrequencyCorrection);
|
||||
mRequestedCorrectAveragingBuffer.reset();
|
||||
if(partialCorrection != 0)
|
||||
{
|
||||
mAppliedFrequencyCorrection += (long)(partialCorrection * ERROR_PROCESSING_GAIN);
|
||||
mTunerChannelSource.setFrequencyCorrection(mAppliedFrequencyCorrection);
|
||||
mRequestedCorrectAveragingBuffer.reset();
|
||||
}
|
||||
|
||||
appliedFrequencyCorrection = mAppliedFrequencyCorrection;
|
||||
}
|
||||
|
||||
ChannelFrequencyCorrectionStatusNotification notification = ChannelFrequencyCorrectionStatusNotification
|
||||
.create(mTunerChannelSource, mAverageRequestedCorrection, mAppliedFrequencyCorrection, mParent.getTunerPPM(),
|
||||
.create(mTunerChannelSource, mAverageRequestedCorrection, appliedFrequencyCorrection, mParent.getTunerPPM(),
|
||||
mParent.getTunerFrequencyCorrection(), mParent.isEnabled());
|
||||
mTunerChannelSource.broadcastConsumerSourceEvent(notification);
|
||||
mAverageRequestedCorrection = 0;
|
||||
@@ -152,7 +172,7 @@ public class ChannelFrequencyErrorManager implements ISourceEventListener, Liste
|
||||
else
|
||||
{
|
||||
ChannelFrequencyCorrectionStatusNotification notification = ChannelFrequencyCorrectionStatusNotification
|
||||
.create(mTunerChannelSource, 0, mAppliedFrequencyCorrection, mParent.getTunerPPM(),
|
||||
.create(mTunerChannelSource, 0, getFrequencyError(), mParent.getTunerPPM(),
|
||||
mParent.getTunerFrequencyCorrection(), mParent.isEnabled());
|
||||
mTunerChannelSource.broadcastConsumerSourceEvent(notification);
|
||||
}
|
||||
|
||||
@@ -132,6 +132,13 @@ public class TunerFrequencyErrorManager implements ISourceEventProcessor
|
||||
}
|
||||
}
|
||||
|
||||
//Skip the update when no channel has reported a measurement since the last update. A divide by zero
|
||||
//exception would cancel all subsequent executions of this scheduled task.
|
||||
if(count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
requestedChangeHz /= count;
|
||||
mTunerController.setMeasuredFrequencyError((int)requestedChangeHz);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user