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();
}
- }
+ }
}