Files
sdrtrunk/src/dsp/afc/AutomaticFrequencyControl.java
dennis.sheirer e61c3a891c Memory/CPU performance improvement and Audio/Mixer source restructuring
Converted to use float primitives and to keep samples in buffer format until the sample rate is decimated to 48kHz.  
Added new non-recursive, CIC decimation filter -- untested

Updated sound card/mixer input source management.  Now testing for mono/stereo support for each card and limiting channel choices accordingly.  Separated the mixersource into a ComplexMixer and and SimplexMixerSource.  The ComplexMixer is used for sound card based tuners like the funcube.  The SimplexMixerSource is used for demodulated sound card inputs.

Interfaces for sample handling - standardized on using 'Complex' to indicate I/Q samples and 'Simplex' to indicate demodulated float samples.  The processing chain now accepts either a decimated (48k) list of complex samples from a tuner channel source, or a 48k simplex buffer (array of demodulated float samples).

Resolved issue with HackRF tuner not applying tuner configuration information.
2014-10-26 10:11:30 +00:00

182 lines
3.2 KiB
Java

package dsp.afc;
import sample.simplex.SimplexSampleListener;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeEvent.Attribute;
import source.tuner.FrequencyChangeListener;
import buffer.FloatAveragingBuffer;
public class AutomaticFrequencyControl implements SimplexSampleListener,
FrequencyChangeListener
{
private static float LARGE_ERROR = 10000.0f;
private static float MEDIUM_ERROR = 5000.0f;
private static float SMALL_ERROR = 1000.0f;
private static float FINE_ERROR = 500.0f;
private static int SAMPLE_THRESHOLD = 15000;
private Mode mMode = Mode.FAST;
private FloatAveragingBuffer mBuffer =
new FloatAveragingBuffer( SAMPLE_THRESHOLD );
private int mSampleCounter = 0;
private int mSkipCounter = 0;
private int mSkipThreshold = 4;
private int mErrorCorrection = 0;
private long mCurrentFrequency;
private FrequencyChangeListener mListener;
public enum Mode
{
NORMAL,FAST;
}
public AutomaticFrequencyControl( FrequencyChangeListener listener )
{
mListener = listener;
}
public void dispose()
{
mListener = null;
mBuffer = null;
}
public int getErrorCorrection()
{
return mErrorCorrection;
}
public void reset()
{
mErrorCorrection = 0;
mMode = Mode.FAST;
dispatch();
}
private void dispatch()
{
if( mListener != null )
{
mListener.frequencyChanged(
new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR,
mErrorCorrection ) );
}
}
@Override
public void receive( float sample )
{
if( mMode == Mode.FAST )
{
float average = mBuffer.get( sample );
mSampleCounter++;
if( mSampleCounter >= SAMPLE_THRESHOLD )
{
mSampleCounter = 0;
update( average );
}
}
else
{
mSkipCounter++;
if( mSkipCounter >= mSkipThreshold )
{
mSkipCounter = 0;
float average = mBuffer.get( sample );
mSampleCounter++;
if( mSampleCounter >= SAMPLE_THRESHOLD )
{
mSampleCounter = 0;
update( average );
}
}
}
}
private void update( float average )
{
int correction = 0;
if( average > LARGE_ERROR )
{
correction = -1000;
mMode = Mode.FAST;
}
else if( average > MEDIUM_ERROR )
{
correction = -500;
mMode = Mode.FAST;
}
else if( average > SMALL_ERROR )
{
correction = -100;
mMode = Mode.NORMAL;
}
else if( average > FINE_ERROR )
{
correction = -50;
mMode = Mode.NORMAL;
}
else if( average < -LARGE_ERROR )
{
correction = 1000;
mMode = Mode.FAST;
}
else if( average < -MEDIUM_ERROR )
{
correction = 500;
mMode = Mode.FAST;
}
else if( average < -SMALL_ERROR )
{
correction = 100;
mMode = Mode.NORMAL;
}
else if( average < -FINE_ERROR )
{
correction = 50;
mMode = Mode.NORMAL;
}
if( correction != 0 )
{
mErrorCorrection -= correction;
dispatch();
}
else
{
mMode = Mode.NORMAL;
}
}
@Override
public void frequencyChanged( FrequencyChangeEvent event )
{
switch( event.getAttribute() )
{
case FREQUENCY:
int frequency = (int)event.getValue();
if( mCurrentFrequency != frequency )
{
mCurrentFrequency = frequency;
reset();
}
case SAMPLE_RATE_ERROR:
break;
default:
break;
}
}
}