Resolves #373 - Adds support for Tuner frequency error PPM monitoring

and auto-correction for R820T tuners.

-Updated TunerModel and TunerViewPanel to add 2 new columns to
display the current tuner's PPM setting and (when available) the
measured frequency error averaged over 5 second intervals provided by
certain decoders (e.g. P25 C4FM and LSM).  Frequency error value from
P25 decoders is provided from the Costas Loop PLL once 2 or more P25
message sync events have been observed in a short period.
-Updated R820T tuner to auto-correct PPM when measured frequency error
exceeds the +/- 0.4PPM threshold for a period of 30 seconds or more.
Feature can be enabled/disabled by user in the tuner editor panel.

Resolved several issues with P25 C4FM/LSM decoders that was impacting
performance related to channel misalignment from tuner PPM offsets.
This commit is contained in:
Denny
2018-07-29 10:48:29 -04:00
parent 5c0d97d942
commit 0c47efea03
44 changed files with 1296 additions and 483 deletions

View File

@@ -1,6 +1,26 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* 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 the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.bits;
public interface ISyncProcessor
{
public void checkSync( long value );
/**
* Checks if the value matches a known sync pattern
* @param value
* @return
*/
boolean checkSync(long value);
}

View File

@@ -1,111 +1,130 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* 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 the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.bits;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Multi-Sync pattern matcher. Accepts multiple sync detector objects for
* Multi-Sync pattern matcher. Accepts multiple sync detector objects for
* comparision against the incoming bit stream.
*
*
* Note: works for sync patterns up to 63 bits (integer size - 1 ) long.
* If a 64 bit or larger sync pattern is applied, then the wrapping feature
* of the Long.rotate methods will wrap the MSB around to the LSB and
* corrupt the matching value.
*
*/
public class MultiSyncPatternMatcher
{
private List<ISyncProcessor> mSyncProcessors = new ArrayList<ISyncProcessor>();
private long mBits = 0;
private long mMask = 0;
public MultiSyncPatternMatcher( int syncSize )
{
Validate.isTrue(syncSize < 64);
//Setup a bit mask of all ones the length of the sync pattern
mMask = (long)( ( Math.pow( 2, syncSize ) ) - 1 );
}
public void dispose()
{
mSyncProcessors.clear();
}
/**
* Processes two bits before checking sync processors for a match.
*/
public void receive( boolean bit1, boolean bit2 )
{
mBits = Long.rotateLeft( mBits, 1 );
mBits &= mMask;
if( bit1 )
{
mBits += 1;
}
private final static Logger mLog = LoggerFactory.getLogger(MultiSyncPatternMatcher.class);
mBits = Long.rotateLeft( mBits, 1 );
mBits &= mMask;
if( bit2 )
{
mBits += 1;
}
private ISyncDetectListener mSyncDetectListener;
private int mSyncLossThreshold;
private int mBitCount;
private List<ISyncProcessor> mSyncProcessors = new ArrayList<ISyncProcessor>();
for( ISyncProcessor processor: mSyncProcessors )
{
processor.checkSync( mBits );
}
}
/**
* Processes one bit before checking sync processors for a match.
*/
public void receive( boolean bit )
{
mBits = Long.rotateLeft( mBits, 1 );
mBits &= mMask;
if( bit )
{
mBits += 1;
}
private long mBits = 0;
private long mMask = 0;
for( ISyncProcessor processor: mSyncProcessors )
{
processor.checkSync( mBits );
}
}
public MultiSyncPatternMatcher(ISyncDetectListener syncDetectListener, int syncLossThreshold, int syncSize)
{
mSyncDetectListener = syncDetectListener;
mSyncLossThreshold = syncLossThreshold;
Validate.isTrue(syncSize < 64);
/**
* Adds a sync processor to receive the bit stream.
*/
public void add( ISyncProcessor processor )
{
mSyncProcessors.add( processor );
}
//Setup a bit mask of all ones the length of the sync pattern
mMask = (long)((Math.pow(2, syncSize)) - 1);
}
public void dispose()
{
mSyncProcessors.clear();
}
/**
* Processes two bits before checking sync processors for a match.
*/
public void receive(boolean bit1, boolean bit2)
{
mBits = Long.rotateLeft(mBits, 1);
mBits &= mMask;
if(bit1)
{
mBits += 1;
}
mBits = Long.rotateLeft(mBits, 1);
mBits &= mMask;
if(bit2)
{
mBits += 1;
}
mBitCount += 2;
for(ISyncProcessor processor : mSyncProcessors)
{
if(processor.checkSync(mBits))
{
mSyncDetectListener.syncDetected();
mBitCount = 0;
}
}
if(mBitCount > mSyncLossThreshold)
{
mBitCount = 0;
mSyncDetectListener.syncLost();
}
}
/**
* Processes one bit before checking sync processors for a match.
*/
public void receive(boolean bit)
{
mBits = Long.rotateLeft(mBits, 1);
mBits &= mMask;
if(bit)
{
mBits += 1;
}
for(ISyncProcessor processor : mSyncProcessors)
{
processor.checkSync(mBits);
}
}
/**
* Adds a sync processor to receive the bit stream.
*/
public void add(ISyncProcessor processor)
{
mSyncProcessors.add(processor);
}
}

View File

@@ -1,50 +1,68 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* 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 the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.bits;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
public class SoftSyncDetector implements ISyncProcessor
{
private ISyncDetectListener mListener;
private long mPattern;
private int mThreshold;
public SoftSyncDetector( ISyncDetectListener listener, long pattern, int threshold )
{
this( pattern, threshold );
mListener = listener;
}
public SoftSyncDetector( long pattern, int threshold )
{
mPattern = pattern;
mThreshold = threshold;
}
public void dispose()
{
mListener = null;
}
private ISyncDetectListener mListener;
private long mPattern;
private int mThreshold;
@Override
public void checkSync( long value )
{
long difference = value ^ mPattern;
if( ( difference == 0 || Long.bitCount( difference ) <= mThreshold ) &&
mListener != null )
{
mListener.syncDetected();
}
}
public void setThreshold( int threshold )
{
mThreshold = threshold;
}
public void setListener( ISyncDetectListener listener )
{
mListener = listener;
}
public SoftSyncDetector(ISyncDetectListener listener, long pattern, int threshold)
{
this(pattern, threshold);
mListener = listener;
}
public SoftSyncDetector(long pattern, int threshold)
{
mPattern = pattern;
mThreshold = threshold;
}
public void dispose()
{
mListener = null;
}
@Override
public boolean checkSync(long value)
{
long difference = value ^ mPattern;
if((difference == 0 || Long.bitCount(difference) <= mThreshold) &&
mListener != null)
{
mListener.syncDetected();
return true;
}
return false;
}
public void setThreshold(int threshold)
{
mThreshold = threshold;
}
public void setListener(ISyncDetectListener listener)
{
mListener = listener;
}
}

View File

@@ -1,35 +1,57 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* 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 the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.bits;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
public class SyncDetector implements ISyncProcessor
{
private long mPattern;
private ISyncDetectListener mListener;
private long mPattern;
private ISyncDetectListener mListener;
public SyncDetector( long pattern )
{
mPattern = pattern;
}
public SyncDetector( long pattern, ISyncDetectListener listener )
{
this( pattern );
mListener = listener;
}
public void setListener( ISyncDetectListener listener )
{
mListener = listener;
}
public SyncDetector(long pattern)
{
mPattern = pattern;
}
@Override
public void checkSync( long value )
{
if( value == mPattern && mListener != null )
{
mListener.syncDetected();
}
}
public SyncDetector(long pattern, ISyncDetectListener listener)
{
this(pattern);
mListener = listener;
}
public void setListener(ISyncDetectListener listener)
{
mListener = listener;
}
@Override
public boolean checkSync(long value)
{
if(value == mPattern)
{
if(mListener != null)
{
mListener.syncDetected();
}
return true;
}
return false;
}
}