P25 - Automatic Gain Control for P25 decoder

This commit is contained in:
dennis.sheirer
2015-01-19 19:25:43 +00:00
parent 1c0da75c01
commit e5fad7ee22
14 changed files with 154 additions and 162 deletions

View File

@@ -1,85 +0,0 @@
package dsp.fsk;
import instrument.Instrumentable;
import instrument.tap.Tap;
import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import sample.real.RealSampleListener;
public class C4FMDecoder implements RealSampleListener, Instrumentable
{
private static final String TAP_C4FM_INPUT = "C4FM Decoder Input";
private static final String TAP_SYMBOL_FILTER_OUTPUT = "C4FM Symbol Filter Output";
private ArrayList<Tap> mTaps;
private FloatTap mInputTap;
private FloatTap mSymbolFilterOutputTap;
private C4FMSymbolFilter mSymbolFilter = new C4FMSymbolFilter();
private RealSampleListener mInput;
public C4FMDecoder()
{
mInput = mSymbolFilter;
}
@Override
public void receive( float sample )
{
mInput.receive( sample );
}
@Override
public List<Tap> getTaps()
{
if( mTaps == null )
{
mTaps = new ArrayList<Tap>();
FloatTap floatTap = new FloatTap( TAP_C4FM_INPUT, 0, 1.0f );
mTaps.add( floatTap );
FloatTap symbolTap = new FloatTap( TAP_SYMBOL_FILTER_OUTPUT, 10, 0.1f );
mTaps.add( symbolTap );
}
return mTaps;
}
@Override
public void addTap( Tap tap )
{
switch( tap.getName() )
{
case TAP_C4FM_INPUT:
mInputTap = (FloatTap)tap;
mInput = mInputTap;
mInputTap.setListener( mSymbolFilter );
break;
case TAP_SYMBOL_FILTER_OUTPUT:
mSymbolFilterOutputTap = (FloatTap)tap;
mSymbolFilter.setListener( mSymbolFilterOutputTap );
break;
}
}
@Override
public void removeTap( Tap tap )
{
switch( tap.getName() )
{
case TAP_C4FM_INPUT:
mInput = mSymbolFilter;
mInputTap = null;
break;
case TAP_SYMBOL_FILTER_OUTPUT:
mSymbolFilter.removeListener( mSymbolFilterOutputTap );
mSymbolFilterOutputTap = null;
break;
}
}
}

View File

@@ -17,6 +17,7 @@ import source.tuner.FrequencyChangeBroadcaster;
import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeEvent.Attribute;
import source.tuner.FrequencyChangeListener;
import dsp.gain.GainController;
public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
RealSampleListener,
@@ -201,10 +202,11 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
private RealSampleListener mListener;
public static final long MAX_FREQUENCY_CORRECTION = 7000;
private FrequencyChangeListener mFrequencyChangeListener;
private long mFrequencyCorrection;
private float mGain = 15.4f;
private GainController mGainController;
/**
* C4FM Symbol Filter
@@ -219,13 +221,9 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
* setting for this filter is 15.4 and that yields a symbol spread that
* is centered on 2.0, ranging 1.92 to 2.08.
*/
public C4FMSymbolFilter( float gain )
{
mGain = gain;
}
public C4FMSymbolFilter()
public C4FMSymbolFilter( GainController gainController )
{
mGainController = gainController;
}
public long getFrequencyCorrection()
@@ -238,7 +236,8 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
{
mSymbolClock += mSymbolTime;
mHistory[ mHistoryLast++ ] = sample * mGain;
mHistory[ mHistoryLast++ ] = sample;
mHistoryLast %= NUMBER_FILTER_TAPS;
if( mSymbolClock > 1.0f )
@@ -317,9 +316,19 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
mSymbolClock -= symbolError * K_SYMBOL_TIMING;
}
mSymbolSpread = Math.max( mSymbolSpread, SYMBOL_SPREAD_MIN );
mSymbolSpread = Math.min( mSymbolSpread, SYMBOL_SPREAD_MAX );
if( mSymbolSpread < SYMBOL_SPREAD_MIN )
{
mGainController.increase();
mSymbolSpread = SYMBOL_SPREAD_MIN;
}
else if( mSymbolSpread > SYMBOL_SPREAD_MAX )
{
mGainController.decrease();
mSymbolSpread = SYMBOL_SPREAD_MAX;
}
mCoarseFrequencyCorrection += ( ( mFineFrequencyCorrection -
mCoarseFrequencyCorrection ) * K_COARSE_FREQUENCY );
@@ -333,14 +342,21 @@ public class C4FMSymbolFilter implements FrequencyChangeBroadcaster,
mFrequencyCorrection += (
500 * ( mCoarseFrequencyCorrection > 0 ? 1 : -1 ) );
if( mFrequencyCorrection > MAX_FREQUENCY_CORRECTION )
{
mFrequencyCorrection = MAX_FREQUENCY_CORRECTION;
}
else if( -mFrequencyCorrection > MAX_FREQUENCY_CORRECTION )
{
mFrequencyCorrection = -MAX_FREQUENCY_CORRECTION;
}
mFrequencyChangeListener.frequencyChanged(
new FrequencyChangeEvent( Attribute.FREQUENCY_ERROR,
mFrequencyCorrection ) );
/* reset internal frequency error tracker */
mCoarseFrequencyCorrection = 0;
mLog.debug( "Frequency Corrected: " + mFrequencyCorrection );
}
}