mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-10 23:57:25 -05:00
Merge pull request #430 from DSheirer/429-polyphase-channelizer-25khz-channel-rate
429 polyphase channelizer 25khz channel rate
This commit is contained in:
@@ -63,7 +63,7 @@ public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChann
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ComplexPolyphaseChannelizerM2.class);
|
||||
|
||||
private static final int DEFAULT_MINIMUM_CHANNEL_BANDWIDTH = 12500;
|
||||
private static final int DEFAULT_MINIMUM_CHANNEL_BANDWIDTH = 25000;
|
||||
|
||||
//Sized at 152 buffers a second where max = 5 seconds and reset = 2 seconds worth of buffers
|
||||
private IFFTProcessor mIFFTProcessor = new IFFTProcessor((5 * 152), (2 * 152));
|
||||
|
||||
@@ -29,6 +29,7 @@ import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerController;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import org.slf4j.Logger;
|
||||
@@ -62,7 +63,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
public class PolyphaseChannelManager implements ISourceEventProcessor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelManager.class);
|
||||
private static final double MINIMUM_CHANNEL_BANDWIDTH = 12500.0;
|
||||
private static final double MINIMUM_CHANNEL_BANDWIDTH = 25000.0;
|
||||
private static final double CHANNEL_OVERSAMPLING = 2.0;
|
||||
private static final int POLYPHASE_CHANNELIZER_TAPS_PER_CHANNEL = 9;
|
||||
private static final int POLYPHASE_SYNTHESIZER_TAPS_PER_CHANNEL = 9;
|
||||
@@ -141,7 +142,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
||||
* @param tunerChannel specifying center frequency and bandwidth.
|
||||
* @return source or null.
|
||||
*/
|
||||
public TunerChannelSource getChannel(TunerChannel tunerChannel)
|
||||
public TunerChannelSource getChannel(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
|
||||
{
|
||||
PolyphaseChannelSource channelSource = null;
|
||||
|
||||
@@ -155,10 +156,17 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
||||
{
|
||||
long centerFrequency = mChannelCalculator.getCenterFrequencyForIndexes(polyphaseIndexes);
|
||||
|
||||
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
|
||||
mChannelCalculator.getChannelSampleRate(), centerFrequency);
|
||||
try
|
||||
{
|
||||
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
|
||||
mChannelCalculator.getChannelSampleRate(), centerFrequency, channelSpecification);
|
||||
|
||||
mChannelSources.add(channelSource);
|
||||
mChannelSources.add(channelSource);
|
||||
}
|
||||
catch(FilterDesignException fde)
|
||||
{
|
||||
mLog.debug("Couldn't design final output low pass filter for polyphase channel source");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(IllegalArgumentException iae)
|
||||
|
||||
@@ -16,22 +16,35 @@
|
||||
package io.github.dsheirer.dsp.filter.channelizer;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.channelizer.output.IPolyphaseChannelOutputProcessor;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
|
||||
import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter2;
|
||||
import io.github.dsheirer.dsp.filter.fir.remez.RemezFIRFilterDesigner;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PolyphaseChannelSource extends TunerChannelSource
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelSource.class);
|
||||
|
||||
private ReusableComplexBufferAssembler mReusableComplexBufferAssembler;
|
||||
private IPolyphaseChannelOutputProcessor mPolyphaseChannelOutputProcessor;
|
||||
private IPolyphaseChannelOutputProcessor mReplacementPolyphaseChannelOutputProcessor;
|
||||
private long mReplacementFrequency;
|
||||
private ComplexFIRFilter2 mLowPassFilter;
|
||||
private static Map<Integer,float[]> sLowPassFilters = new HashMap();
|
||||
|
||||
private double mChannelSampleRate;
|
||||
private long mIndexCenterFrequency;
|
||||
private long mChannelFrequencyCorrection;
|
||||
@@ -46,15 +59,22 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
* @param producerSourceEventListener to receive source event requests (e.g. start/stop sample stream)
|
||||
* @param channelSampleRate for the downstream sample output
|
||||
* @param centerFrequency of the incoming polyphase channel(s)
|
||||
* @throws FilterDesignException if a channel low pass filter can't be designed to the channel specification
|
||||
*/
|
||||
public PolyphaseChannelSource(TunerChannel tunerChannel, IPolyphaseChannelOutputProcessor outputProcessor,
|
||||
Listener<SourceEvent> producerSourceEventListener, double channelSampleRate,
|
||||
long centerFrequency)
|
||||
long centerFrequency, ChannelSpecification channelSpecification)
|
||||
throws FilterDesignException
|
||||
{
|
||||
super(producerSourceEventListener, tunerChannel);
|
||||
mPolyphaseChannelOutputProcessor = outputProcessor;
|
||||
mChannelSampleRate = channelSampleRate;
|
||||
mReusableComplexBufferAssembler = new ReusableComplexBufferAssembler(2500, mChannelSampleRate);
|
||||
|
||||
float[] filterCoefficients = getLowPassFilter(channelSampleRate, channelSpecification.getPassFrequency(),
|
||||
channelSpecification.getStopFrequency());
|
||||
mLowPassFilter = new ComplexFIRFilter2(filterCoefficients, 1.0f);
|
||||
|
||||
setFrequency(centerFrequency);
|
||||
}
|
||||
|
||||
@@ -93,14 +113,33 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
*/
|
||||
public void setPolyphaseChannelOutputProcessor(IPolyphaseChannelOutputProcessor outputProcessor, long frequency)
|
||||
{
|
||||
//Lock on the channel output processor to block the channel results processor thread from servicing the
|
||||
//channel output processor's buffer while we change out the processors.
|
||||
synchronized(mPolyphaseChannelOutputProcessor)
|
||||
//If this is the first time, simply assign the output processor
|
||||
if(mPolyphaseChannelOutputProcessor == null)
|
||||
{
|
||||
mPolyphaseChannelOutputProcessor = outputProcessor;
|
||||
}
|
||||
//Otherwise, we have to swap out the processor on the sample processing thread
|
||||
else
|
||||
{
|
||||
mReplacementPolyphaseChannelOutputProcessor = outputProcessor;
|
||||
mReplacementFrequency = frequency;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the output processor to use the new output processor provided by the external
|
||||
* polyphase channel manager. This method should only be executed on the sample processing
|
||||
* thread, within the processChannelResults() method.
|
||||
*/
|
||||
private void swapOutputProcessor()
|
||||
{
|
||||
if(mReplacementPolyphaseChannelOutputProcessor != null)
|
||||
{
|
||||
IPolyphaseChannelOutputProcessor existingProcessor = mPolyphaseChannelOutputProcessor;
|
||||
|
||||
//Swap out the processor so that incoming samples can accumulate in the new channel output processor
|
||||
mPolyphaseChannelOutputProcessor = outputProcessor;
|
||||
mPolyphaseChannelOutputProcessor = mReplacementPolyphaseChannelOutputProcessor;
|
||||
mReplacementPolyphaseChannelOutputProcessor = null;
|
||||
|
||||
//Remove the buffer overflow listener and clear any previous buffer overflow state
|
||||
existingProcessor.setSourceOverflowListener(null);
|
||||
@@ -109,18 +148,9 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
//Register to receive buffer overflow notifications so we can push them up through the source chain
|
||||
mPolyphaseChannelOutputProcessor.setSourceOverflowListener(this);
|
||||
|
||||
//Fully process the residual channel results buffer of the previous channel output processor
|
||||
if(existingProcessor != null)
|
||||
{
|
||||
existingProcessor.processChannelResults(mReusableComplexBufferAssembler);
|
||||
}
|
||||
|
||||
//Finally, setup the frequency offset for the output processor and reset the frequency correction value
|
||||
//to allow consumers to adjust and calculate a new frequency correction value, if needed.
|
||||
mIndexCenterFrequency = frequency;
|
||||
mChannelFrequencyCorrection = 0;
|
||||
//Finally, setup the frequency offset for the output processor.
|
||||
mIndexCenterFrequency = mReplacementFrequency;
|
||||
mPolyphaseChannelOutputProcessor.setFrequencyOffset(getFrequencyOffset());
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mChannelFrequencyCorrection));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,12 +163,13 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
*/
|
||||
public void receiveChannelResults(ReusableChannelResultsBuffer channelResultsBuffer)
|
||||
{
|
||||
mReusableComplexBufferAssembler.updateTimestamp(channelResultsBuffer.getTimestamp());
|
||||
|
||||
if(mPolyphaseChannelOutputProcessor != null)
|
||||
if(mReplacementPolyphaseChannelOutputProcessor != null)
|
||||
{
|
||||
mPolyphaseChannelOutputProcessor.receiveChannelResults(channelResultsBuffer);
|
||||
swapOutputProcessor();
|
||||
}
|
||||
|
||||
mReusableComplexBufferAssembler.updateTimestamp(channelResultsBuffer.getTimestamp());
|
||||
mPolyphaseChannelOutputProcessor.receiveChannelResults(channelResultsBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +204,6 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
if(mPolyphaseChannelOutputProcessor != null)
|
||||
{
|
||||
mPolyphaseChannelOutputProcessor.dispose();
|
||||
mPolyphaseChannelOutputProcessor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,11 +243,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
@Override
|
||||
protected void processSamples()
|
||||
{
|
||||
//Lock on the output processor so that it can't be changed in the middle of processing
|
||||
synchronized(mPolyphaseChannelOutputProcessor)
|
||||
{
|
||||
mPolyphaseChannelOutputProcessor.processChannelResults(mReusableComplexBufferAssembler);
|
||||
}
|
||||
mPolyphaseChannelOutputProcessor.processChannelResults(mReusableComplexBufferAssembler);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,10 +262,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
*/
|
||||
private void updateFrequencyOffset()
|
||||
{
|
||||
synchronized(mPolyphaseChannelOutputProcessor)
|
||||
{
|
||||
mPolyphaseChannelOutputProcessor.setFrequencyOffset(getFrequencyOffset());
|
||||
}
|
||||
mPolyphaseChannelOutputProcessor.setFrequencyOffset(getFrequencyOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -248,4 +271,42 @@ public class PolyphaseChannelSource extends TunerChannelSource
|
||||
return "POLYPHASE [" + mPolyphaseChannelOutputProcessor.getInputChannelCount() + "] " +
|
||||
getTunerChannel().getFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a low-pass filter to use as the final cleanup filter for the decimated output stream
|
||||
*
|
||||
* @param sampleRate for the final output channel rate
|
||||
* @param passFrequency for half of the desired channel rate
|
||||
* @param stopFrequency for the attenuated band
|
||||
* @return a newly designed filter or a previously designed (cached) filter
|
||||
* @throws FilterDesignException
|
||||
*/
|
||||
private float[] getLowPassFilter(double sampleRate, double passFrequency, double stopFrequency) throws FilterDesignException
|
||||
{
|
||||
//Use existing filter if we've already designed one
|
||||
if(sLowPassFilters.containsKey((int)sampleRate))
|
||||
{
|
||||
return sLowPassFilters.get((int)sampleRate);
|
||||
}
|
||||
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(sampleRate)
|
||||
.gridDensity(16)
|
||||
.passBandCutoff(passFrequency)
|
||||
.passBandAmplitude(1.0)
|
||||
.passBandRipple(0.01)
|
||||
.stopBandStart(stopFrequency)
|
||||
.stopBandAmplitude(0.0)
|
||||
.stopBandRipple(0.01)
|
||||
.build();
|
||||
|
||||
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
|
||||
|
||||
//This will throw an exception if the filter cannot be designed
|
||||
float[] taps = designer.getImpulseResponse();
|
||||
|
||||
sLowPassFilters.put((int)sampleRate, taps);
|
||||
|
||||
return taps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,29 +16,18 @@
|
||||
package io.github.dsheirer.dsp.filter.channelizer.output;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.channelizer.TwoChannelSynthesizerM2;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
|
||||
import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter2;
|
||||
import io.github.dsheirer.dsp.filter.fir.remez.RemezFIRFilterDesigner;
|
||||
import io.github.dsheirer.dsp.mixer.FS4DownConverter;
|
||||
import io.github.dsheirer.sample.buffer.ReusableChannelResultsBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TwoChannelOutputProcessor extends ChannelOutputProcessor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TwoChannelOutputProcessor.class);
|
||||
|
||||
private static Map<Integer,float[]> sLowPassFilterKernelMap = new HashMap<>();
|
||||
// private final static Logger mLog = LoggerFactory.getLogger(TwoChannelOutputProcessor.class);
|
||||
private TwoChannelSynthesizerM2 mSynthesizer;
|
||||
private FS4DownConverter mFS4DownConverter = new FS4DownConverter();
|
||||
private ComplexFIRFilter2 mLowPassFilter;
|
||||
|
||||
private int mChannelOffset1;
|
||||
private int mChannelOffset2;
|
||||
@@ -58,28 +47,11 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
|
||||
super(2, sampleRate, gain);
|
||||
setPolyphaseChannelIndices(channelIndexes);
|
||||
setSynthesisFilter(filter);
|
||||
|
||||
float[] lowPassFilter = sLowPassFilterKernelMap.get((int)sampleRate);
|
||||
|
||||
if(lowPassFilter == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
lowPassFilter = getLowPassFilter(sampleRate);
|
||||
sLowPassFilterKernelMap.put((int)sampleRate, lowPassFilter);
|
||||
}
|
||||
catch(FilterDesignException fde)
|
||||
{
|
||||
mLog.error("Couldn't design a low-pass filter for 2-channel synthesizer", fde);
|
||||
throw new IllegalStateException("Cannot design low-pass filter for 2 channel synthesizer", fde);
|
||||
}
|
||||
}
|
||||
|
||||
mLowPassFilter = new ComplexFIRFilter2(lowPassFilter, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frequency offset to apply to the incoming samples to mix the desired signal to baseband.
|
||||
*
|
||||
* @param frequencyOffset in hertz
|
||||
*/
|
||||
@Override
|
||||
@@ -126,7 +98,7 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
|
||||
public void process(List<ReusableChannelResultsBuffer> channelResultsBuffers,
|
||||
ReusableComplexBufferAssembler reusableComplexBufferAssembler)
|
||||
{
|
||||
for(ReusableChannelResultsBuffer buffer: channelResultsBuffers)
|
||||
for(ReusableChannelResultsBuffer buffer : channelResultsBuffers)
|
||||
{
|
||||
ReusableComplexBuffer channel1 = buffer.getChannel(mChannelOffset1);
|
||||
ReusableComplexBuffer channel2 = buffer.getChannel(mChannelOffset2);
|
||||
@@ -140,48 +112,11 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
|
||||
//Apply offset and frequency correction to center the signal of interest within the synthesized channel
|
||||
getFrequencyCorrectionMixer().mixComplex(synthesized.getSamples());
|
||||
|
||||
ReusableComplexBuffer lowPassFiltered = mLowPassFilter.filter(synthesized);
|
||||
synthesized.applyGain(getGain());
|
||||
|
||||
lowPassFiltered.applyGain(getGain());
|
||||
|
||||
reusableComplexBufferAssembler.receive(lowPassFiltered);
|
||||
reusableComplexBufferAssembler.receive(synthesized);
|
||||
|
||||
buffer.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a low-pass filter kernel for the specified sample rate.
|
||||
* @param sampleRate for the channel
|
||||
* @return filter
|
||||
* @throws FilterDesignException if the filter cannot be designed
|
||||
*/
|
||||
private static float[] getLowPassFilter(double sampleRate) throws FilterDesignException
|
||||
{
|
||||
double cutoff = sampleRate / 4.0;
|
||||
int passBandCutoff = (int)(cutoff * 0.92);
|
||||
int stopBandStart = (int)(cutoff * 1.08);
|
||||
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(sampleRate)
|
||||
.gridDensity(16)
|
||||
.oddLength(true)
|
||||
.passBandCutoff((int)passBandCutoff)
|
||||
.passBandAmplitude(1.0)
|
||||
.passBandRipple(0.01)
|
||||
.stopBandStart((int)stopBandStart)
|
||||
.stopBandAmplitude(0.0)
|
||||
.stopBandRipple(0.005) //Approximately 94 dB attenuation
|
||||
.build();
|
||||
|
||||
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
|
||||
|
||||
if(designer.isValid())
|
||||
{
|
||||
return designer.getImpulseResponse();
|
||||
}
|
||||
|
||||
throw new FilterDesignException("Couldn't design low-pass filter for sample rate: " + sampleRate +
|
||||
" Pass End:" + passBandCutoff + " Stop Begin:" + stopBandStart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ public enum PLLGain
|
||||
//NOTE: static gain level of 200 produced the best results for releases prior to 0.3.4b2
|
||||
|
||||
LEVEL_1(150.0, 0, 1),
|
||||
LEVEL_2(175.0, 2, 4),
|
||||
LEVEL_3(200.0, 5, 6),
|
||||
LEVEL_2(170.0, 2, 4),
|
||||
LEVEL_3(190.0, 5, 6),
|
||||
LEVEL_4(200.0, 7, 8),
|
||||
LEVEL_5(200.0, 9, 10);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||
@@ -376,10 +377,11 @@ public class ChannelizerViewer2 extends JFrame
|
||||
mComplexDecibelConverter.addListener(mSpectrumPanel);
|
||||
|
||||
TunerChannel tunerChannel = new TunerChannel(frequency, bandwidth);
|
||||
mSource = mTestTuner.getChannelSourceManager().getSource(tunerChannel, null);
|
||||
mSource = mTestTuner.getChannelSourceManager().getSource(tunerChannel, new ChannelSpecification(50000, 12500, 6000, 7000));
|
||||
|
||||
if(mSource != null)
|
||||
{
|
||||
mLog.debug("Channel: " + mSource.getTunerChannel() + " Rate:" + mSource.getSampleRate());
|
||||
mSource.setListener(new Listener<ReusableComplexBuffer>()
|
||||
{
|
||||
@Override
|
||||
|
||||
@@ -113,7 +113,6 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration
|
||||
@Override
|
||||
public ChannelSpecification getChannelSpecification()
|
||||
{
|
||||
return new ChannelSpecification(50000.0,
|
||||
12500, 6000.0, 7000.0);
|
||||
return new ChannelSpecification(50000.0, 12500, 5750.0, 6500.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.manager.ChannelSourceManager;
|
||||
import io.github.dsheirer.source.tuner.manager.HeterodyneChannelSourceManager;
|
||||
import io.github.dsheirer.source.tuner.manager.PolyphaseChannelSourceManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -51,8 +51,8 @@ public abstract class Tuner implements ISourceEventProcessor
|
||||
//Register to receive frequency and sample rate change notifications
|
||||
mTunerController.addListener(this::process);
|
||||
|
||||
// mChannelSourceManager = new PolyphaseChannelSourceManager(mTunerController);
|
||||
mChannelSourceManager = new HeterodyneChannelSourceManager(mTunerController);
|
||||
mChannelSourceManager = new PolyphaseChannelSourceManager(mTunerController);
|
||||
// mChannelSourceManager = new HeterodyneChannelSourceManager(mTunerController);
|
||||
|
||||
//Register to receive channel count change notifications
|
||||
mChannelSourceManager.addSourceEventListener(this::process);
|
||||
|
||||
@@ -18,7 +18,7 @@ package io.github.dsheirer.source.tuner.channel;
|
||||
import io.github.dsheirer.dsp.filter.cic.ComplexPrimeCICDecimate;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
import io.github.dsheirer.dsp.mixer.IOscillator;
|
||||
import io.github.dsheirer.dsp.mixer.Oscillator;
|
||||
import io.github.dsheirer.dsp.mixer.LowPhaseNoiseOscillator;
|
||||
import io.github.dsheirer.sample.IOverflowListener;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue;
|
||||
@@ -81,7 +81,7 @@ public class CICTunerChannelSource extends TunerChannelSource implements Listene
|
||||
mTunerFrequency = tunerChannel.getFrequency();
|
||||
long frequencyOffset = mTunerFrequency - getTunerChannel().getFrequency();
|
||||
|
||||
mFrequencyCorrectionMixer = new Oscillator(frequencyOffset, sampleRate);
|
||||
mFrequencyCorrectionMixer = new LowPhaseNoiseOscillator(frequencyOffset, sampleRate);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -294,6 +294,10 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
{
|
||||
mLog.error("Error while sending heartbeat", t);
|
||||
}
|
||||
}
|
||||
|
||||
if(!mStopped)
|
||||
{
|
||||
try
|
||||
{
|
||||
processSamples();
|
||||
|
||||
@@ -393,11 +393,6 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
|
||||
@Override
|
||||
public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
|
||||
{
|
||||
if(channelSpecification != null)
|
||||
{
|
||||
throw new IllegalArgumentException("Update polyphase source manager to support channel specifications");
|
||||
}
|
||||
|
||||
if(isTunable(tunerChannel))
|
||||
{
|
||||
//Get a new set of currently tuned channels
|
||||
@@ -422,7 +417,7 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
|
||||
}
|
||||
|
||||
//If we're successful to here, allocate the channel
|
||||
return mPolyphaseChannelManager.getChannel(tunerChannel);
|
||||
return mPolyphaseChannelManager.getChannel(tunerChannel, channelSpecification);
|
||||
}
|
||||
catch(SourceException se)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ public class TestTunerController extends TunerController
|
||||
|
||||
public static final long MINIMUM_FREQUENCY = 1l;
|
||||
public static final long MAXIMUM_FREQUENCY = 1000000000l;
|
||||
public static final int SAMPLE_RATE = 50000;
|
||||
public static final int SAMPLE_RATE = 10000000;
|
||||
public static final int DC_NOISE_BANDWIDTH = 0;
|
||||
public static final double USABLE_BANDWIDTH_PERCENTAGE = 1.00;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user