Merge pull request #420 from DSheirer/419-heterdyne-channelizer-center-frequency-tuning

419 Heterodyne Channelizer Center Frequency Calculations
This commit is contained in:
Denny Sheirer
2018-09-16 06:04:09 -04:00
committed by GitHub
3 changed files with 139 additions and 43 deletions

View File

@@ -26,12 +26,15 @@ import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceEventListenerToProcessorAdapter;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.frequency.FrequencyController;
import io.github.dsheirer.source.tuner.frequency.FrequencyController.Tunable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.SortedSet;
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
IReusableComplexBufferProvider, Listener<ReusableComplexBuffer>
{
@@ -361,4 +364,85 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
{
broadcast(complexBuffer);
}
/**
* Indicates if the current center frequency and bandwidth is correct to source the tuner channel
*
* @param tunerChannel to test
* @return true if the current center frequency and bandwidth is correct for the channel
*/
public boolean isTunedFor(TunerChannel tunerChannel)
{
try
{
if(tunerChannel.getMinFrequency() < getMinTunedFrequency())
{
return false;
}
if(tunerChannel.getMaxFrequency() > getMaxTunedFrequency())
{
return false;
}
if(hasMiddleUnusableBandwidth())
{
long minAvoid = getFrequency() - getMiddleUnusableHalfBandwidth();
long maxAvoid = getFrequency() + getMiddleUnusableHalfBandwidth();
if(tunerChannel.overlaps(minAvoid, maxAvoid))
{
return false;
}
}
}
catch(SourceException se)
{
return false;
}
return true;
}
/**
* Indicates if the current center frequency and bandwidth is correct to source the tuner channel set
*
* @param tunerChannels to test
* @return true if the current center frequency and bandwidth is correct for the channel set
*/
public boolean isTunedFor(SortedSet<TunerChannel> tunerChannels)
{
try
{
if(tunerChannels.first().getMinFrequency() < getMinTunedFrequency())
{
return false;
}
if(tunerChannels.last().getMaxFrequency() > getMaxTunedFrequency())
{
return false;
}
if(hasMiddleUnusableBandwidth())
{
long minAvoid = getFrequency() - getMiddleUnusableHalfBandwidth();
long maxAvoid = getFrequency() + getMiddleUnusableHalfBandwidth();
for(TunerChannel tunerChannel: tunerChannels)
{
if(tunerChannel.overlaps(minAvoid, maxAvoid))
{
return false;
}
}
}
}
catch(SourceException se)
{
return false;
}
return true;
}
}

View File

@@ -54,48 +54,57 @@ public class CenterFrequencyCalculator
//Start by placing the highest frequency channel at the high end of the spectrum
candidateFrequency = maxChannelFrequency - (tunerController.getUsableBandwidth() / 2);
//Iterate the channels and make sure that none of them overlap the center DC spike buffer, if one exists
if(tunerController.getMiddleUnusableHalfBandwidth() > 0)
if(maxChannelFrequency - minChannelFrequency <= tunerController.getUsableHalfBandwidth())
{
boolean processingRequired = true;
while(isValidCandidateFrequency && processingRequired)
candidateFrequency = minChannelFrequency - tunerController.getMiddleUnusableHalfBandwidth();
isValidCandidateFrequency = true;
}
else
{
//Iterate the channels and make sure that none of them overlap the center DC spike buffer, if one exists
if(tunerController.getMiddleUnusableHalfBandwidth() > 0)
{
processingRequired = false;
boolean processingRequired = true;
long minAvoid = candidateFrequency - tunerController.getMiddleUnusableHalfBandwidth();
long maxAvoid = candidateFrequency + tunerController.getMiddleUnusableHalfBandwidth();
//If any of the center channel(s) overlap the central DC spike avoid area, we'll iteratively
//increase the tuned frequency causing the set of channels to move left in the tuned bandwidth until
//we either find a good center tune frequency, or we walk the lowest frequency channel out of the
//minimum tuned range, in which case we'll throw an exception indicating we don't have a solution.
for(TunerChannel channel : channels)
while(isValidCandidateFrequency && processingRequired)
{
if(channel.overlaps(minAvoid, maxAvoid))
processingRequired = false;
long minAvoid = candidateFrequency - tunerController.getMiddleUnusableHalfBandwidth();
long maxAvoid = candidateFrequency + tunerController.getMiddleUnusableHalfBandwidth();
//If any of the center channel(s) overlap the central DC spike avoid area, we'll iteratively
//increase the tuned frequency causing the set of channels to move left in the tuned bandwidth until
//we either find a good center tune frequency, or we walk the lowest frequency channel out of the
//minimum tuned range, in which case we'll throw an exception indicating we don't have a solution.
for(TunerChannel channel : channels)
{
//Calculate a tuned frequency adjustment that places this overlapping channel just to the
//left of the central DC spike avoid zone
long adjustment = channel.getMaxFrequency() - minAvoid + 1;
//If the candidate frequency doesn't push the lowest channel out of bounds, make adjustment
if(candidateFrequency + adjustment - (tunerController.getUsableBandwidth() / 2) <= minChannelFrequency)
if(channel.overlaps(minAvoid, maxAvoid))
{
candidateFrequency += adjustment;
processingRequired = true;
}
//Otherwise, punt and indicate that we can't find a center frequency or add the channel
else
{
isValidCandidateFrequency = false;
}
//Calculate a tuned frequency adjustment that places this overlapping channel just to the
//left of the central DC spike avoid zone
long adjustment = channel.getMaxFrequency() - minAvoid + 1;
//break out of the for/each loop, so that we can start over again with all of the channels
break;
//If the candidate frequency doesn't push the lowest channel out of bounds, make adjustment
if(candidateFrequency + adjustment - (tunerController.getUsableBandwidth() / 2) <= minChannelFrequency)
{
candidateFrequency += adjustment;
processingRequired = true;
}
//Otherwise, punt and indicate that we can't find a center frequency or add the channel
else
{
isValidCandidateFrequency = false;
}
//break out of the for/each loop, so that we can start over again with all of the channels
break;
}
}
}
}
}
}
if(isValidCandidateFrequency)

View File

@@ -108,23 +108,26 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
*/
private void updateTunerFrequency()
{
long centerFrequency = CenterFrequencyCalculator.getCenterFrequency(mTunerController, getTunerChannels());
if(centerFrequency == CenterFrequencyCalculator.INVALID_FREQUENCY)
if(!mTunerController.isTunedFor(getTunerChannels()))
{
mLog.error("Couldn't calculate center frequency for tuner and tuner channels");
return;
}
long centerFrequency = CenterFrequencyCalculator.getCenterFrequency(mTunerController, getTunerChannels());
if(centerFrequency != mTunerController.getFrequency())
{
try
if(centerFrequency == CenterFrequencyCalculator.INVALID_FREQUENCY)
{
mTunerController.setFrequency(centerFrequency);
mLog.error("Couldn't calculate center frequency for tuner and tuner channels");
return;
}
catch(SourceException se)
if(centerFrequency != mTunerController.getFrequency())
{
mLog.error("Couldn't update tuner center frequency to " + centerFrequency, se);
try
{
mTunerController.setFrequency(centerFrequency);
}
catch(SourceException se)
{
mLog.error("Couldn't update tuner center frequency to " + centerFrequency, se);
}
}
}
}