mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 09:37:36 -05:00
Tuner Channel - uses new CIC prime decimation filter for decimating channel to 48k sample rate.
This commit is contained in:
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user