mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
#2212 Introduce carrier offset measurement processor to monitor a 12.5 kHz channel and provide estimated carrier offset measurements that allow the tuner's frequency error monitor to correct for the average error reported from each channel. Uses a 15 dB threshold where the signal must be at least 15 dB above the noise floor before it will calculate and broadcast the estimate. Stores the updated PPM in the tuner configuration after each update to ensure the value persists across sessions. When selected in the tuner panel, updates the displayed PPM value after each PPM autocorrection. (#2218)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
* Copyright (C) 2014-2025 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
|
||||
@@ -41,7 +41,7 @@ public class SourceEvent
|
||||
NOTIFICATION_FREQUENCY_ROTATION_FAILURE,
|
||||
NOTIFICATION_MEASURED_FREQUENCY_ERROR,
|
||||
NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED,
|
||||
NOTIFICATION_PLL_FREQUENCY,
|
||||
NOTIFICATION_CARRIER_OFFSET_FREQUENCY,
|
||||
NOTIFICATION_RECORDING_FILE_LOADED,
|
||||
NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
NOTIFICATION_SQUELCH_THRESHOLD,
|
||||
@@ -245,13 +245,13 @@ public class SourceEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new PLL frequency error measurement notification event.
|
||||
* Creates a new carrier offset measurement notification event.
|
||||
*
|
||||
* @param frequencyError in hertz
|
||||
* @param carrierOffset in hertz
|
||||
*/
|
||||
public static SourceEvent pllFrequencyMeasurement(long frequencyError)
|
||||
public static SourceEvent carrierOffsetMeasurement(long carrierOffset)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_PLL_FREQUENCY, frequencyError);
|
||||
return new SourceEvent(Event.NOTIFICATION_CARRIER_OFFSET_FREQUENCY, carrierOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -318,7 +318,7 @@ public class SourceEvent
|
||||
/**
|
||||
* Creates a new channel count change event
|
||||
*
|
||||
* @param channelCount
|
||||
* @param channelCount of channels
|
||||
*/
|
||||
public static SourceEvent channelCountChange(int channelCount)
|
||||
{
|
||||
|
||||
@@ -596,6 +596,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
||||
public void setMeasuredFrequencyError(int measuredFrequencyError)
|
||||
{
|
||||
mMeasuredFrequencyError = measuredFrequencyError;
|
||||
getFrequencyErrorCorrectionManager().updatePPM(getPPMFrequencyError());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -201,7 +201,6 @@ public class AirspyTunerController extends USBTunerController
|
||||
{
|
||||
setFrequency(config.getFrequency());
|
||||
setFrequencyCorrection(config.getFrequencyCorrection());
|
||||
getFrequencyErrorCorrectionManager().setEnabled(config.getAutoPPMCorrectionEnabled());
|
||||
|
||||
setIFGain(config.getIFGain());
|
||||
setMixerGain(config.getMixerGain());
|
||||
|
||||
@@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -147,9 +147,9 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED:
|
||||
case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED:
|
||||
case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
|
||||
case NOTIFICATION_PLL_FREQUENCY:
|
||||
case NOTIFICATION_CARRIER_OFFSET_FREQUENCY:
|
||||
case NOTIFICATION_STOP_SAMPLE_STREAM:
|
||||
case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
|
||||
//no-op
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
@@ -198,7 +198,7 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
* Broadcasts the source event to the outbound sample stream consumer.
|
||||
* @param sourceEvent to broadcast
|
||||
*/
|
||||
protected void broadcastConsumerSourceEvent(SourceEvent sourceEvent)
|
||||
public void broadcastConsumerSourceEvent(SourceEvent sourceEvent)
|
||||
{
|
||||
if(mConsumerSourceEventListener != null)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2025 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
|
||||
@@ -179,7 +179,30 @@ public class TunerConfigurationManager implements IDiscoveredTunerStatusListener
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tuner configuration with the current tuner PPM setting so that the value can be stored across
|
||||
* sessions.
|
||||
* @param discoveredTuner that has an updated PPM value.
|
||||
*/
|
||||
public void updateTunerPPM(DiscoveredTuner discoveredTuner)
|
||||
{
|
||||
if(discoveredTuner != null)
|
||||
{
|
||||
TunerType tunerType = discoveredTuner.getTuner().getTunerType();
|
||||
|
||||
if(tunerType != TunerType.RECORDING)
|
||||
{
|
||||
TunerConfiguration tunerConfiguration = getTunerConfiguration(tunerType, discoveredTuner.getId());
|
||||
|
||||
if(tunerConfiguration != null)
|
||||
{
|
||||
tunerConfiguration.setFrequencyCorrection(discoveredTuner.getTuner().getTunerController().getFrequencyCorrection());
|
||||
saveConfigurations();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2025 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
|
||||
@@ -20,11 +20,10 @@ package io.github.dsheirer.source.tuner.manager;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import java.text.DecimalFormat;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
* Monitors measured frequency error PPM values from the tuner and (when enabled) applies the current
|
||||
* error measurement to the tuner controller to adjust the tuner's PPM and align the frequency value.
|
||||
@@ -35,6 +34,7 @@ public class FrequencyErrorCorrectionManager
|
||||
|
||||
private static final double FREQUENCY_CORRECTION_ERROR_THRESHOLD = 0.4;
|
||||
private static final long AUTO_CORRECTION_OBSERVATION_PERIOD_MILLISECONDS = 30 * 1000; //30 seconds
|
||||
private static final long INITIAL_AUTO_CORRECTION_OBSERVATION_PERIOD_MILLISECONDS = 5 * 1000; //5 seconds
|
||||
private long mObservationPeriodStart;
|
||||
private double mPPMRequired;
|
||||
private boolean mEnabled = true;
|
||||
@@ -97,7 +97,6 @@ public class FrequencyErrorCorrectionManager
|
||||
try
|
||||
{
|
||||
mLog.info("Auto-Correcting Tuner PPM to [" + mDecimalFormat.format(frequencyCorrection) + "]");
|
||||
|
||||
mTunerController.setFrequencyCorrection(frequencyCorrection);
|
||||
reset();
|
||||
}
|
||||
@@ -117,7 +116,8 @@ public class FrequencyErrorCorrectionManager
|
||||
{
|
||||
if(mObservationPeriodStart == 0)
|
||||
{
|
||||
mObservationPeriodStart = System.currentTimeMillis();
|
||||
mObservationPeriodStart = System.currentTimeMillis() - AUTO_CORRECTION_OBSERVATION_PERIOD_MILLISECONDS +
|
||||
INITIAL_AUTO_CORRECTION_OBSERVATION_PERIOD_MILLISECONDS;
|
||||
mPPMRequired = ppm;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -70,11 +70,11 @@ import org.usb4java.LibUsb;
|
||||
public class TunerManager implements IDiscoveredTunerStatusListener
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(TunerManager.class);
|
||||
private UserPreferences mUserPreferences;
|
||||
private DiscoveredTunerModel mDiscoveredTunerModel = new DiscoveredTunerModel();
|
||||
private TunerConfigurationManager mTunerConfigurationManager;
|
||||
private HotplugEventSupport mHotplugEventSupport = new HotplugEventSupport();
|
||||
private Context mLibUsbApplicationContext = new Context();
|
||||
private final UserPreferences mUserPreferences;
|
||||
private final DiscoveredTunerModel mDiscoveredTunerModel;
|
||||
private final TunerConfigurationManager mTunerConfigurationManager;
|
||||
private final HotplugEventSupport mHotplugEventSupport = new HotplugEventSupport();
|
||||
private final Context mLibUsbApplicationContext = new Context();
|
||||
private boolean mLibUsbInitialized = false;
|
||||
private SDRplay mSDRplay;
|
||||
|
||||
@@ -86,6 +86,7 @@ public class TunerManager implements IDiscoveredTunerStatusListener
|
||||
{
|
||||
mUserPreferences = userPreferences;
|
||||
mTunerConfigurationManager = new TunerConfigurationManager(userPreferences);
|
||||
mDiscoveredTunerModel = new DiscoveredTunerModel(mTunerConfigurationManager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -297,18 +297,6 @@ public class RTL2832TunerController extends USBTunerController
|
||||
return mBiasTEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides updates for measured frequency error so that the updates can also be applied to the
|
||||
* frequency error correction manager for automatic PPM updating.
|
||||
* @param measuredFrequencyError in hertz averaged over a 5 second interval.
|
||||
*/
|
||||
@Override
|
||||
public void setMeasuredFrequencyError(int measuredFrequencyError)
|
||||
{
|
||||
super.setMeasuredFrequencyError(measuredFrequencyError);
|
||||
getFrequencyErrorCorrectionManager().updatePPM(getPPMFrequencyError());
|
||||
}
|
||||
|
||||
private void setIFFrequency(int frequency) throws LibUsbException
|
||||
{
|
||||
long ifFrequency = ((long) TWO_TO_22_POWER * (long) frequency) / (long) mOscillatorFrequency * -1;
|
||||
|
||||
@@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,6 +21,7 @@ package io.github.dsheirer.source.tuner.ui;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationManager;
|
||||
import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
|
||||
import io.github.dsheirer.source.tuner.manager.DiscoveredUSBTuner;
|
||||
import io.github.dsheirer.source.tuner.manager.IDiscoveredTunerStatusListener;
|
||||
@@ -62,13 +63,15 @@ public class DiscoveredTunerModel extends AbstractTableModel implements Listener
|
||||
private List<Listener<TunerEvent>> mTunerEventListeners = new ArrayList<>();
|
||||
private DecimalFormat mFrequencyFormat = new DecimalFormat("0.00000");
|
||||
private Lock mLock = new ReentrantLock();
|
||||
|
||||
private TunerConfigurationManager mTunerConfigurationManager;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param tunerConfigurationManager to update tuner configurations from tuners.
|
||||
*/
|
||||
public DiscoveredTunerModel()
|
||||
public DiscoveredTunerModel(TunerConfigurationManager tunerConfigurationManager)
|
||||
{
|
||||
mTunerConfigurationManager = tunerConfigurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -425,8 +428,8 @@ public class DiscoveredTunerModel extends AbstractTableModel implements Listener
|
||||
|
||||
try
|
||||
{
|
||||
DiscoveredTuner matching = getDiscoveredTuner(event.getTuner());
|
||||
int index = mDiscoveredTuners.indexOf(matching);
|
||||
DiscoveredTuner matchingTuner = getDiscoveredTuner(event.getTuner());
|
||||
int index = mDiscoveredTuners.indexOf(matchingTuner);
|
||||
|
||||
if(index >= 0)
|
||||
{
|
||||
@@ -441,6 +444,12 @@ public class DiscoveredTunerModel extends AbstractTableModel implements Listener
|
||||
case NOTIFICATION_ERROR_STATE:
|
||||
EventQueue.invokeLater(() -> fireTableRowsUpdated(index, index));
|
||||
break;
|
||||
case UPDATE_FREQUENCY_ERROR:
|
||||
if(mTunerConfigurationManager != null)
|
||||
{
|
||||
mTunerConfigurationManager.updateTunerPPM(matchingTuner);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -755,9 +755,11 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
|
||||
@Override
|
||||
public void receive(TunerEvent tunerEvent)
|
||||
{
|
||||
if(tunerEvent.getEvent().equals(TunerEvent.Event.UPDATE_MEASURED_FREQUENCY_ERROR))
|
||||
switch(tunerEvent.getEvent())
|
||||
{
|
||||
SwingUtils.run(() -> getFrequencyPanel().updateFrequencyError());
|
||||
//Note: called methods are responsible for executing on the swing thread.
|
||||
case UPDATE_MEASURED_FREQUENCY_ERROR -> getFrequencyPanel().updateFrequencyError();
|
||||
case UPDATE_FREQUENCY_ERROR -> getFrequencyPanel().updatePPM();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,6 +948,18 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates or refreshes the displayed tuner PPM setting.
|
||||
*/
|
||||
public void updatePPM()
|
||||
{
|
||||
SwingUtils.run(() -> {
|
||||
setLoading(true);
|
||||
getFrequencyCorrectionSpinner().setValue(getTuner().getTunerController().getFrequencyCorrection());
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
* Copyright (C) 2014-2025 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
|
||||
@@ -124,6 +124,19 @@ public class ComplexWaveSource extends Source implements IControllableFileSource
|
||||
// return (int)(getSampleRate() / 20.0d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio format for the currently opened or started source file.
|
||||
*/
|
||||
public AudioFormat getAudioFormat()
|
||||
{
|
||||
if(mInputStream == null)
|
||||
{
|
||||
throw new IllegalStateException("Source not opened or started");
|
||||
}
|
||||
|
||||
return mInputStream.getFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user