Adds an AM Demodulator to the list of available decoders.

This commit is contained in:
dennis.sheirer
2014-10-11 18:00:49 +00:00
parent c5c3029392
commit 61ecb5abf2
15 changed files with 472 additions and 47 deletions

View File

@@ -1,27 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="lib" path="imports/commons-lang3-3.2.1.jar"/>
<classpathentry kind="lib" path="imports/jide-oss-3.5.15.jar"/>
<classpathentry kind="lib" path="imports/jsr80-1.0.1.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-arm.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-x86.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-osx-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-osx-x86.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-windows-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-windows-x86.jar"/>
<classpathentry kind="lib" path="imports/miglayout-4.0-swing.jar"/>
<classpathentry kind="lib" path="imports/usb-api-1.0.2.jar"/>
<classpathentry kind="lib" path="imports/usb4java-1.2.0.jar"/>
<classpathentry kind="lib" path="imports/usb4java-javax-1.2.0.jar"/>
<classpathentry kind="lib" path="config"/>
<classpathentry kind="lib" path="imports/JTransforms-3.0.jar" sourcepath="/home/denny/.m2/repository/com/github/wendykierp/JTransforms/3.0/JTransforms-3.0-sources.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-ppc.jar"/>
<classpathentry kind="lib" path="imports/JLargeArrays-1.2.jar"/>
<classpathentry kind="lib" path="imports/slf4j-api-1.7.7.jar"/>
<classpathentry kind="lib" path="imports/logback-classic-1.1.2.jar"/>
<classpathentry kind="lib" path="imports/logback-core-1.1.2.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="lib" path="imports/commons-lang3-3.2.1.jar"/>
<classpathentry kind="lib" path="imports/jide-oss-3.5.15.jar"/>
<classpathentry kind="lib" path="imports/jsr80-1.0.1.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-arm.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-x86.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-osx-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-osx-x86.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-windows-x86_64.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-windows-x86.jar"/>
<classpathentry kind="lib" path="imports/miglayout-4.0-swing.jar"/>
<classpathentry kind="lib" path="imports/usb-api-1.0.2.jar"/>
<classpathentry kind="lib" path="imports/usb4java-1.2.0.jar"/>
<classpathentry kind="lib" path="imports/usb4java-javax-1.2.0.jar"/>
<classpathentry kind="lib" path="config"/>
<classpathentry kind="lib" path="imports/JTransforms-3.0.jar" sourcepath="/home/denny/.m2/repository/com/github/wendykierp/JTransforms/3.0/JTransforms-3.0-sources.jar"/>
<classpathentry kind="lib" path="imports/libusb4java-1.2.0-linux-ppc.jar"/>
<classpathentry kind="lib" path="imports/JLargeArrays-1.2.jar"/>
<classpathentry kind="lib" path="imports/slf4j-api-1.7.7.jar"/>
<classpathentry kind="lib" path="imports/logback-classic-1.1.2.jar"/>
<classpathentry kind="lib" path="imports/logback-core-1.1.2.jar"/>
<classpathentry kind="lib" path="imports/commons-io-2.4.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -404,6 +404,7 @@ public class ProcessingChain implements Listener<Message>
}
if( mSource instanceof TunerChannelSource &&
mChannel.getDecodeConfiguration().supportsAFC() &&
mChannel.getDecodeConfiguration().isAFCEnabled() )
{
TunerChannelSource tcs = (TunerChannelSource)mSource;

View File

@@ -39,6 +39,8 @@ import controller.channel.Channel;
import controller.channel.Channel.ChannelType;
import controller.channel.ChannelEvent;
import controller.channel.ChannelEventListener;
import decode.am.AMChannelState;
import decode.am.AMPanel;
import decode.fleetsync2.FleetsyncChannelState;
import decode.fleetsync2.FleetsyncPanel;
import decode.ltrnet.LTRNetChannelState;
@@ -139,8 +141,12 @@ public class ChannelStateList extends JPanel implements ChannelEventListener
ChannelState state = channel.getProcessingChain().getChannelState();
ChannelStatePanel panel = null;
if( state instanceof NBFMChannelState )
if( state instanceof AMChannelState )
{
panel = new AMPanel( channel );
}
else if( state instanceof NBFMChannelState )
{
NBFMChannelState convState =
(NBFMChannelState)state;

View File

@@ -37,18 +37,21 @@ public class DecodeEditor extends Editor
{
mConfig = config;
mAFC = new JCheckBox( "Automatic Frequency Control" );
mAFC.setSelected( mConfig.isAFCEnabled() );
mAFC.addActionListener( new ActionListener()
if( config.supportsAFC() )
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
mConfig.setAFC( mAFC.isSelected() );
}
} );
mAFC = new JCheckBox( "Automatic Frequency Control" );
mAFC.setSelected( mConfig.isAFCEnabled() );
mAFC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
mConfig.setAFC( mAFC.isSelected() );
}
} );
add( mAFC, "wrap" );
add( mAFC, "wrap" );
}
}
public DecodeConfiguration getConfig()

View File

@@ -22,6 +22,8 @@ import alias.AliasList;
import controller.channel.ChannelMap;
import controller.channel.ProcessingChain;
import controller.state.ChannelState;
import decode.am.AMChannelState;
import decode.am.AMDecoder;
import decode.config.AuxDecodeConfiguration;
import decode.config.DecodeConfigLTRNet;
import decode.config.DecodeConfigLTRStandard;
@@ -62,6 +64,9 @@ public class DecoderFactory
switch( config.getDecoderType() )
{
case AM:
retVal = new AMDecoder( sampleType );
break;
case NBFM:
retVal = new NBFMConventionalDecoder( sampleType );
break;
@@ -128,12 +133,11 @@ public class DecoderFactory
switch( decodeConfig.getDecoderType() )
{
case AM:
retVal = new AMChannelState( chain, aliasList );
break;
case NBFM:
retVal = new NBFMChannelState( chain, aliasList );
DecodeConfigNBFM conv =
(DecodeConfigNBFM)decodeConfig;
break;
case LTR_STANDARD:
retVal = new LTRChannelState( chain, aliasList );

View File

@@ -25,6 +25,7 @@ import java.util.EnumSet;
*/
public enum DecoderType
{
AM( "AM", "AM", "images/am", 10000 ),
FLEETSYNC2( "Fleetsync II", "Fsync2", "images/fm", 12500 ),
LTR_STANDARD( "LTR-Standard", "LTR", "images/ltr_standard", 10000 ),
LTR_NET( "LTR-Net", "LTR-Net", "images/ltr_net", 10000 ),
@@ -53,7 +54,8 @@ public enum DecoderType
*/
public static EnumSet<DecoderType> getAvailableDecoders()
{
return EnumSet.of( DecoderType.LTR_NET,
return EnumSet.of( DecoderType.AM,
DecoderType.LTR_NET,
DecoderType.LTR_STANDARD,
DecoderType.MPT1327,
DecoderType.NBFM,

View File

@@ -0,0 +1,69 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package decode.am;
import alias.AliasList;
import audio.SquelchListener;
import audio.SquelchListener.SquelchState;
import controller.channel.ProcessingChain;
import controller.state.AuxChannelState;
import controller.state.ChannelState;
/**
* Conventional channel state - this class doesn't do anything at the moment,
* it is a place holder for future expansion for the conventional decoder
*/
public class AMChannelState extends ChannelState
{
public AMChannelState( ProcessingChain channel, AliasList aliasList )
{
super( channel, aliasList );
}
/**
* Make the ConventionalChannelState always unsquelched
*/
public void addListener( SquelchListener listener )
{
super.addListener( listener );
super.setSquelchState( SquelchState.UNSQUELCH );
}
@Override
public void setSquelchState( SquelchState state )
{
//do nothing ... we want the squelch state always unsquelched (for now)
}
@Override
public String getActivitySummary()
{
StringBuilder sb = new StringBuilder();
sb.append( "Activity Summary\n" );
sb.append( "\tDecoder:\tAM\n\n" );
for( AuxChannelState state: mAuxChannelStates )
{
sb.append( state.getActivitySummary() );
sb.append( "\n\n" );
}
return sb.toString();
}
}

View File

@@ -0,0 +1,68 @@
package decode.am;
import sample.Listener;
import source.Source.SampleType;
import decode.Decoder;
import decode.DecoderType;
import dsp.am.AMDemodulator;
import dsp.filter.DCRemovalFilter2;
public class AMDecoder extends Decoder
{
/**
* This value determines how quickly the DC remove filter responds to
* changes in frequency.
*/
private static final double DC_REMOVAL_RATIO = 0.000003;
private AMDemodulator mDemodulator;
private DCRemovalFilter2 mDCRemovalFilter;
public AMDecoder( SampleType sampleType )
{
super( sampleType );
/**
* Only setup a demod chain if we're receiving complex samples. If
* we're receiving demodulated samples, they'll be handled the same
* was as we handle the output of the demodulator.
*/
if( mSourceSampleType == SampleType.COMPLEX )
{
/**
* The Decoder super class is both a Complex listener and a float
* listener. So, we add the demod to listen to the incoming
* quadrature samples, and we wire the output of the demod right
* back to this class, so we can receive the demodulated output
* to process
*/
mDemodulator = new AMDemodulator();
this.addComplexListener( mDemodulator );
/**
* Remove the DC component that is present when we're mistuned
*/
mDCRemovalFilter = new DCRemovalFilter2( DC_REMOVAL_RATIO );
mDemodulator.addListener( mDCRemovalFilter );
/**
* Route the demodulated, filtered samples back to this class to send
* to all registered listeners
*/
mDCRemovalFilter.setListener( this.getFloatReceiver() );
}
}
@Override
public DecoderType getType()
{
return DecoderType.AM;
}
@Override
public void addUnfilteredFloatListener( Listener<Float> listener )
{
mDemodulator.addListener( listener );
}
}

View File

@@ -0,0 +1,31 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package decode.am;
import decode.DecodeEditor;
import decode.config.DecodeConfiguration;
public class AMEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
public AMEditor( DecodeConfiguration config )
{
super( config );
}
}

136
src/decode/am/AMPanel.java Normal file
View File

@@ -0,0 +1,136 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package decode.am;
import java.awt.EventQueue;
import javax.swing.JLabel;
import settings.ColorSetting;
import settings.Setting;
import controller.channel.Channel;
import controller.state.ChannelState.ChangedAttribute;
import controller.state.ChannelStatePanel;
public class AMPanel extends ChannelStatePanel
{
private static final long serialVersionUID = 1L;
private JLabel mStateLabel;
private JLabel mSourceLabel;
private JLabel mChannelLabel;
private JLabel mProtocol = new JLabel( "AM" );
public AMPanel( Channel channel )
{
super( channel );
init();
}
public void init()
{
mStateLabel = new JLabel( mChannel.getProcessingChain().
getChannelState().getState().getDisplayValue() );
mStateLabel.setFont( mFontDecoder );
mStateLabel.setForeground( mColorLabelDecoder );
mSourceLabel = new JLabel( mChannel.getSourceConfiguration().getDescription() );
mSourceLabel.setFont( mFontDetails );
mSourceLabel.setForeground( mColorLabelDetails );
mChannelLabel = new JLabel( mChannel.getChannelDisplayName() );
mChannelLabel.setFont( mFontDetails );
mChannelLabel.setForeground( mColorLabelDetails );
mProtocol.setFont( mFontDecoder );
mProtocol.setForeground( mColorLabelDecoder );
add( mStateLabel );
add( mSourceLabel );
add( mChannelLabel, "wrap" );
add( mProtocol, "wrap" );
}
@Override
public void receive( final ChangedAttribute changedAttribute )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
switch( changedAttribute )
{
case CHANNEL_STATE:
mStateLabel.setText( mChannel.getProcessingChain().
getChannelState().getState().getDisplayValue() );
break;
case SOURCE:
mSourceLabel.setText( mChannel.getSourceConfiguration()
.getDescription() );
break;
case CHANNEL_NAME:
case SITE_NAME:
case SYSTEM_NAME:
mChannelLabel.setText( mChannel.getChannelDisplayName() );
break;
}
repaint();
}
});
}
@Override
public void settingChanged( Setting setting )
{
super.settingChanged( setting );
if( setting instanceof ColorSetting )
{
ColorSetting colorSetting = (ColorSetting)setting;
switch( colorSetting.getColorSettingName() )
{
case CHANNEL_STATE_LABEL_DECODER:
if( mStateLabel != null )
{
mStateLabel.setForeground( mColorLabelDecoder );
}
if( mProtocol != null )
{
mProtocol.setForeground( mColorLabelDecoder );
}
break;
case CHANNEL_STATE_LABEL_DETAILS:
if( mSourceLabel != null )
{
mSourceLabel.setForeground( mColorLabelDetails );
}
if( mChannelLabel != null )
{
mChannelLabel.setForeground( mColorLabelDetails );
}
break;
}
}
}
}

View File

@@ -0,0 +1,35 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package decode.config;
import decode.DecoderType;
public class DecodeConfigAM extends DecodeConfiguration
{
public DecodeConfigAM()
{
super( DecoderType.AM );
setAFC( false );
}
public boolean supportsAFC()
{
return false;
}
}

View File

@@ -33,6 +33,9 @@ public class DecodeConfigFactory
switch( decoder )
{
case AM:
retVal = new DecodeConfigAM();
break;
case NBFM:
retVal = new DecodeConfigNBFM();
break;

View File

@@ -24,7 +24,8 @@ import javax.xml.bind.annotation.XmlSeeAlso;
import controller.config.Configuration;
import decode.DecoderType;
@XmlSeeAlso( { DecodeConfigNBFM.class,
@XmlSeeAlso( { DecodeConfigAM.class,
DecodeConfigNBFM.class,
DecodeConfigLTRNet.class,
DecodeConfigLTRStandard.class,
DecodeConfigMPT1327.class,
@@ -65,4 +66,9 @@ public abstract class DecodeConfiguration extends Configuration
{
mAFCEnabled = enabled;
}
public boolean supportsAFC()
{
return true;
}
}

View File

@@ -0,0 +1,62 @@
package dsp.am;
import sample.Broadcaster;
import sample.Listener;
import sample.complex.ComplexSample;
import dsp.filter.ComplexFIRFilter;
import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType;
public class AMDemodulator implements Listener<ComplexSample>
{
private Broadcaster<Float> mBroadcaster = new Broadcaster<Float>();
private ComplexFIRFilter mIQFilter;
public AMDemodulator()
{
this( FilterFactory.getLowPass( 48000, 2000, 73, WindowType.HAMMING ),
1000.0 );
}
public AMDemodulator( double[] iqFilter, double iqGain )
{
mIQFilter = new ComplexFIRFilter( iqFilter, iqGain );
mIQFilter.setListener( new Demodulator() );
}
@Override
public void receive( ComplexSample sample )
{
mIQFilter.receive( sample );
}
/**
* Adds a listener to receive demodulated samples
*/
public void addListener( Listener<Float> listener )
{
mBroadcaster.addListener( listener );
}
/**
* Removes a listener from receiving demodulated samples
*/
public void removeListener( Listener<Float> listener )
{
mBroadcaster.removeListener( listener );
}
public class Demodulator implements Listener<ComplexSample>
{
@Override
public void receive( ComplexSample sample )
{
float demodulated = (float)Math.abs(
Math.sqrt( ( sample.real() * sample.real() ) +
( sample.imaginery() * sample.imaginery() ) ) );
mBroadcaster.broadcast( demodulated * 30.0f );
}
}
}

View File

@@ -17,7 +17,6 @@
******************************************************************************/
package gui;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.EventQueue;
@@ -29,7 +28,6 @@ import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.swing.JFrame;