#1397 Adds channel fft frequency overlay, cursor readout, pll tracking indicator, and channel bandwidth lines. (#1406)

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2023-01-13 04:28:00 -05:00
committed by GitHub
parent 8ce8aaddf9
commit f97b2150b9
27 changed files with 1406 additions and 529 deletions

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 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
@@ -427,9 +427,6 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
source.dispose();
}
break;
case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
//ignore
break;
case NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED:
//Rebroadcast so that the tuner source can process this event
mSourceEventBroadcaster.broadcast(sourceEvent);

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 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
@@ -28,6 +28,7 @@ import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.tuner.channel.StreamProcessorWithHeartbeat;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
@@ -45,9 +46,13 @@ public class PolyphaseChannelSource extends TunerChannelSource implements Listen
private StreamProcessorWithHeartbeat<ComplexSamples> mStreamHeartbeatProcessor;
private double mChannelSampleRate;
private long mIndexCenterFrequency;
private long mChannelFrequencyCorrection;
private ReentrantLock mOutputProcessorLock = new ReentrantLock();
private List<Integer> mOutputProcessorIndexes = new ArrayList<>();
private double mTunerSampleRate;
private double mTunerCenterFrequency;
/**
* Constructs an instance
*
@@ -66,6 +71,33 @@ public class PolyphaseChannelSource extends TunerChannelSource implements Listen
updateOutputProcessor(channelCalculator, filterManager);
}
/**
* Current output processor indexes.
* @return indexes
*/
public List<Integer> getOutputProcessorIndexes()
{
return mOutputProcessorIndexes;
}
/**
* Sample rate or bandwidth of the tuner providing input to the channelizer.
* @return sample rate
*/
public double getTunerSampleRate()
{
return mTunerSampleRate;
}
/**
* Center tuned frequency of the tuner providing input to the channelizer.
* @return center frequency
*/
public double getTunerCenterFrequency()
{
return mTunerCenterFrequency;
}
@Override
public void start()
{
@@ -125,6 +157,11 @@ public class PolyphaseChannelSource extends TunerChannelSource implements Listen
//calculator will throw an IllegalArgException ... handled below
List<Integer> indexes = channelCalculator.getChannelIndexes(getTunerChannel());
mOutputProcessorIndexes.clear();
mOutputProcessorIndexes.addAll(indexes);
mTunerCenterFrequency = channelCalculator.getCenterFrequency();
mTunerSampleRate = channelCalculator.getSampleRate();
//The provided channels are necessarily aligned to the center frequency that this source is providing and an
//oscillator will mix the provided channels to bring the desired center frequency to baseband.
setFrequency(channelCalculator.getCenterFrequencyForIndexes(indexes));
@@ -263,59 +300,32 @@ public class PolyphaseChannelSource extends TunerChannelSource implements Listen
}
}
@Override
public long getChannelFrequencyCorrection()
{
return mChannelFrequencyCorrection;
}
/**
* Adjusts the frequency correction value that is being applied to the channelized output stream by the
* polyphase channel output processor.
*
* @param value to apply for frequency correction in hertz
*/
protected void setChannelFrequencyCorrection(long value)
{
mChannelFrequencyCorrection = value;
updateFrequencyOffset();
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mChannelFrequencyCorrection));
}
/**
* Sets the center frequency for this channel.frequency for the incoming sample stream channel results and resets frequency correction to zero.
* Sets the center frequency for this channel.
* @param frequency in hertz
*/
@Override
public void setFrequency(long frequency)
{
mIndexCenterFrequency = frequency;
}
//Set frequency correction to zero to trigger an update to the mixer and allow downstream monitors to
//recalculate the frequency error correction again
setChannelFrequencyCorrection(0);
/**
* Center frequency from the incoming index channel(s).
* @return frequency in hertz
*/
public long getIndexCenterFrequency()
{
return mIndexCenterFrequency;
}
/**
* Calculates the frequency offset required to mix the incoming signal to center the desired frequency
* within the channel
*/
private long getFrequencyOffset()
public long getFrequencyOffset()
{
return mIndexCenterFrequency - getTunerChannel().getFrequency() + mChannelFrequencyCorrection;
}
/**
* Updates the frequency offset being applied by the output processor. Calculates the offset using the center
* frequency of the incoming polyphase channel results and the desired output channel frequency adjusted by any
* requested frequency correction value.
*/
private void updateFrequencyOffset()
{
if(mPolyphaseChannelOutputProcessor != null)
{
mPolyphaseChannelOutputProcessor.setFrequencyOffset(getFrequencyOffset());
}
return mIndexCenterFrequency - getTunerChannel().getFrequency();
}
@Override

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 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
@@ -72,6 +72,15 @@ public abstract class ComplexMixer
return mOscillator.hasFrequency();
}
/**
* Current frequency of this oscillator
* @return frequency in hertz
*/
public double getFrequency()
{
return mOscillator.getFrequency();
}
/**
* Sets the sample rate of the underlying oscillator
* @param sampleRate in Hertz

View File

@@ -0,0 +1,117 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.dsp.oscillator;
import io.github.dsheirer.sample.complex.ComplexSamples;
import java.util.Random;
/**
* Additive white gaussian noise wrapper around a complex oscillator that mixes in gaussian noise to the complex
* samples generated by the underlying complex oscillator.
*/
public class AWGNOscillator implements IComplexOscillator
{
private final Random mRandom = new Random();
private IComplexOscillator mComplexOscillator;
private float mNoiseScale;
/**
* Constructs an instance
* @param complexOscillator to generate samples
* @param noiseScale to apply to generated samples to reduce the power of the noise and increase the SNR.
*/
public AWGNOscillator(IComplexOscillator complexOscillator, float noiseScale)
{
mComplexOscillator = complexOscillator;
mNoiseScale = noiseScale;
}
/**
* Produce the next scaled noise sample.
* @return next scaled noise sample.
*/
private float nextNoise()
{
return (float)mRandom.nextGaussian() * mNoiseScale;
}
@Override
public float[] generate(int sampleCount)
{
float[] generated = mComplexOscillator.generate(sampleCount);
for(int x = 0; x < generated.length; x++)
{
generated[x] += nextNoise();
}
return generated;
}
@Override
public ComplexSamples generateComplexSamples(int sampleCount, long timestamp)
{
ComplexSamples samples = mComplexOscillator.generateComplexSamples(sampleCount, timestamp);
for(int x = 0; x < samples.i().length; x++)
{
samples.i()[x] += nextNoise();
samples.q()[x] += nextNoise();
}
return samples;
}
@Override
public double getFrequency()
{
return mComplexOscillator.getFrequency();
}
@Override
public void setFrequency(double frequency)
{
mComplexOscillator.setFrequency(frequency);
}
@Override
public boolean hasFrequency()
{
return mComplexOscillator.hasFrequency();
}
@Override
public double getSampleRate()
{
return mComplexOscillator.getSampleRate();
}
@Override
public void setSampleRate(double sampleRate)
{
mComplexOscillator.setSampleRate(sampleRate);
}
@Override
public boolean isEnabled()
{
return mComplexOscillator.isEnabled();
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.dsp.psk.pll;
@@ -101,7 +98,9 @@ public class FrequencyCorrectionSyncMonitor implements ISyncDetectListener, IFre
@Override
public void processFrequencyError(long frequencyError)
{
//Only rebroadcast the frequency error if the sync count is more than 2
mFeedbackDecoder.broadcast(SourceEvent.pllFrequencyMeasurement(frequencyError));
//Only rebroadcast as a frequency error measurement if the sync count is more than 2
if(mSyncCount > 2)
{
mFeedbackDecoder.broadcast(SourceEvent.frequencyErrorMeasurement(frequencyError));