mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-10 23:57:25 -05:00
Compare commits
7 Commits
v0.3.0-bet
...
v0.3.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf0018e6ba | ||
|
|
e8055dcab0 | ||
|
|
fce3d5c4f3 | ||
|
|
9cc0d367a8 | ||
|
|
2ca9e5d5ce | ||
|
|
861203c3a0 | ||
|
|
7c930deefe |
@@ -7,7 +7,7 @@
|
||||
<property name="major" value="0"/>
|
||||
<property name="minor" value="3"/>
|
||||
<property name="patch" value="0"/>
|
||||
<property name="release" value="-beta3"/>
|
||||
<property name="release" value="-beta4"/>
|
||||
<property name="filename" value="sdrtrunk_${major}.${minor}.${patch}${release}"/>
|
||||
|
||||
<!-- Build properties -->
|
||||
|
||||
@@ -631,36 +631,47 @@ public class AliasList implements Listener<AliasEvent>
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this alias list has a non-null, non-empty name
|
||||
*/
|
||||
private boolean hasName()
|
||||
{
|
||||
return mName != null && !mName.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive alias change event notifications and modify this list accordingly
|
||||
*/
|
||||
@Override
|
||||
public void receive(AliasEvent event)
|
||||
{
|
||||
Alias alias = event.getAlias();
|
||||
|
||||
switch(event.getEvent())
|
||||
if(hasName())
|
||||
{
|
||||
case ADD:
|
||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
||||
{
|
||||
addAlias(alias);
|
||||
}
|
||||
break;
|
||||
case CHANGE:
|
||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
||||
{
|
||||
addAlias(alias);
|
||||
}
|
||||
break;
|
||||
case DELETE:
|
||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
||||
{
|
||||
removeAlias(alias);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
Alias alias = event.getAlias();
|
||||
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case ADD:
|
||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
||||
{
|
||||
addAlias(alias);
|
||||
}
|
||||
break;
|
||||
case CHANGE:
|
||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
||||
{
|
||||
addAlias(alias);
|
||||
}
|
||||
break;
|
||||
case DELETE:
|
||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
||||
{
|
||||
removeAlias(alias);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,22 +197,44 @@ public class PatchGroupAlias extends Alias
|
||||
return hasPatchGroupAlias() && getPatchGroupAlias().hasActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest listenable audio priority defined among the aliases in the group, or returns 'Do Not Monitor'
|
||||
* if that is the only priority defined. Otherwise, returns default (100) priority.
|
||||
*/
|
||||
@Override
|
||||
public int getCallPriority()
|
||||
{
|
||||
int highestPriority = (hasPatchGroupAlias() ? getPatchGroupAlias().getCallPriority() : Priority.DEFAULT_PRIORITY);
|
||||
boolean hasDoNotMonitor = false;
|
||||
|
||||
int highestPriority = (hasPatchGroupAlias() ? getPatchGroupAlias().getCallPriority() : Priority.DEFAULT_PRIORITY + 1);
|
||||
|
||||
for(Alias alias: mPatchedAliases)
|
||||
{
|
||||
if(!(alias instanceof PatchGroupAlias) &&
|
||||
alias.hasCallPriority() &&
|
||||
alias.getCallPriority() < highestPriority)
|
||||
if(!(alias instanceof PatchGroupAlias) && alias.hasCallPriority() && alias.getCallPriority() < highestPriority)
|
||||
{
|
||||
highestPriority = alias.getCallPriority();
|
||||
if(alias.getCallPriority() == Priority.DO_NOT_MONITOR)
|
||||
{
|
||||
hasDoNotMonitor = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
highestPriority = alias.getCallPriority();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return highestPriority;
|
||||
if(highestPriority <= Priority.DEFAULT_PRIORITY)
|
||||
{
|
||||
return highestPriority;
|
||||
}
|
||||
else if(hasDoNotMonitor)
|
||||
{
|
||||
return Priority.DO_NOT_MONITOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Priority.DEFAULT_PRIORITY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,65 +1,64 @@
|
||||
package dsp.filter.design;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import dsp.filter.fir.FIRFilterSpecification;
|
||||
import dsp.filter.fir.remez.RemezFIRFilterDesigner;
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FilterViewer extends Application
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( FilterViewer.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger(FilterViewer.class);
|
||||
|
||||
/**
|
||||
* Developer tool to visualize filter designs
|
||||
*/
|
||||
public FilterViewer()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start( Stage primaryStage ) throws Exception
|
||||
{
|
||||
Scene scene = new Scene( new FilterView( getFilter() ) );
|
||||
|
||||
primaryStage.setTitle( "Filter Viewer" );
|
||||
primaryStage.setScene( scene );
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
public static void main( String[] args )
|
||||
{
|
||||
launch( args );
|
||||
}
|
||||
/**
|
||||
* Developer tool to visualize filter designs
|
||||
*/
|
||||
public FilterViewer()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the filter to visualize. Modify this method to visualize your filter design.
|
||||
*/
|
||||
private float[] getFilter()
|
||||
{
|
||||
// FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
// .sampleRate( 48000 )
|
||||
// .gridDensity( 16 )
|
||||
// .passBandCutoff( 3200 )
|
||||
// .passBandAmplitude( 1.0 )
|
||||
// .passBandRipple( 0.02 )
|
||||
// .stopBandStart( 4000 )
|
||||
// .stopBandAmplitude( 0.0 )
|
||||
// .stopBandRipple( 0.03 )
|
||||
// .build();
|
||||
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder()
|
||||
.sampleRate( 24000 )
|
||||
.stopBandCutoff( 800 )
|
||||
.stopBandAmplitude( 0.0 )
|
||||
.stopBandRipple( 0.03 )
|
||||
.passBandStart( 1000 )
|
||||
.passBandAmplitude( 1.0 )
|
||||
.passBandRipple( 0.08 )
|
||||
.build();
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception
|
||||
{
|
||||
Scene scene = new Scene(new FilterView(getFilter()));
|
||||
|
||||
primaryStage.setTitle("Filter Viewer");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
launch(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the filter to visualize. Modify this method to visualize your filter design.
|
||||
*/
|
||||
private float[] getFilter()
|
||||
{
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(48000)
|
||||
.gridDensity(16)
|
||||
.passBandCutoff(2500)
|
||||
.passBandAmplitude(1.0)
|
||||
.passBandRipple(0.01)
|
||||
.stopBandStart(4000)
|
||||
.stopBandAmplitude(0.0)
|
||||
.stopBandRipple(0.008)
|
||||
.build();
|
||||
|
||||
// FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder()
|
||||
// .sampleRate(24000)
|
||||
// .stopBandCutoff(800)
|
||||
// .stopBandAmplitude(0.0)
|
||||
// .stopBandRipple(0.03)
|
||||
// .passBandStart(1000)
|
||||
// .passBandAmplitude(1.0)
|
||||
// .passBandRipple(0.08)
|
||||
// .build();
|
||||
|
||||
// FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder()
|
||||
// .sampleRate( 48000 )
|
||||
@@ -71,24 +70,25 @@ public class FilterViewer extends Application
|
||||
// .passRipple( 0.008)
|
||||
// .build();
|
||||
|
||||
float[] taps = null;
|
||||
float[] taps = null;
|
||||
|
||||
// taps = FilterFactory.getLowPass( 16000, 2400, 73, WindowType.HANNING );
|
||||
// taps = FilterFactory.getLowPass(48000, 6750, 7500, 60,
|
||||
// Window.WindowType.HAMMING, true);
|
||||
|
||||
try
|
||||
{
|
||||
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner( specification );
|
||||
|
||||
if( designer.isValid() )
|
||||
{
|
||||
taps = designer.getImpulseResponse();
|
||||
}
|
||||
}
|
||||
catch( FilterDesignException fde )
|
||||
{
|
||||
mLog.error( "Filter design error", fde );
|
||||
}
|
||||
|
||||
return taps;
|
||||
}
|
||||
try
|
||||
{
|
||||
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
|
||||
|
||||
if(designer.isValid())
|
||||
{
|
||||
taps = designer.getImpulseResponse();
|
||||
}
|
||||
}
|
||||
catch(FilterDesignException fde)
|
||||
{
|
||||
mLog.error("Filter design error", fde);
|
||||
}
|
||||
|
||||
return taps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,35 +103,35 @@ public class DecoderFactory
|
||||
|
||||
//Low-pass filter with ~60 dB attenuation and 89 taps
|
||||
private static final FIRFilterSpecification MPT1327_FILTER_SPECIFICATION = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate( 48000 )
|
||||
.gridDensity( 16 )
|
||||
.passBandCutoff( 3200 )
|
||||
.passBandAmplitude( 1.0 )
|
||||
.passBandRipple( 0.02 )
|
||||
.stopBandStart( 4000 )
|
||||
.stopBandAmplitude( 0.0 )
|
||||
.stopBandRipple( 0.03 )
|
||||
.build();
|
||||
.sampleRate( 48000 ).gridDensity( 16 ).passBandCutoff( 3200 ).passBandAmplitude( 1.0 ).passBandRipple( 0.02 )
|
||||
.stopBandStart( 4000 ).stopBandAmplitude( 0.0 ).stopBandRipple( 0.03 ).build();
|
||||
|
||||
private static final FIRFilterSpecification P25_C4FM_IQ_SPECIFICATION = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(48000).gridDensity(16).passBandCutoff(6750).passBandAmplitude(1.0).passBandRipple(0.01)
|
||||
.stopBandStart(7000).stopBandAmplitude(0.0).stopBandRipple(0.008).build();
|
||||
|
||||
private static final FIRFilterSpecification P25_C4FM_DEMOD_SPECIFICATION = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(48000).gridDensity(16).passBandCutoff(2500).passBandAmplitude(1.0).passBandRipple(0.01)
|
||||
.stopBandStart(4000).stopBandAmplitude(0.0).stopBandRipple(0.008).build();
|
||||
|
||||
private static float[] MPT1327_LOWPASS_FILTER;
|
||||
private static float[] P25_C4FM_IQ_FILTER;
|
||||
private static float[] P25_C4FM_DEMOD_FILTER;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
MPT1327_LOWPASS_FILTER = FilterFactory.getTaps(MPT1327_FILTER_SPECIFICATION);
|
||||
P25_C4FM_IQ_FILTER = FilterFactory.getTaps(P25_C4FM_IQ_SPECIFICATION);
|
||||
P25_C4FM_DEMOD_FILTER = FilterFactory.getTaps(P25_C4FM_DEMOD_SPECIFICATION);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Couldn't design MPT1327 bandpass filter");
|
||||
mLog.error("Couldn't design startup filter(s)");
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean NO_REMOVE_DC = false;
|
||||
public static final boolean REMOVE_DC = true;
|
||||
|
||||
public static final int NO_FREQUENCY_CORRECTION = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of one primary decoder and any auxiliary decoders, as
|
||||
* specified in the configurations.
|
||||
@@ -228,7 +228,7 @@ public class DecoderFactory
|
||||
}
|
||||
|
||||
modules.add(new FMDemodulatorModule(iqPass, iqStop));
|
||||
modules.add(new DemodulatedAudioFilterModule(MPT1327_LOWPASS_FILTER, 1.0f));
|
||||
modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f));
|
||||
modules.add(new AudioModule(metadata));
|
||||
break;
|
||||
case PASSPORT:
|
||||
@@ -247,7 +247,8 @@ public class DecoderFactory
|
||||
switch(modulation)
|
||||
{
|
||||
case C4FM:
|
||||
modules.add(new FMDemodulatorModule(6750, 7500));
|
||||
modules.add(new FMDemodulatorModule(P25_C4FM_IQ_FILTER));
|
||||
modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f));
|
||||
modules.add(new P25_C4FMDecoder(aliasList, decodeConfig.getAFCMaximumCorrection()));
|
||||
modules.add(new P25DecoderState(aliasList, channelType, Modulation.C4FM,
|
||||
p25Config.getIgnoreDataCalls()));
|
||||
|
||||
@@ -47,12 +47,10 @@ public class P25_C4FMDecoder extends P25Decoder
|
||||
private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class );
|
||||
|
||||
/* Instrumentation Taps */
|
||||
private static final String INSTRUMENT_FILTER_OUTPUT = "Tap Point: Pre-Filter Output";
|
||||
private static final String INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT = "Tap Point: Symbol Filter Output";
|
||||
private static final String INSTRUMENT_C4FM_SLICER_OUTPUT = "Tap Point: C4FM Slicer Output";
|
||||
|
||||
private List<TapGroup> mAvailableTaps;
|
||||
private RealFIRFilter_RB_RB mC4FMPreFilter;
|
||||
private C4FMSymbolFilter mSymbolFilter;
|
||||
private C4FMSlicer mC4FMSlicer;
|
||||
private P25MessageFramer mMessageFramer;
|
||||
@@ -74,15 +72,9 @@ public class P25_C4FMDecoder extends P25Decoder
|
||||
{
|
||||
super( aliasList );
|
||||
|
||||
/* Filter demodulated sample buffers */
|
||||
float[] filter = FilterFactory.getLowPass( 48000, 2500, 4000, 80, WindowType.HANNING, true );
|
||||
|
||||
mC4FMPreFilter = new RealFIRFilter_RB_RB( filter, 1.0f );
|
||||
|
||||
/* Shape gain and frequency offsets to optimize sample stream */
|
||||
mSymbolFilter = new C4FMSymbolFilter( frequencyCorrectionMaximum );
|
||||
mC4FMPreFilter.setListener( mSymbolFilter );
|
||||
|
||||
|
||||
/* Convert samples to symbols */
|
||||
mC4FMSlicer = new C4FMSlicer();
|
||||
mSymbolFilter.setListener( mC4FMSlicer );
|
||||
@@ -100,9 +92,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
||||
{
|
||||
super.dispose();
|
||||
|
||||
mC4FMPreFilter.dispose();
|
||||
mC4FMPreFilter = null;
|
||||
|
||||
mSymbolFilter.dispose();
|
||||
mSymbolFilter = null;
|
||||
|
||||
@@ -121,7 +110,7 @@ public class P25_C4FMDecoder extends P25Decoder
|
||||
@Override
|
||||
public Listener<RealBuffer> getFilteredRealBufferListener()
|
||||
{
|
||||
return mC4FMPreFilter;
|
||||
return mSymbolFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,8 +125,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
||||
|
||||
TapGroup group = new TapGroup( "P25 C4FM Decoder" );
|
||||
|
||||
group.add( new FloatBufferTap( INSTRUMENT_FILTER_OUTPUT, 0, 1.0f ) );
|
||||
|
||||
group.add( new FloatTap( INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT, 0, 0.1f ) );
|
||||
group.add( new DibitTap( INSTRUMENT_C4FM_SLICER_OUTPUT, 0, 0.1f ) );
|
||||
|
||||
@@ -165,11 +152,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
||||
|
||||
switch( tap.getName() )
|
||||
{
|
||||
case INSTRUMENT_FILTER_OUTPUT:
|
||||
FloatBufferTap filterOutput = (FloatBufferTap)tap;
|
||||
mC4FMPreFilter.setListener( filterOutput );
|
||||
filterOutput.setListener( mSymbolFilter );
|
||||
break;
|
||||
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
||||
FloatTap symbolTap = (FloatTap)tap;
|
||||
mSymbolFilter.setListener( symbolTap );
|
||||
@@ -201,9 +183,6 @@ public class P25_C4FMDecoder extends P25Decoder
|
||||
|
||||
switch( tap.getName() )
|
||||
{
|
||||
case INSTRUMENT_FILTER_OUTPUT:
|
||||
mC4FMPreFilter.setListener( mSymbolFilter );
|
||||
break;
|
||||
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
||||
mSymbolFilter.setListener( mC4FMSlicer );
|
||||
break;
|
||||
|
||||
@@ -62,6 +62,13 @@ public class FMDemodulatorModule extends Module implements IComplexBufferListene
|
||||
mIQFilter.setListener(mDemodulator);
|
||||
}
|
||||
|
||||
public FMDemodulatorModule(float[] filter)
|
||||
{
|
||||
mIQFilter = new ComplexFIRFilter_CB_CB(filter, 1.0f);
|
||||
mDemodulator = new FMDemodulator_CB(1.0f);
|
||||
mIQFilter.setListener(mDemodulator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<ComplexBuffer> getComplexBufferListener()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user