From ae8a44caed0de0de9a995714e30f678f3c3ca65b Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 11 Mar 2017 11:53:12 -0500 Subject: [PATCH] Removes cic cleanup filter from processing chain. --- .../filter/cic/ComplexPrimeCICDecimate.java | 754 +++++++++--------- 1 file changed, 379 insertions(+), 375 deletions(-) diff --git a/src/dsp/filter/cic/ComplexPrimeCICDecimate.java b/src/dsp/filter/cic/ComplexPrimeCICDecimate.java index 72a869d0..95bf15ce 100644 --- a/src/dsp/filter/cic/ComplexPrimeCICDecimate.java +++ b/src/dsp/filter/cic/ComplexPrimeCICDecimate.java @@ -1,408 +1,412 @@ /******************************************************************************* - * SDR Trunk - * Copyright (C) 2015 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see + * sdrtrunk + * Copyright (C) 2014-2017 Dennis Sheirer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ******************************************************************************/ package dsp.filter.cic; -import java.util.ArrayList; -import java.util.List; - +import dsp.filter.FilterFactory; +import dsp.filter.Filters; +import dsp.filter.Window.WindowType; +import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB; +import dsp.filter.halfband.complex.HalfBandFilter_CB_CB; import org.apache.commons.lang3.Validate; import sample.Listener; import sample.complex.ComplexBuffer; import sample.complex.ComplexSampleListener; import sample.complex.ComplexToComplexBufferAssembler; import sample.decimator.ComplexDecimator; -import dsp.filter.FilterFactory; -import dsp.filter.Filters; -import dsp.filter.Window.WindowType; -import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB; -import dsp.filter.halfband.complex.HalfBandFilter_CB_CB; + +import java.util.ArrayList; +import java.util.List; public class ComplexPrimeCICDecimate implements Listener { - 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, - 257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359, - 367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463, - 467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593, - 599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691 }; - - private ArrayList mDecimatingStages = - new ArrayList(); - - private DecimatingStage mFirstDecimatingStage; + 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, + 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, + 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, + 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691}; - private Output mOutput; + private ArrayList mDecimatingStages = + new ArrayList(); - /** - * Non-Recursive Prime-Factor CIC Filter with float sample array inputs and - * decimated, single paired i/q float sample output. - * - * Implements the CIC filter described in Understanding Digital Signal - * Processing, 3e, Lyons, on page 769. This filter is comprised of multiple - * decimating stages each with a prime factor decimation rate. Multiple - * stages are cascaded to achieve the overall decimation rate. - * - * This filter supports a maximum decimation rate of 700. This filter can - * be adapted to higher decimation rates by adding additional prime factors - * to the PRIMES array. - * - * @param decimation - overall decimation rate - * @param order - filter order - */ - public ComplexPrimeCICDecimate( int decimation, int order, - int passFrequency, int attenuation, WindowType windowType ) - { - Validate.isTrue(decimation <= 700); - + private DecimatingStage mFirstDecimatingStage; - List stageSizes = getPrimeFactors( decimation ); - - for( int x = 0; x < stageSizes.size(); x++ ) - { - DecimatingStage stage = new DecimatingStage( stageSizes.get( x ), order ); - - mDecimatingStages.add( stage ); - - if( x == 0 ) - { - /* Reference to first stage -- will receive all samples */ - mFirstDecimatingStage = stage; - } - else - { - /* Wire the current stage to the previous stage */ - mDecimatingStages.get( x - 1 ).setListener( stage ); - } - } - - mOutput = new Output( 48000, passFrequency, attenuation, windowType ); - - mDecimatingStages.get( mDecimatingStages.size() - 1 ) - .setListener( mOutput ); - } - - public void dispose() - { - for( DecimatingStage stage: mDecimatingStages ) - { - stage.dispose(); - } - - mDecimatingStages.clear(); - mDecimatingStages = null; - mFirstDecimatingStage = null; - - mOutput.dispose(); - mOutput = null; - } - - /** - * Adds a listener to receive the output of this CIC decimation filter - */ - public void setListener( Listener listener ) - { - mOutput.setListener( listener ); - } - - /** - * Removes listener from output of this CIC decimation filter - */ - public void removeListener() - { - mOutput.removeListener(); - } + private Output mOutput; - /** - * Calculates the prime factors of the decimation rate up to a maximum - * decimation rate of 700. If you wish to have decimation rates higher - * than 700, then add additional prime factors to the PRIMES array. - * - * @param decimation - integral decimation rate - * @return - ordered list (smallest to largest) of prime factors - */ - public static List getPrimeFactors( int decimation ) - { - ArrayList stages = new ArrayList(); - - int pointer = 0; - - while( decimation > 0 && pointer < PRIMES.length ) - { - int prime = PRIMES[ pointer ]; - - if( decimation % prime == 0 ) - { - stages.add( prime ); - - decimation /= prime; - } - else - { - pointer++; - } - } - - return stages; - } - - /** - * Primary input method for receiving sample arrays composed as I,Q,I,Q, etc. - */ - @Override - public void receive( ComplexBuffer buffer ) + /** + * Non-Recursive Prime-Factor CIC Filter with float sample array inputs and + * decimated, single paired i/q float sample output. + * + * Implements the CIC filter described in Understanding Digital Signal + * Processing, 3e, Lyons, on page 769. This filter is comprised of multiple + * decimating stages each with a prime factor decimation rate. Multiple + * stages are cascaded to achieve the overall decimation rate. + * + * This filter supports a maximum decimation rate of 700. This filter can + * be adapted to higher decimation rates by adding additional prime factors + * to the PRIMES array. + * + * @param decimation - overall decimation rate + * @param order - filter order + */ + public ComplexPrimeCICDecimate(int decimation, int order, + int passFrequency, int attenuation, WindowType windowType) { - if( mFirstDecimatingStage != null ) - { - float[] samples = buffer.getSamples(); - - for( int x = 0; x < samples.length; x += 2 ) - { - mFirstDecimatingStage.receive( samples[ x ], samples[ x + 1 ] ); - } - } - } - - /** - * Decimating stage combines multiple CIC stages with a decimator. The - * number of stages is indicated by the order value and the size indicates - * the decimation rate of this stage. - */ - public class DecimatingStage implements ComplexSampleListener - { - private ArrayList mStages = new ArrayList(); - private Stage mFirstStage; - private ComplexDecimator mDecimator; - - public DecimatingStage( int size, int order ) - { - for( int x = 0; x < order; x++ ) - { - Stage stage; - - if( size == 2 ) - { - stage = new TwoStage(); - } - else - { - stage = new Stage( size ); - } - - mStages.add( stage ); - - if( x == 0 ) - { - mFirstStage = stage; - } - else - { - mStages.get( x - 1 ).setListener( stage ); - } - } - - mDecimator = new ComplexDecimator( size ); - - mStages.get( mStages.size() - 1 ).setListener( mDecimator ); - } - - public void dispose() - { - for( Stage stage: mStages ) - { - stage.dispose(); - } - - mStages.clear(); - mDecimator.dispose(); - mDecimator = null; - mFirstStage = null; - mStages = null; - } + Validate.isTrue(decimation <= 700); - @Override - public void receive( float i, float q ) + + List stageSizes = getPrimeFactors(decimation); + + for(int x = 0; x < stageSizes.size(); x++) { - mFirstStage.receive( i, q ); - } - - public void setListener( ComplexSampleListener listener ) - { - mDecimator.setListener( listener ); - } - } - - /** - * Single non-decimating CIC stage component. Uses a circular buffer and a - * running average internally to implement the stage so that stage size has - * essentially no impact on the computational requirements of the stage - */ - public class Stage implements ComplexSampleListener - { - protected ComplexSampleListener mListener; - - private float[] mISamples; - private float[] mQSamples; - - protected float mISum; - protected float mQSum; - - private int mSamplePointer = 0; - private int mSize; - - protected float mGain; - - public Stage() - { - } + DecimatingStage stage = new DecimatingStage(stageSizes.get(x), order); - public Stage( int size ) - { - mSize = size - 1; - - mISamples = new float[ mSize ]; - mQSamples = new float[ mSize ]; - - mGain = 1.0f / (float)size; - } - - public void dispose() - { - mListener = null; - } - - public void receive( float i, float q ) - { + mDecimatingStages.add(stage); + + if(x == 0) + { + /* Reference to first stage -- will receive all samples */ + mFirstDecimatingStage = stage; + } + else + { + /* Wire the current stage to the previous stage */ + mDecimatingStages.get(x - 1).setListener(stage); + } + } + + mOutput = new Output(48000, passFrequency, attenuation, windowType); + + mDecimatingStages.get(mDecimatingStages.size() - 1) + .setListener(mOutput); + } + + public void dispose() + { + for(DecimatingStage stage : mDecimatingStages) + { + stage.dispose(); + } + + mDecimatingStages.clear(); + mDecimatingStages = null; + mFirstDecimatingStage = null; + + mOutput.dispose(); + mOutput = null; + } + + /** + * Adds a listener to receive the output of this CIC decimation filter + */ + public void setListener(Listener listener) + { + mOutput.setListener(listener); + } + + /** + * Removes listener from output of this CIC decimation filter + */ + public void removeListener() + { + mOutput.removeListener(); + } + + /** + * Calculates the prime factors of the decimation rate up to a maximum + * decimation rate of 700. If you wish to have decimation rates higher + * than 700, then add additional prime factors to the PRIMES array. + * + * @param decimation - integral decimation rate + * @return - ordered list (smallest to largest) of prime factors + */ + public static List getPrimeFactors(int decimation) + { + ArrayList stages = new ArrayList(); + + int pointer = 0; + + while(decimation > 0 && pointer < PRIMES.length) + { + int prime = PRIMES[pointer]; + + if(decimation % prime == 0) + { + stages.add(prime); + + decimation /= prime; + } + else + { + pointer++; + } + } + + return stages; + } + + /** + * Primary input method for receiving sample arrays composed as I,Q,I,Q, etc. + */ + @Override + public void receive(ComplexBuffer buffer) + { + if(mFirstDecimatingStage != null) + { + float[] samples = buffer.getSamples(); + + for(int x = 0; x < samples.length; x += 2) + { + mFirstDecimatingStage.receive(samples[x], samples[x + 1]); + } + } + } + + /** + * Decimating stage combines multiple CIC stages with a decimator. The + * number of stages is indicated by the order value and the size indicates + * the decimation rate of this stage. + */ + public class DecimatingStage implements ComplexSampleListener + { + private ArrayList mStages = new ArrayList(); + private Stage mFirstStage; + private ComplexDecimator mDecimator; + + public DecimatingStage(int size, int order) + { + for(int x = 0; x < order; x++) + { + Stage stage; + + if(size == 2) + { + stage = new TwoStage(); + } + else + { + stage = new Stage(size); + } + + mStages.add(stage); + + if(x == 0) + { + mFirstStage = stage; + } + else + { + mStages.get(x - 1).setListener(stage); + } + } + + mDecimator = new ComplexDecimator(size); + + mStages.get(mStages.size() - 1).setListener(mDecimator); + } + + public void dispose() + { + for(Stage stage : mStages) + { + stage.dispose(); + } + + mStages.clear(); + mDecimator.dispose(); + mDecimator = null; + mFirstStage = null; + mStages = null; + } + + @Override + public void receive(float i, float q) + { + mFirstStage.receive(i, q); + } + + public void setListener(ComplexSampleListener listener) + { + mDecimator.setListener(listener); + } + } + + /** + * Single non-decimating CIC stage component. Uses a circular buffer and a + * running average internally to implement the stage so that stage size has + * essentially no impact on the computational requirements of the stage + */ + public class Stage implements ComplexSampleListener + { + protected ComplexSampleListener mListener; + + private float[] mISamples; + private float[] mQSamples; + + protected float mISum; + protected float mQSum; + + private int mSamplePointer = 0; + private int mSize; + + protected float mGain; + + public Stage() + { + } + + public Stage(int size) + { + mSize = size - 1; + + mISamples = new float[mSize]; + mQSamples = new float[mSize]; + + mGain = 1.0f / (float)size; + } + + public void dispose() + { + mListener = 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 - mQSamples[ mSamplePointer ] + q; + mISum = mISum - mISamples[mSamplePointer] + i; + mQSum = mQSum - mQSamples[mSamplePointer] + q; /* Overwrite the oldest sample with the newest */ - mISamples[ mSamplePointer ] = i; - mQSamples[ mSamplePointer ] = q; - - mSamplePointer++; - - if( mSamplePointer >= mSize ) - { - mSamplePointer = 0; - } + mISamples[mSamplePointer] = i; + mQSamples[mSamplePointer] = q; - if( mListener != null ) - { - mListener.receive( ( mISum * mGain ), ( mQSum * mGain ) ); - } - } - - public void setListener( ComplexSampleListener listener ) - { - mListener = listener; - } - } - - /** - * Size 2 stage that removes the unnecessary circular buffer management for - * a two-stage. - */ - public class TwoStage extends Stage - { - public TwoStage() - { - super(); - - mGain = 0.5f; - } - - public void receive( float i, float q ) - { - float iSum = mISum + i; - float qSum = mQSum + q; - - mISum = i; - mQSum = q; - - if( mListener != null ) - { - mListener.receive( ( iSum * mGain ), ( qSum * mGain ) ); - } - } - } - + mSamplePointer++; - /** - * Output adapter - applies gain correction and cleanup filter and broadcast - * to registered listener. - */ - public class Output implements ComplexSampleListener - { - /* Decimated output buffers will contain 1024 samples */ - private ComplexToComplexBufferAssembler mAssembler = - new ComplexToComplexBufferAssembler( 2048 ); + if(mSamplePointer >= mSize) + { + mSamplePointer = 0; + } - private ComplexFIRFilter_CB_CB mCleanupFilter; - private HalfBandFilter_CB_CB mHalfBandFilter = new HalfBandFilter_CB_CB( - Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 0.4f, false ); - - public Output( int outputSampleRate, int passFrequency, int attenuation, - WindowType windowType ) - { - mCleanupFilter = new ComplexFIRFilter_CB_CB( FilterFactory - .getCICCleanupFilter( outputSampleRate, - passFrequency, - attenuation, - windowType ), 0.4f ); - - mAssembler.setListener( mCleanupFilter ); - mCleanupFilter.setListener( mHalfBandFilter ); - } - - public void dispose() - { - mAssembler.dispose(); - mCleanupFilter.dispose(); - mHalfBandFilter.dispose(); - } - - /** - * Receiver method for the output adapter to receive a filtered, - * decimated sample, apply gain correction, apply cleanup filtering - * and output the sample values as a complex sample. - */ - @Override - public void receive( float inphase, float quadrature ) - { - mAssembler.receive( inphase, quadrature ); - } - - /** - * Adds a listener to receive output samples - */ - public void setListener( Listener listener ) - { - mHalfBandFilter.setListener( listener ); + if(mListener != null) + { + mListener.receive((mISum * mGain), (mQSum * mGain)); + } } - /** - * Removes the listener from receiving output samples - */ + public void setListener(ComplexSampleListener listener) + { + mListener = listener; + } + } + + /** + * Size 2 stage that removes the unnecessary circular buffer management for + * a two-stage. + */ + public class TwoStage extends Stage + { + public TwoStage() + { + super(); + + mGain = 0.5f; + } + + public void receive(float i, float q) + { + float iSum = mISum + i; + float qSum = mQSum + q; + + mISum = i; + mQSum = q; + + if(mListener != null) + { + mListener.receive((iSum * mGain), (qSum * mGain)); + } + } + } + + + /** + * Output adapter - applies gain correction and cleanup filter and broadcast + * to registered listener. + */ + public class Output implements ComplexSampleListener + { + /* Decimated output buffers will contain 1024 samples */ + private ComplexToComplexBufferAssembler mAssembler = + new ComplexToComplexBufferAssembler(2048); + + private ComplexFIRFilter_CB_CB mCleanupFilter; + private HalfBandFilter_CB_CB mHalfBandFilter = new HalfBandFilter_CB_CB( + Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 0.4f, false); + + public Output(int outputSampleRate, int passFrequency, int attenuation, + WindowType windowType) + { + mCleanupFilter = new ComplexFIRFilter_CB_CB(FilterFactory + .getCICCleanupFilter(outputSampleRate, + passFrequency, + attenuation, + windowType), 0.4f); + + //Bypassing the CIC cleanup filter for now + mAssembler.setListener(mHalfBandFilter); + +// mAssembler.setListener( mCleanupFilter ); +// mCleanupFilter.setListener( mHalfBandFilter ); + } + + public void dispose() + { + mAssembler.dispose(); + mCleanupFilter.dispose(); + mHalfBandFilter.dispose(); + } + + /** + * Receiver method for the output adapter to receive a filtered, + * decimated sample, apply gain correction, apply cleanup filtering + * and output the sample values as a complex sample. + */ + @Override + public void receive(float inphase, float quadrature) + { + mAssembler.receive(inphase, quadrature); + } + + /** + * Adds a listener to receive output samples + */ + public void setListener(Listener listener) + { + mHalfBandFilter.setListener(listener); + } + + /** + * Removes the listener from receiving output samples + */ public void removeListener() { - mHalfBandFilter.removeListener(); + mHalfBandFilter.removeListener(); } - } + } }