mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
WIP - polyphase channelizer
This commit is contained in:
10
.idea/vcs.xml
generated
10
.idea/vcs.xml
generated
@@ -1,5 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="IssueNavigationConfiguration">
|
||||
<option name="links">
|
||||
<list>
|
||||
<IssueNavigationLink>
|
||||
<option name="issueRegexp" value="#(\d+)" />
|
||||
<option name="linkRegexp" value="https://github.com/DSheirer/sdrtrunk/issues/$1" />
|
||||
</IssueNavigationLink>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
|
||||
@@ -25,9 +25,9 @@ import source.tuner.TunerChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChannelizerConfiguration
|
||||
public class ChannelIndexCalculator
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelizerConfiguration.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelIndexCalculator.class);
|
||||
|
||||
private long mCenterFrequency;
|
||||
private int mChannelCount;
|
||||
@@ -35,16 +35,15 @@ public class ChannelizerConfiguration
|
||||
private double mOversampling = 1.0;
|
||||
|
||||
/**
|
||||
* Configuration details for a polyphase channelizer that can be used to identify which polyphase
|
||||
* channelizer output channel(s) should be processed to produce an output channel of a specified
|
||||
* center frequency and channel sample rate/bandwidth.
|
||||
* Calculates the channel index(es) from a polyphase channelizer output to source a DDC polyphase channel source
|
||||
* with a specified channel center frequency and bandwidth.
|
||||
*
|
||||
* @param centerFrequency
|
||||
* @param channelCount
|
||||
* @param channelBandwidth
|
||||
* @param oversampling set to 1.0 for no oversample, or greater than 1.0 for oversampling
|
||||
*/
|
||||
public ChannelizerConfiguration(long centerFrequency, int channelCount, int channelBandwidth, double oversampling)
|
||||
public ChannelIndexCalculator(long centerFrequency, int channelCount, int channelBandwidth, double oversampling)
|
||||
{
|
||||
mCenterFrequency = centerFrequency;
|
||||
mChannelCount = channelCount;
|
||||
@@ -289,19 +288,19 @@ public class ChannelizerConfiguration
|
||||
|
||||
int channelCount = 10;
|
||||
|
||||
ChannelizerConfiguration channelizerConfiguration =
|
||||
new ChannelizerConfiguration(100062500, channelCount, 12500, 2.0);
|
||||
ChannelIndexCalculator channelIndexCalculator =
|
||||
new ChannelIndexCalculator(100062500, channelCount, 12500, 2.0);
|
||||
|
||||
for(int x = 0; x < channelCount; x++)
|
||||
{
|
||||
mLog.debug("Channel " + x + ": " + channelizerConfiguration.getMinimumFrequencyForChannelIndex(x) + " - " +
|
||||
channelizerConfiguration.getMaximumFrequencyForChannelIndex(x) +
|
||||
" Center: " + channelizerConfiguration.getCenterFrequencyForChannelIndex(x));
|
||||
mLog.debug("Channel " + x + ": " + channelIndexCalculator.getMinimumFrequencyForChannelIndex(x) + " - " +
|
||||
channelIndexCalculator.getMaximumFrequencyForChannelIndex(x) +
|
||||
" Center: " + channelIndexCalculator.getCenterFrequencyForChannelIndex(x));
|
||||
}
|
||||
|
||||
TunerChannel tunerChannel = new TunerChannel(100006250, 12500);
|
||||
|
||||
List<Integer> indices = channelizerConfiguration.getPolyphaseChannelIndexes(tunerChannel);
|
||||
List<Integer> indices = channelIndexCalculator.getPolyphaseChannelIndexes(tunerChannel);
|
||||
|
||||
mLog.debug("Indices: " + indices);
|
||||
|
||||
@@ -32,7 +32,6 @@ import source.tuner.TunerChannel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class PolyphaseChannelManager implements ISourceEventProcessor, Listener<SourceEvent>
|
||||
{
|
||||
@@ -43,12 +42,16 @@ public class PolyphaseChannelManager implements ISourceEventProcessor, Listener<
|
||||
|
||||
private Tuner mTuner;
|
||||
private List<PolyphaseChannelSource> mChannelSources = new CopyOnWriteArrayList<>();
|
||||
private ChannelizerConfiguration mChannelizerConfiguration;
|
||||
private ChannelIndexCalculator mChannelIndexCalculator;
|
||||
private ComplexPolyphaseChannelizerM2 mPolyphaseChannelizer;
|
||||
|
||||
/**
|
||||
* Provides access to Digital Drop Channel (DDC) sources from a tuner. Incorporates a polyphase channelizer
|
||||
* with downstream channel and upstream tuner management.
|
||||
* Polyphase Channel Manager is a DDC channel manager for a tuner. This class provides DDC polyphase channel
|
||||
* sources and wraps a polyphase channelizer processing sample buffers produced by the tuner and distributing
|
||||
* channelized sample buffers to each allocated DDC polyphase channel source. This class is responsible for
|
||||
* monitoring the tuner for changes in center frequency and/or sample rate and updating active DDC polyphase channel
|
||||
* sources accordingly. This class also monitors source event requests and notifications received from active DDC
|
||||
* polyphase channel sources to adjust sample streams as required.
|
||||
*
|
||||
* @param tuner providing broadband sample buffers
|
||||
*/
|
||||
@@ -74,8 +77,8 @@ public class PolyphaseChannelManager implements ISourceEventProcessor, Listener<
|
||||
|
||||
long frequency = mTuner.getTunerController().getFrequency();
|
||||
|
||||
mChannelizerConfiguration = new ChannelizerConfiguration(frequency, channelCount,
|
||||
CHANNEL_BANDWIDTH, CHANNEL_OVERSAMPLING);
|
||||
mChannelIndexCalculator = new ChannelIndexCalculator(frequency, channelCount, CHANNEL_BANDWIDTH,
|
||||
CHANNEL_OVERSAMPLING);
|
||||
|
||||
mTuner.addSourceEventListener(this);
|
||||
}
|
||||
@@ -90,41 +93,42 @@ public class PolyphaseChannelManager implements ISourceEventProcessor, Listener<
|
||||
{
|
||||
PolyphaseChannelSource channelSource = null;
|
||||
|
||||
IPolyphaseChannelOutputProcessor outputProcessor = null;
|
||||
|
||||
try
|
||||
{
|
||||
List<Integer> polyphaseIndexes = mChannelizerConfiguration.getPolyphaseChannelIndexes(tunerChannel);
|
||||
List<Integer> polyphaseIndexes = mChannelIndexCalculator.getPolyphaseChannelIndexes(tunerChannel);
|
||||
|
||||
switch(polyphaseIndexes.size())
|
||||
IPolyphaseChannelOutputProcessor outputProcessor = getOutputProcessor(polyphaseIndexes);
|
||||
|
||||
if(outputProcessor != null)
|
||||
{
|
||||
case 1:
|
||||
outputProcessor = new OneChannelOutputProcessor(CHANNEL_SAMPLE_RATE, polyphaseIndexes);
|
||||
break;
|
||||
case 2:
|
||||
outputProcessor = new TwoChannelOutputProcessor(CHANNEL_SAMPLE_RATE, polyphaseIndexes);
|
||||
break;
|
||||
default:
|
||||
//TODO: create output processor for greater than 2 input channels
|
||||
break;
|
||||
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, this);
|
||||
mChannelSources.add(channelSource);
|
||||
}
|
||||
}
|
||||
catch(IllegalArgumentException iae)
|
||||
{
|
||||
mLog.info("Can't provide DDC for " + tunerChannel.toString() + " due to channelizer frequency [" +
|
||||
mChannelizerConfiguration.getCenterFrequency() + "] and sample rate [" +
|
||||
(mChannelizerConfiguration.getChannelCount() * mChannelizerConfiguration.getChannelBandwidth()) + "]");
|
||||
}
|
||||
|
||||
if(outputProcessor != null)
|
||||
{
|
||||
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, this);
|
||||
mChannelSources.add(channelSource);
|
||||
mChannelIndexCalculator.getCenterFrequency() + "] and sample rate [" +
|
||||
(mChannelIndexCalculator.getChannelCount() * mChannelIndexCalculator.getChannelBandwidth()) + "]");
|
||||
}
|
||||
|
||||
return channelSource;
|
||||
}
|
||||
|
||||
private IPolyphaseChannelOutputProcessor getOutputProcessor(List<Integer> indexes) throws IllegalArgumentException
|
||||
{
|
||||
switch(indexes.size())
|
||||
{
|
||||
case 1:
|
||||
return new OneChannelOutputProcessor(CHANNEL_SAMPLE_RATE, indexes);
|
||||
case 2:
|
||||
return new TwoChannelOutputProcessor(CHANNEL_SAMPLE_RATE, indexes);
|
||||
default:
|
||||
//TODO: create output processor for greater than 2 input channels
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts/adds the channel source to receive channelized sample buffers, registering with the tuner to receive
|
||||
* sample buffers when this is the first channel.
|
||||
@@ -157,6 +161,9 @@ public class PolyphaseChannelManager implements ISourceEventProcessor, Listener<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes source events from the tuner or from any of the child polyphase channel sources.
|
||||
*/
|
||||
@Override
|
||||
public void process(SourceEvent sourceEvent)
|
||||
{
|
||||
@@ -169,7 +176,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor, Listener<
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.error("Request to stop sample stream for unrecognized source: " +
|
||||
mLog.error("Request to start sample stream for unrecognized source: " +
|
||||
(sourceEvent.hasSource() ? sourceEvent.getSource().getClass() : "null source"));
|
||||
}
|
||||
//TODO: add the channel and register for samples from the tuner
|
||||
@@ -186,29 +193,69 @@ public class PolyphaseChannelManager implements ISourceEventProcessor, Listener<
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_FREQUENCY_CHANGE:
|
||||
mChannelizerConfiguration.setCenterFrequency(sourceEvent.getValue().longValue());
|
||||
updateChannelResultsProcessors();
|
||||
mChannelIndexCalculator.setCenterFrequency(sourceEvent.getValue().longValue());
|
||||
updateOutputProcessors();
|
||||
break;
|
||||
case NOTIFICATION_SAMPLE_RATE_CHANGE:
|
||||
int sampleRate = sourceEvent.getValue().intValue();
|
||||
int channelCount = sampleRate / mChannelizerConfiguration.getChannelBandwidth();
|
||||
mChannelizerConfiguration.setChannelCount(channelCount);
|
||||
updateChannelResultsProcessors();
|
||||
int channelCount = sampleRate / mChannelIndexCalculator.getChannelBandwidth();
|
||||
mChannelIndexCalculator.setChannelCount(channelCount);
|
||||
updateOutputProcessors();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Listener<SourceEvent> interface by delegating to the process(sourceEvent) method.
|
||||
*/
|
||||
@Override
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
process(sourceEvent);
|
||||
}
|
||||
|
||||
private void updateChannelResultsProcessors()
|
||||
/**
|
||||
* Updates each of the output processors for any changes in the tuner's center frequency or sample rate, which
|
||||
* would cause the output processors to change the polyphase channelizer results channel(s) that the processor is
|
||||
* consuming
|
||||
*/
|
||||
private void updateOutputProcessors()
|
||||
{
|
||||
//Update the processors anytime that the center frequency or sample rate changes
|
||||
for(PolyphaseChannelSource channelSource: mChannelSources)
|
||||
{
|
||||
updateOutputProcessor(channelSource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the polyphase channel source's output processor due to a change in the center frequency or sample
|
||||
* rate for the source providing sample buffers to the polyphase channelizer, or whenever the DDC channel's
|
||||
* center tuned frequency changes.
|
||||
*
|
||||
* @param channelSource that requires an update to its output processor
|
||||
*/
|
||||
private void updateOutputProcessor(PolyphaseChannelSource channelSource)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Integer> indexes = mChannelIndexCalculator.getPolyphaseChannelIndexes(channelSource.getTunerChannel());
|
||||
|
||||
//If the indexes size is the same then update the current processor, otherwise create a new one
|
||||
if(channelSource.getPolyphaseChannelOutputProcessor().getInputChannelCount() == indexes.size())
|
||||
{
|
||||
channelSource.getPolyphaseChannelOutputProcessor().setPolyphaseChannelIndices(indexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
channelSource.setPolyphaseChannelOutputProcessor(getOutputProcessor(indexes));
|
||||
}
|
||||
}
|
||||
catch(IllegalArgumentException iae)
|
||||
{
|
||||
mLog.error("Error updating polyphase channel source - can't determine output channel indexes for " +
|
||||
"updated tuner center frequency and sample rate. Stopping channel source", iae);
|
||||
|
||||
stopChannelSource(channelSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,33 @@ public class PolyphaseChannelSource extends ComplexChannelSource
|
||||
mPolyphaseChannelOutputProcessor = outputProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel output processor used by this channel source.
|
||||
*/
|
||||
public IPolyphaseChannelOutputProcessor getPolyphaseChannelOutputProcessor()
|
||||
{
|
||||
return mPolyphaseChannelOutputProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the output processor for this channel source
|
||||
*/
|
||||
public void setPolyphaseChannelOutputProcessor(IPolyphaseChannelOutputProcessor outputProcessor)
|
||||
{
|
||||
synchronized(mPolyphaseChannelOutputProcessor)
|
||||
{
|
||||
mPolyphaseChannelOutputProcessor = outputProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tuner channel sourced by this channel source.
|
||||
*/
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
return mTunerChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process source event notifications received from upstream source provider and source event requests
|
||||
* received from downstream consumers.
|
||||
|
||||
@@ -23,20 +23,29 @@ import sample.complex.Complex;
|
||||
|
||||
public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputProcessor
|
||||
{
|
||||
private int mInputChannelCount;
|
||||
private Oscillator mFrequencyCorrectionMixer;
|
||||
|
||||
/**
|
||||
* Base class for polyphase channelizer output channel processing. Provides built-in frequency translation
|
||||
* oscillator support to apply frequency correction to the channel sample stream as requested by sample consumer.
|
||||
*
|
||||
* @param inputChannelCount is the number of input channels for this output processor
|
||||
* @param sampleRate of the output channel. This is used to match the oscillator's sample rate to the output
|
||||
* channel sample rate for frequency translation/correction.
|
||||
*/
|
||||
public ChannelOutputProcessor(int sampleRate)
|
||||
public ChannelOutputProcessor(int inputChannelCount, int sampleRate)
|
||||
{
|
||||
mInputChannelCount = inputChannelCount;
|
||||
mFrequencyCorrectionMixer = new Oscillator(0, sampleRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInputChannelCount()
|
||||
{
|
||||
return mInputChannelCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides frequency correction of the inphase component or simply returns the inphase argument value when no
|
||||
* frequency correction value has been specified.
|
||||
|
||||
@@ -20,6 +20,8 @@ package dsp.filter.channelizer.output;
|
||||
|
||||
import sample.complex.IComplexSampleListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IPolyphaseChannelOutputProcessor
|
||||
{
|
||||
/**
|
||||
@@ -37,4 +39,16 @@ public interface IPolyphaseChannelOutputProcessor
|
||||
* @param frequencyCorrection correction value
|
||||
*/
|
||||
void setFrequencyCorrection(long frequencyCorrection);
|
||||
|
||||
/**
|
||||
* Indicates the number of input channels processed by this output processor
|
||||
* @return
|
||||
*/
|
||||
int getInputChannelCount();
|
||||
|
||||
/**
|
||||
* Updates the input polyphase channel index(es) used by this output processor
|
||||
* @param indexes
|
||||
*/
|
||||
void setPolyphaseChannelIndices(List<Integer> indexes);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class OneChannelOutputProcessor extends ChannelOutputProcessor
|
||||
*/
|
||||
public OneChannelOutputProcessor(int sampleRate, List<Integer> channelIndexes)
|
||||
{
|
||||
super(sampleRate);
|
||||
super(1, sampleRate);
|
||||
setPolyphaseChannelIndices(channelIndexes);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
|
||||
{
|
||||
//Set the frequency correction oscillator to 2 x output sample rate since we'll be correcting the frequency
|
||||
//after synthesizing both input channels
|
||||
super(sampleRate * 2);
|
||||
super(2, sampleRate * 2);
|
||||
setPolyphaseChannelIndices(channelIndexes);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user