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,3 +1,18 @@
/*******************************************************************************
* 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.source.tuner;
import io.github.dsheirer.properties.SystemProperties;
@@ -31,17 +46,19 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
public static final int SAMPLE_RATE = 2;
public static final int FREQUENCY = 3;
public static final int CHANNEL_COUNT = 4;
public static final int SPECTRAL_DISPLAY_MAIN = 5;
public static final int SPECTRAL_DISPLAY_NEW = 6;
public static final int FREQUENCY_ERROR = 5;
public static final int MEASURED_FREQUENCY_ERROR = 6;
public static final int SPECTRAL_DISPLAY_NEW = 7;
private static final String MHZ = " MHz";
private static final String[] COLUMNS =
{"Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Spectral", "Display"};
private static final String[] COLUMNS = {"Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Current PPM",
"Measured Error", "Display"};
private List<Tuner> mTuners = new ArrayList<>();
private List<Listener<TunerEvent>> mTunerEventListeners = new ArrayList<>();
private DecimalFormat mFrequencyFormat = new DecimalFormat("0.00000");
private DecimalFormat mSampleRateFormat = new DecimalFormat("0.000");
private DecimalFormat mFrequencyErrorPPMFormat = new DecimalFormat("0.0");
private TunerConfigurationModel mTunerConfigurationModel;
@@ -206,15 +223,21 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
case CHANNEL_COUNT:
fireTableCellUpdated(index, CHANNEL_COUNT);
break;
case FREQUENCY:
case FREQUENCY_UPDATED:
fireTableCellUpdated(index, FREQUENCY);
mTunerConfigurationModel.tunerFrequencyChanged(event.getTuner());
break;
case SAMPLE_RATE:
case FREQUENCY_ERROR_UPDATED:
fireTableCellUpdated(index, FREQUENCY_ERROR);
break;
case MEASURED_FREQUENCY_ERROR_UPDATED:
fireTableCellUpdated(index, MEASURED_FREQUENCY_ERROR);
break;
case SAMPLE_RATE_UPDATED:
fireTableCellUpdated(index, SAMPLE_RATE);
break;
case REQUEST_MAIN_SPECTRAL_DISPLAY:
fireTableCellUpdated(index, SPECTRAL_DISPLAY_MAIN);
fireTableCellUpdated(index, MEASURED_FREQUENCY_ERROR);
default:
break;
}
@@ -275,8 +298,21 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
{
return "0";
}
case SPECTRAL_DISPLAY_MAIN:
return "Main";
case FREQUENCY_ERROR:
double ppm = tuner.getTunerController().getFrequencyCorrection();
return mFrequencyErrorPPMFormat.format(ppm);
case MEASURED_FREQUENCY_ERROR:
if(tuner.getTunerController().hasMeasuredFrequencyError())
{
StringBuilder sb = new StringBuilder();
sb.append(tuner.getTunerController().getMeasuredFrequencyError());
sb.append("Hz (");
sb.append(mFrequencyErrorPPMFormat.format(tuner.getTunerController().getPPMFrequencyError()));
sb.append("ppm)");
return sb.toString();
}
return "";
case SPECTRAL_DISPLAY_NEW:
return "New";
default: