mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 09:07:27 -05:00
Tuner Channel - uses new CIC prime decimation filter for decimating channel to 48k sample rate.
This commit is contained in:
@@ -114,16 +114,12 @@ public class P25Decoder extends Decoder
|
||||
FrameSync.P25_PHASE1.getSync(), 64, false, mAliasList );
|
||||
mNormalFramer.setListener( mMessageProcessor );
|
||||
|
||||
// mInvertedFramer = new P25MessageFramer(
|
||||
// FrameSync.P25_PHASE1_INVERTED.getSync(), 64, true, mAliasList );
|
||||
// mInvertedFramer.setListener( mMessageProcessor );
|
||||
|
||||
/* Setup demodulation chains based on sample type (real or complex) and
|
||||
* modulation (C4FM or CQPSK) */
|
||||
if( mSourceSampleType == SampleType.COMPLEX )
|
||||
{
|
||||
mBasebandFilter = new ComplexFIRFilter( FilterFactory.getLowPass(
|
||||
48000, 6500, 7500, 48, WindowType.HANNING, true ), 4.0 );
|
||||
48000, 7000, 7500, 60, WindowType.HAMMING, true ), 1.0 );
|
||||
|
||||
if( modulation == Modulation.CQPSK )
|
||||
{
|
||||
@@ -139,7 +135,6 @@ public class P25Decoder extends Decoder
|
||||
mCQPSKDemodulator.setListener( mCQPSKSlicer );
|
||||
|
||||
mCQPSKSlicer.addListener( mNormalFramer );
|
||||
// mCQPSKSlicer.addListener( mInvertedFramer );
|
||||
}
|
||||
else /* C4FM */
|
||||
{
|
||||
@@ -172,7 +167,6 @@ public class P25Decoder extends Decoder
|
||||
mSymbolFilter.setListener( mC4FMSlicer );
|
||||
|
||||
mC4FMSlicer.addListener( mNormalFramer );
|
||||
// mC4FMSlicer.addListener( mInvertedFramer );
|
||||
}
|
||||
|
||||
mAudioOutput = new P25AudioOutput( resourceManager );
|
||||
|
||||
@@ -262,12 +262,14 @@ public class ComplexCICDecimate extends ComplexFilter
|
||||
mDecimation = decimation;
|
||||
mCleanupFilter = new ComplexFIRFilter( FilterFactory
|
||||
.getCICCleanupFilter( outputSampleRate,
|
||||
stageCount,
|
||||
1,
|
||||
12000,
|
||||
60,
|
||||
WindowType.BLACKMAN ), 1.0d );
|
||||
|
||||
setGain();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Receiver method for the output adapter to receive a filtered,
|
||||
* decimated sample, apply gain correction, apply cleanup filtering
|
||||
|
||||
@@ -3,7 +3,9 @@ package dsp.filter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import sample.Broadcaster;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexBuffer;
|
||||
import sample.complex.ComplexSample;
|
||||
@@ -11,8 +13,11 @@ import sample.complex.ComplexSampleListener;
|
||||
import sample.decimator.ComplexDecimator;
|
||||
import dsp.filter.Window.WindowType;
|
||||
|
||||
public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
public class ComplexPrimeCICDecimate
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( ComplexPrimeCICDecimate.class );
|
||||
|
||||
public static int[] PRIMES = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
|
||||
59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,
|
||||
157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,
|
||||
@@ -25,11 +30,11 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
new ArrayList<DecimatingStage>();
|
||||
|
||||
private DecimatingStage mFirstDecimatingStage;
|
||||
|
||||
public Broadcaster<ComplexSample> mBroadcaster =
|
||||
new Broadcaster<ComplexSample>();
|
||||
|
||||
public Output mOutput;
|
||||
private Output mOutput;
|
||||
|
||||
private Listener<ComplexSample> mListener;
|
||||
|
||||
/**
|
||||
* Non-Recursive Prime-Factor CIC Filter with float sample array inputs and
|
||||
* decimated, single paired i/q float sample output.
|
||||
@@ -46,7 +51,8 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
* @param decimation - overall decimation rate
|
||||
* @param order - filter order
|
||||
*/
|
||||
public ComplexPrimeCICDecimate( int decimation, int order )
|
||||
public ComplexPrimeCICDecimate( int decimation, int order,
|
||||
int passFrequency, int attenuation, WindowType windowType )
|
||||
{
|
||||
assert( decimation <= 700 );
|
||||
|
||||
@@ -69,13 +75,12 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
mDecimatingStages.get( x - 1 ).addListener( stage );
|
||||
}
|
||||
}
|
||||
|
||||
mOutput = new Output( 48000, stageSizes.size(), decimation );
|
||||
|
||||
mOutput = new Output( 48000, order, decimation, passFrequency,
|
||||
attenuation, windowType );
|
||||
|
||||
mDecimatingStages.get( mDecimatingStages.size() - 1 )
|
||||
.addListener( mOutput );
|
||||
|
||||
mOutput.setListener( mBroadcaster );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
@@ -86,26 +91,22 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
}
|
||||
|
||||
mDecimatingStages.clear();
|
||||
|
||||
mBroadcaster.dispose();
|
||||
|
||||
mBroadcaster = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to receive the output of this CIC decimation filter
|
||||
*/
|
||||
public void addListener( Listener<ComplexSample> listener )
|
||||
public void setListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
mBroadcaster.addListener( listener );
|
||||
mOutput.setListener( listener );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes listener from output of this CIC decimation filter
|
||||
*/
|
||||
public void removeListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
mBroadcaster.removeListener( listener );
|
||||
mOutput.removeListener( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,11 +145,8 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
/**
|
||||
* Primary input method for receiving sample arrays composed as I,Q,I,Q, etc.
|
||||
*/
|
||||
@Override
|
||||
public void receive( ComplexBuffer sampleArray )
|
||||
public void receive( float[] samples )
|
||||
{
|
||||
float[] samples = sampleArray.getSamples();
|
||||
|
||||
for( int x = 0; x < samples.length; x += 2 )
|
||||
{
|
||||
mFirstDecimatingStage.receive( samples[ x ], samples[ x + 1 ] );
|
||||
@@ -232,28 +230,27 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
private float mISum;
|
||||
private float mQSum;
|
||||
|
||||
private int mSamplePointer;
|
||||
private int mSamplePointer = 0;
|
||||
private int mSize;
|
||||
|
||||
public Stage( int size )
|
||||
{
|
||||
mSize = size;
|
||||
mISamples = new float[ size ];
|
||||
mQSamples = new float[ size ];
|
||||
mSize = size - 1;
|
||||
|
||||
mISamples = new float[ mSize ];
|
||||
mQSamples = new float[ mSize ];
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mListener = null;
|
||||
mISamples = null;
|
||||
mQSamples = null;
|
||||
}
|
||||
|
||||
public void receive( float i, float q )
|
||||
{
|
||||
/* Subtract the oldest sample and add back in the newest */
|
||||
mISum = mISum - mISamples[ mSamplePointer ] + i;
|
||||
mQSum = mQSum - mISamples[ mSamplePointer ] + q;
|
||||
mQSum = mQSum - mQSamples[ mSamplePointer ] + q;
|
||||
|
||||
/* Overwrite the oldest sample with the newest */
|
||||
mISamples[ mSamplePointer ] = i;
|
||||
@@ -285,19 +282,22 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
*/
|
||||
public class Output implements ComplexSampleListener
|
||||
{
|
||||
private int mStageCount;
|
||||
private int mDecimation;
|
||||
private int mOrder;
|
||||
private double mGain = 1.0d;
|
||||
private ComplexFilter mCleanupFilter;
|
||||
|
||||
public Output( int outputSampleRate, int stageCount, int decimation )
|
||||
public Output( int outputSampleRate, int order, int decimation,
|
||||
int passFrequency, int attenuation, WindowType windowType )
|
||||
{
|
||||
mStageCount = stageCount;
|
||||
mOrder = order;
|
||||
mDecimation = decimation;
|
||||
mCleanupFilter = new ComplexFIRFilter( FilterFactory
|
||||
.getCICCleanupFilter( outputSampleRate,
|
||||
stageCount,
|
||||
WindowType.BLACKMAN ), 1.0d );
|
||||
mOrder,
|
||||
passFrequency,
|
||||
attenuation,
|
||||
windowType ), 1.0d );
|
||||
|
||||
setGain();
|
||||
}
|
||||
@@ -359,10 +359,9 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
|
||||
private void setGain()
|
||||
{
|
||||
/* decimation is NOT multiplied by delay since delay is 1 */
|
||||
double gain = Math.pow( (double)mDecimation, (double)mStageCount );
|
||||
double gain = Math.pow( (double)mDecimation, (double)mOrder );
|
||||
|
||||
mGain = 10.0d / gain;
|
||||
mGain = 1.0d / gain;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ import dsp.filter.Window.WindowType;
|
||||
|
||||
public class FilterFactory
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( FilterFactory.class );
|
||||
// private final static Logger mLog =
|
||||
// LoggerFactory.getLogger( FilterFactory.class );
|
||||
|
||||
/**
|
||||
* Generates coefficients for a unity-gain, windowed low-pass filter
|
||||
@@ -381,99 +381,14 @@ public class FilterFactory
|
||||
return (int)( Math.round( (double)attenuation / ( 22.0d * frequency ) ) );
|
||||
}
|
||||
|
||||
public static ComplexFilter[] getDecimationFilters( int sampleRate,
|
||||
int decimatedRate,
|
||||
long passFrequency,
|
||||
int attenuation,
|
||||
WindowType windowType )
|
||||
public static ComplexPrimeCICDecimate getDecimationFilter( int sampleRate,
|
||||
int decimatedRate, int order, int passFrequency, int attenuation,
|
||||
WindowType windowType )
|
||||
{
|
||||
ComplexFilter[] filters;
|
||||
|
||||
if( sampleRate == 96000 && decimatedRate == 48000 )
|
||||
{
|
||||
filters = new ComplexFilter[ 1 ];
|
||||
filters[ 0 ] = new ComplexHalfBandFilter(
|
||||
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO, 1.0002 );
|
||||
}
|
||||
else if( sampleRate == 192000 && decimatedRate == 48000 )
|
||||
{
|
||||
filters = new ComplexFilter[ 2 ];
|
||||
filters[ 0 ] = new ComplexHalfBandFilter(
|
||||
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO, 1.0002 );
|
||||
filters[ 1 ] = new ComplexHalfBandFilter(
|
||||
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO, 1.0002 );
|
||||
}
|
||||
else
|
||||
{
|
||||
filters = new ComplexFilter[ 1 ];
|
||||
int decimationRate = (int)( sampleRate / decimatedRate );
|
||||
|
||||
int decimate = (int)( sampleRate / decimatedRate );
|
||||
|
||||
// if( decimate < 25 )
|
||||
// {
|
||||
filters[ 0 ] = new ComplexCICDecimate( decimate, 1, decimatedRate );
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// filters[ 0 ] = new ComplexCICDecimate( decimate, 3, decimatedRate );
|
||||
// }
|
||||
|
||||
|
||||
// int finalStopFrequency = decimatedRate - passFrequency;
|
||||
//
|
||||
// int[] rates = getPolyphaseDecimationRates( sampleRate,
|
||||
// decimatedRate,
|
||||
// passFrequency,
|
||||
// finalStopFrequency );
|
||||
//
|
||||
// filters = new ComplexFilter[ rates.length ];
|
||||
//
|
||||
// int counter = 0;
|
||||
// int currentSampleRate = sampleRate;
|
||||
// int currentDecimatedRate = sampleRate;
|
||||
//
|
||||
// while( counter < rates.length )
|
||||
// {
|
||||
// currentDecimatedRate /= rates[ counter ];
|
||||
//
|
||||
// int stopFrequency = currentDecimatedRate- passFrequency;
|
||||
//
|
||||
// int proposedFilterLength = getTapCount( currentSampleRate,
|
||||
// passFrequency,
|
||||
// stopFrequency,
|
||||
// attenuation );
|
||||
//
|
||||
// /* check filter length is multiple of decimation rate */
|
||||
// int multiplier = (int)( proposedFilterLength / rates[ counter ] );
|
||||
//
|
||||
// /* increase filter length to the next multiple, if needed */
|
||||
// if( multiplier * rates[ counter ] < proposedFilterLength )
|
||||
// {
|
||||
// multiplier++;
|
||||
// }
|
||||
//
|
||||
// double[] filter = getLowPass( currentSampleRate,
|
||||
// passFrequency,
|
||||
// rates[counter] * multiplier,
|
||||
// windowType );
|
||||
//
|
||||
// filters[ counter ] =
|
||||
// new ComplexPolyphaseDecimationFilter( filter, rates[ counter ] );
|
||||
//
|
||||
// Log.info( "FilterFactory - PFD filter [" + ( counter + 1 ) + "/" + rates.length +
|
||||
// "] overall rate [" + sampleRate +
|
||||
// "] decimate [" + rates[ counter ] +
|
||||
// "] filter taps [" + filter.length +
|
||||
// "] rate [" + currentSampleRate +
|
||||
// "] pass [" + passFrequency +
|
||||
// "]" );
|
||||
//
|
||||
// currentSampleRate /= rates[ counter ];
|
||||
// counter++;
|
||||
// }
|
||||
}
|
||||
|
||||
return filters;
|
||||
return new ComplexPrimeCICDecimate( decimationRate, order,
|
||||
passFrequency, attenuation, windowType );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -516,10 +431,10 @@ public class FilterFactory
|
||||
|
||||
int stage1 = findClosest( optimalStage1, factors );
|
||||
|
||||
mLog.info( "Decimation rate [" + decimation +
|
||||
"] stage1 optimal [" + optimalStage1 +
|
||||
"] stage1 actual [" + stage1 +
|
||||
"]");
|
||||
// mLog.info( "Decimation rate [" + decimation +
|
||||
// "] stage1 optimal [" + optimalStage1 +
|
||||
// "] stage1 actual [" + stage1 +
|
||||
// "]");
|
||||
|
||||
if( stage1 == decimation || stage1 == 1 )
|
||||
{
|
||||
@@ -627,11 +542,11 @@ public class FilterFactory
|
||||
|
||||
int retVal = (int)( 2.0d * decimation * ( numerator / denominator ) );
|
||||
|
||||
mLog.info( "Optimal Stage 1 Decimation - rate [" + sampleRate +
|
||||
"] pass [" + passFrequency +
|
||||
"] bw ratio [" + ratio +
|
||||
"] optimal [" + retVal +
|
||||
"]" );
|
||||
// mLog.info( "Optimal Stage 1 Decimation - rate [" + sampleRate +
|
||||
// "] pass [" + passFrequency +
|
||||
// "] bw ratio [" + ratio +
|
||||
// "] optimal [" + retVal +
|
||||
// "]" );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
@@ -660,15 +575,14 @@ public class FilterFactory
|
||||
* @return
|
||||
*/
|
||||
public static double[] getCICCleanupFilter( int outputSampleRate,
|
||||
int stageCount,
|
||||
int order,
|
||||
int passFrequency,
|
||||
int attenuation,
|
||||
WindowType window )
|
||||
{
|
||||
int pass = (int)( outputSampleRate / 4 );
|
||||
int stop = pass + (int)( (double)pass * 0.25d );
|
||||
int attenuation = 60; //db
|
||||
int taps = getTapCount( outputSampleRate, passFrequency, passFrequency + 1500,
|
||||
attenuation );
|
||||
|
||||
int taps = getTapCount( outputSampleRate, pass, stop, attenuation );
|
||||
|
||||
/* Make tap count odd */
|
||||
if( taps% 2 == 0 )
|
||||
{
|
||||
@@ -676,7 +590,7 @@ public class FilterFactory
|
||||
}
|
||||
|
||||
double[] frequencyResponse =
|
||||
getCICResponseArray( outputSampleRate, pass, taps, stageCount );
|
||||
getCICResponseArray( outputSampleRate, passFrequency, taps, order );
|
||||
|
||||
//Apply Inverse DFT against frequency response unity values, leaving the
|
||||
//IDFT bin results in the frequency response array
|
||||
@@ -707,7 +621,7 @@ public class FilterFactory
|
||||
public static double[] getCICResponseArray( int sampleRate,
|
||||
int frequency,
|
||||
int length,
|
||||
int stageCount )
|
||||
int order )
|
||||
{
|
||||
double[] cicArray = new double[ length * 2 ];
|
||||
|
||||
@@ -717,14 +631,14 @@ public class FilterFactory
|
||||
cicArray[ 0 ] = 1.0d;
|
||||
|
||||
double unityResponse = Math.pow( Math.sin( 1.0d / (double)length ) /
|
||||
( 1.0d / (double)length ), stageCount );
|
||||
( 1.0d / (double)length ), order );
|
||||
|
||||
for( int x = 1; x <= binCount; x++ )
|
||||
{
|
||||
/* Calculate unity response plus amplification for droop */
|
||||
double compensated = 1.0d + ( unityResponse -
|
||||
Math.pow( ( Math.sin( (double)x / (double)length ) /
|
||||
( (double)x / (double)length ) ), stageCount ) );
|
||||
( (double)x / (double)length ) ), order ) );
|
||||
|
||||
cicArray[ x ] = compensated;
|
||||
cicArray[ length - x ] = compensated;
|
||||
@@ -821,4 +735,11 @@ public class FilterFactory
|
||||
|
||||
return coefficients;
|
||||
}
|
||||
|
||||
public static void main( String[] args )
|
||||
{
|
||||
double[] coefficients = getCICCleanupFilter( 48000, 2, 60, 24000, WindowType.BLACKMAN );
|
||||
|
||||
System.out.println( Arrays.toString( coefficients ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
******************************************************************************/
|
||||
package dsp.nbfm;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sample.Listener;
|
||||
import sample.complex.ComplexSample;
|
||||
import sample.real.RealSampleBroadcaster;
|
||||
@@ -28,6 +31,9 @@ import dsp.filter.Window.WindowType;
|
||||
|
||||
public class FilteringNBFMDemodulator implements Listener<ComplexSample>
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( FilteringNBFMDemodulator.class );
|
||||
|
||||
private RealSampleBroadcaster mBroadcaster = new RealSampleBroadcaster();
|
||||
private ComplexFIRFilter mIQFilter;
|
||||
private FloatFIRFilter mAudioFilter;
|
||||
|
||||
@@ -37,8 +37,7 @@ import source.tuner.FrequencyChangeEvent.Attribute;
|
||||
import util.Oscillator;
|
||||
import controller.ThreadPoolManager;
|
||||
import controller.ThreadPoolManager.ThreadType;
|
||||
import decode.p25.P25Decoder;
|
||||
import dsp.filter.ComplexFilter;
|
||||
import dsp.filter.ComplexPrimeCICDecimate;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
|
||||
@@ -49,15 +48,15 @@ public class TunerChannelSource extends ComplexSource
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( TunerChannelSource.class );
|
||||
|
||||
private static int sCHANNEL_RATE = 48000;
|
||||
private static int sCHANNEL_PASS_FREQUENCY = 12500;
|
||||
private static int CHANNEL_RATE = 48000;
|
||||
private static int CHANNEL_PASS_FREQUENCY = 12000;
|
||||
|
||||
private LinkedTransferQueue<ComplexBuffer> mBuffer =
|
||||
new LinkedTransferQueue<ComplexBuffer>();
|
||||
private Tuner mTuner;
|
||||
private TunerChannel mTunerChannel;
|
||||
private Oscillator mSineWaveGenerator;
|
||||
private ComplexFilter[] mDecimationFilters;
|
||||
private ComplexPrimeCICDecimate mDecimationFilter;
|
||||
|
||||
private ComplexSampleAssembler mBufferAssembler =
|
||||
new ComplexSampleAssembler( 3000 );
|
||||
@@ -71,7 +70,7 @@ public class TunerChannelSource extends ComplexSource
|
||||
public TunerChannelSource( ThreadPoolManager threadPoolManager,
|
||||
Tuner tuner,
|
||||
TunerChannel tunerChannel )
|
||||
throws RejectedExecutionException, SourceException
|
||||
throws RejectedExecutionException, SourceException
|
||||
{
|
||||
super( "Tuner Channel Source" );
|
||||
|
||||
@@ -118,11 +117,8 @@ public class TunerChannelSource extends ComplexSource
|
||||
|
||||
mBuffer.clear();
|
||||
mBuffer = null;
|
||||
|
||||
for( ComplexFilter filter: mDecimationFilters )
|
||||
{
|
||||
filter.dispose();
|
||||
}
|
||||
|
||||
mDecimationFilter.dispose();
|
||||
|
||||
mBufferAssembler.dispose();
|
||||
|
||||
@@ -160,8 +156,6 @@ public class TunerChannelSource extends ComplexSource
|
||||
public void removeListener( Listener<List<ComplexSample>> listener )
|
||||
{
|
||||
mBufferAssembler.removeListener( listener );
|
||||
mDecimationFilters[ mDecimationFilters.length - 1 ]
|
||||
.setListener( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,28 +178,18 @@ public class TunerChannelSource extends ComplexSource
|
||||
{
|
||||
/* Set the oscillator to the new frequency */
|
||||
mSineWaveGenerator.setSampleRate( sampleRate );
|
||||
|
||||
/* Get new decimation filters */
|
||||
mDecimationFilters = FilterFactory
|
||||
.getDecimationFilters( sampleRate,
|
||||
sCHANNEL_RATE,
|
||||
sCHANNEL_PASS_FREQUENCY,
|
||||
48, //dB attenuation
|
||||
WindowType.HAMMING );
|
||||
|
||||
/* wire the filters together */
|
||||
if( mDecimationFilters.length > 1 )
|
||||
{
|
||||
for( int x = 1; x < mDecimationFilters.length; x++ )
|
||||
{
|
||||
mDecimationFilters[ x - 1 ]
|
||||
.setListener( mDecimationFilters[ x ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Get new decimation filter */
|
||||
mDecimationFilter = FilterFactory
|
||||
.getDecimationFilter( sampleRate,
|
||||
CHANNEL_RATE,
|
||||
2, //Order
|
||||
CHANNEL_PASS_FREQUENCY,
|
||||
60, //dB attenuation
|
||||
WindowType.HAMMING );
|
||||
|
||||
/* re-add the original output listener */
|
||||
mDecimationFilters[ mDecimationFilters.length - 1 ]
|
||||
.setListener( mBufferAssembler );
|
||||
mDecimationFilter.setListener( mBufferAssembler );
|
||||
|
||||
mTunerSampleRate = sampleRate;
|
||||
}
|
||||
@@ -265,28 +249,25 @@ public class TunerChannelSource extends ComplexSource
|
||||
* and process them, causing delays and buffer refill */
|
||||
mBuffer.drainTo( sampleBuffers, 4 );
|
||||
|
||||
for( ComplexBuffer sampleArray: sampleBuffers )
|
||||
for( ComplexBuffer buffer: sampleBuffers )
|
||||
{
|
||||
float[] samples = sampleArray.getSamples();
|
||||
|
||||
float[] samples = buffer.getSamples();
|
||||
float[] translated = new float[ samples.length ];
|
||||
|
||||
/* Perform frequency translation */
|
||||
for( int x = 0; x < samples.length; x += 2 )
|
||||
{
|
||||
Float left = samples[ x ];
|
||||
Float right = samples[ x + 1 ];
|
||||
ComplexSample multiplier =
|
||||
mSineWaveGenerator.nextComplex();
|
||||
|
||||
if( left != null && right != null )
|
||||
{
|
||||
/* perform frequency translation */
|
||||
ComplexSample translated = ComplexSample.multiply(
|
||||
mSineWaveGenerator.nextComplex(), left, right );
|
||||
|
||||
/* decimate the sample rate */
|
||||
if( mDecimationFilters[ 0 ] != null )
|
||||
{
|
||||
mDecimationFilters[ 0 ].receive( translated );
|
||||
}
|
||||
}
|
||||
translated[ x ] = ( samples[ x ] * multiplier.inphase() ) -
|
||||
( samples[ x + 1 ] * multiplier.quadrature() );
|
||||
|
||||
translated[ x + 1 ] = ( samples[ x + 1 ] * multiplier.inphase() ) +
|
||||
( samples[ x ] * multiplier.quadrature() );
|
||||
}
|
||||
|
||||
mDecimationFilter.receive( translated );
|
||||
}
|
||||
|
||||
sampleBuffers.clear();
|
||||
|
||||
Reference in New Issue
Block a user