Updated spectral display to used dBm scale and removed baseline/amplification items.

Updated sample handling code to use -1.0 to 1.0 float values throughout, to support P25 decoder and symbol filter.
This commit is contained in:
dennis.sheirer
2014-11-01 17:39:06 +00:00
parent 86f374bb88
commit ae0568ff3b
34 changed files with 821 additions and 412 deletions

View File

@@ -29,9 +29,8 @@ import source.tuner.FrequencyChangeEvent;
import source.tuner.FrequencyChangeEvent.Attribute;
import spectrum.converter.DFTResultsConverter;
import spectrum.converter.RealDecibelConverter;
import spectrum.menu.AmplificationItem;
import spectrum.menu.AveragingItem;
import spectrum.menu.BaselineItem;
import spectrum.menu.DBScaleItem;
import spectrum.menu.FFTWidthItem;
import spectrum.menu.FFTWindowTypeItem;
import spectrum.menu.FrameRateItem;
@@ -359,14 +358,6 @@ public class ChannelSpectrumPanel extends JPanel
JMenu displayMenu = new JMenu( "Display" );
contextMenu.add( displayMenu );
/**
* Amplification menu
*/
JMenu amplificationMenu = new JMenu( "Amplification" );
amplificationMenu.add(
new AmplificationItem( ChannelSpectrumPanel.this, 50 ) );
displayMenu.add( amplificationMenu );
/**
* Averaging menu
*/
@@ -380,7 +371,7 @@ public class ChannelSpectrumPanel extends JPanel
*/
JMenu baselineMenu = new JMenu( "Baseline" );
baselineMenu.add(
new BaselineItem( ChannelSpectrumPanel.this, 50 ) );
new DBScaleItem( ChannelSpectrumPanel.this, 50 ) );
displayMenu.add( baselineMenu );
/**
@@ -436,18 +427,6 @@ public class ChannelSpectrumPanel extends JPanel
public void mouseReleased( MouseEvent e ) {}
}
@Override
public int getAmplification()
{
return mSpectrumPanel.getAmplification();
}
@Override
public void setAmplification( int amplification )
{
mSpectrumPanel.setAmplification( amplification );
}
@Override
public int getAveraging()
{
@@ -461,15 +440,15 @@ public class ChannelSpectrumPanel extends JPanel
}
@Override
public int getBaseline()
public int getDBScale()
{
return mSpectrumPanel.getBaseline();
return mSpectrumPanel.getDBScale();
}
@Override
public void setBaseline( int baseline )
public void setDBScale( int baseline )
{
mSpectrumPanel.setBaseline( baseline );
mSpectrumPanel.setDBScale( baseline );
}
public class DecimatingSampleAssembler

View File

@@ -2,23 +2,7 @@ package spectrum;
public interface SpectralDisplayAdjuster
{
/**
* Gets the amplification multiplier that is applied against the FFT bin
* results when displaying the value in the spectral display.
*
* @return amplification value ( 1 - 100 )
*/
public int getAmplification();
/**
* Sets the amplification multiplier that is applied against the FFT bin
* results when displaying the value in the spectral display.
*
* @param amplification value ( 1 - 100 )
*/
public void setAmplification( int amplification );
/**
/**
* Gets the averaging value indicating the number of FFT results that are
* averaged to produce each FFT results output.
*
@@ -34,22 +18,18 @@ public interface SpectralDisplayAdjuster
public void setAveraging( int averaging );
/**
* Gets the baseline used when plotting the FFT bin results in the FFT
* spectral display. This value determines the vertical position within the
* spectral display upon which the amplified values are added and then
* plotted.
* Gets the dBm scale used when plotting the FFT bin results in the FFT
* spectral display. This value determines the smallest displayed power
* spectrum value that is shown at the bottom of the display.
*
* @return averaging value ( 1 - 50 )
*/
public int getBaseline();
public int getDBScale();
/**
* Sets the baseline used when plotting the FFT bin results in the FFT
* spectral display. This value determines the vertical position within the
* spectral display upon which the amplified values are added and then
* plotted.
* Sets the dBm scale from 0 (top of display) to the scale value (bottom).
*
* @param baseline value ( 1 - 50 )
* @param baseline value ( -160 to -30 dBm )
*/
public void setBaseline( int baseline );
public void setDBScale( int baseline );
}

View File

@@ -64,9 +64,8 @@ import source.tuner.TunerSelectionListener;
import spectrum.OverlayPanel.ChannelDisplay;
import spectrum.converter.ComplexDecibelConverter;
import spectrum.converter.DFTResultsConverter;
import spectrum.menu.AmplificationItem;
import spectrum.menu.AveragingItem;
import spectrum.menu.BaselineItem;
import spectrum.menu.DBScaleItem;
import spectrum.menu.FFTWidthItem;
import spectrum.menu.FFTWindowTypeItem;
import spectrum.menu.FrameRateItem;
@@ -591,42 +590,24 @@ public class SpectralDisplayPanel extends JPanel
JMenu displayMenu = new JMenu( "Display" );
contextMenu.add( displayMenu );
if( event.getComponent() == mWaterfallPanel )
if( event.getComponent() != mWaterfallPanel )
{
/**
* Baseline menu
* DB Scale menu
*/
JMenu baselineMenu = new JMenu( "Baseline" );
baselineMenu.add(
new BaselineItem( mWaterfallPanel, 50 ) );
displayMenu.add( baselineMenu );
}
else
{
/**
* Amplification menu
*/
JMenu amplificationMenu = new JMenu( "Amplify" );
amplificationMenu.add(
new AmplificationItem( mSpectrumPanel, 50 ) );
displayMenu.add( amplificationMenu );
JMenu dbScaleMenu = new JMenu( "Scale: 0 to dBm" );
dbScaleMenu.add(
new DBScaleItem( mSpectrumPanel, -100 ) );
displayMenu.add( dbScaleMenu );
/**
* Averaging menu
*/
JMenu averagingMenu = new JMenu( "Average" );
JMenu averagingMenu = new JMenu( "Averaging" );
averagingMenu.add(
new AveragingItem( mSpectrumPanel, 4 ) );
displayMenu.add( averagingMenu );
/**
* Baseline menu
*/
JMenu baselineMenu = new JMenu( "Baseline" );
baselineMenu.add(
new BaselineItem( mSpectrumPanel, 50 ) );
displayMenu.add( baselineMenu );
/**
* Channel Display setting menu
*/

View File

@@ -37,7 +37,6 @@ import settings.ColorSetting.ColorSettingName;
import settings.Setting;
import settings.SettingChangeListener;
import buffer.FloatArrayCircularAveragingBuffer;
import buffer.FloatAveragingBuffer;
import controller.ResourceManager;
public class SpectrumPanel extends JPanel
@@ -53,10 +52,8 @@ public class SpectrumPanel extends JPanel
* correct width once the first sample set arrives */
private float[] mDisplayFFTBins = new float[ 1 ];
private FloatArrayCircularAveragingBuffer mFFTAveragingBuffer;
private FloatAveragingBuffer mScaleBuffer = new FloatAveragingBuffer( 20 );
private int mAmplification = 50;
private int mAveraging = 4;
private int mBaseline = 50;
private int mDBScale = -100; //dBm
/**
* Spectral Display Color Settings
@@ -96,9 +93,6 @@ public class SpectrumPanel extends JPanel
{
mAveraging = size;
// mResourceManager.getSettingsManager().setIntegerSetting(
// SPECTRUM_AVERAGING_SIZE, mAveraging );
mFFTAveragingBuffer =
new FloatArrayCircularAveragingBuffer( mAveraging );
}
@@ -108,24 +102,17 @@ public class SpectrumPanel extends JPanel
return mAveraging;
}
public void setAmplification( int amplification )
/**
* Sets the lowest decibel scale value to show on the display
*/
public void setDBScale( int dbScale )
{
mAmplification = amplification;
mDBScale = dbScale;
}
public int getAmplification()
public int getDBScale()
{
return mAmplification;
}
public void setBaseline( int baseline )
{
mBaseline = baseline;
}
public int getBaseline()
{
return mBaseline;
return mDBScale;
}
public void clearSpectrum()
@@ -149,17 +136,8 @@ public class SpectrumPanel extends JPanel
mColorSpectrumLine = getColor( ColorSettingName.SPECTRUM_LINE );
mAveraging = 4;
// mAveraging = getIntegerSetting( "spectrum_averaging_size", 4 );
}
// private int getIntegerSetting( String name, int defaultValue )
// {
// IntegerSetting setting = mResourceManager.getSettingsManager()
// .getIntegerSetting( name, defaultValue );
//
// return setting.getValue();
// }
private Color getColor( ColorSettingName name )
{
ColorSetting setting =
@@ -271,43 +249,38 @@ public class SpectrumPanel extends JPanel
//If we have FFT data to display ...
if( mDisplayFFTBins != null )
{
int binCount = mDisplayFFTBins.length - 1;
float amplify = mAmplification / 50.0f;
float insideHeight = size.height - mSpectrumInset;
float baseline = ( insideHeight * ( 50.0f / (float)mBaseline ) ) - 20.0f;
/* Use the DC component as a reference to scale values to panel height */
float scale = mScaleBuffer.get( ( insideHeight * 0.75f ) /
mDisplayFFTBins[ binCount ] );
float scalor = insideHeight / ( -mDBScale );
float insideWidth = size.width;
int binCount = mDisplayFFTBins.length;
float binSize = insideWidth / ( binCount );
for( int x = 0; x < binCount; x++ )
{
/**
* Height is an inverse value reflecting the drawable spectral
* display vertical axis between the inset value at the bottom
* and the top of the display. Values range from:
*
* top = 0
* bottom = insideHeight = panel height - mSpectrumInset
*/
float height = baseline - ( mDisplayFFTBins[ x ] * scale * amplify );
if( height > insideHeight )
{
height = insideHeight;
}
float height;
if( height < 0 )
if( mDisplayFFTBins[ x ] > 0 )
{
height = 0;
}
else
{
height = (float)( Math.abs( mDisplayFFTBins[ x ] ) * scalor );
if( height > insideHeight )
{
height = insideHeight;
}
if( height < 0 )
{
height = 0;
}
}
spectrumShape.lineTo( ( x * binSize ), height );
}

View File

@@ -47,13 +47,12 @@ import controller.ResourceManager;
*/
public class WaterfallPanel extends JPanel implements DFTResultsListener,
Pausable,
SettingChangeListener,
SpectralDisplayAdjuster
SettingChangeListener
{
private static final long serialVersionUID = 1L;
private static DecimalFormat sCURSOR_FORMAT = new DecimalFormat( "000.00000" );
private static final String sSPECTRUM_CURSOR = "spectrum_cursor";
private static final String sPAUSED = "PAUSED";
private static DecimalFormat CURSOR_FORMAT = new DecimalFormat( "0.00000" );
private static final String SPECTRUM_CURSOR = "spectrum_cursor";
private static final String PAUSED = "PAUSED";
private byte[] mPixels;
private int mFFTSize = 1024;
@@ -62,7 +61,6 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
private ColorModel mColorModel = WaterfallColorModel.getDefaultColorModel();
private Color mColorSpectrumCursor;
private Image mWaterfallImage;
private int mBaseline = 50;
private Point mCursorLocation = new Point( 0, 0 );
private boolean mCursorVisible = false;
@@ -71,8 +69,6 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
private ResourceManager mResourceManager;
private FloatAveragingBuffer mIntraBinAveragingBuffer = new FloatAveragingBuffer( 9 );
public WaterfallPanel( ResourceManager resourceManager )
{
super();
@@ -187,7 +183,7 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
mCursorLocation.x,
(float)(getSize().getHeight() ) ) );
String frequency = sCURSOR_FORMAT.format( mCursorFrequency / 1000000.0D );
String frequency = CURSOR_FORMAT.format( mCursorFrequency / 1000000.0D );
graphics.drawString( frequency ,
mCursorLocation.x + 5,
@@ -197,7 +193,7 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
if( mPaused.get() )
{
graphics.drawString( sPAUSED, 20, 20 );
graphics.drawString( PAUSED, 20, 20 );
}
graphics.dispose();
@@ -218,14 +214,9 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
System.arraycopy( mPixels, 0,
mPixels, mFFTSize, mPixels.length - mFFTSize );
float baseline = mBaseline / 50.0f;
/**
* Scale the power spectrum bin values into a byte range (0-255) value
* using the last bin as the scaling factor
* Find the average value and scale the display to it
*/
float scale = 256.0f / update[ update.length - 1 ];
double sum = 0.0d;
for( int x = 0; x < update.length - 1; x++ )
@@ -234,10 +225,12 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
}
float average = (float)( sum / (double)update.length - 1 );
float scale = 256.0f / average;
for( int x = 0; x < update.length - 1; x++ )
{
float value = ( update[ x ] - average ) * scale * baseline;
float value = ( average - update[ x ] ) * scale;
if( value < 0 )
{
@@ -285,42 +278,4 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
@Override
public void settingDeleted( Setting setting ) {}
@Override
public void setBaseline( int baseline )
{
mBaseline = baseline;
}
@Override
public int getBaseline()
{
return mBaseline;
}
@Override
public int getAmplification()
{
/* Not Implemented */
return 0;
}
@Override
public void setAmplification( int amplification )
{
/* Not Implemented */
}
@Override
public int getAveraging()
{
/* Not Implemented */
return 0;
}
@Override
public void setAveraging( int averaging )
{
/* Not Implemented */
}
}

View File

@@ -1,7 +1,17 @@
package spectrum.converter;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spectrum.DFTProcessor;
public class ComplexDecibelConverter extends DFTResultsConverter
{
private final static Logger mLog =
LoggerFactory.getLogger( DFTResultsConverter.class );
/**
* Converts the output of the JTransforms FloatFFT_1D.complexForward()
* calculation into a normalized power spectrum in decibels, per description
@@ -10,51 +20,40 @@ public class ComplexDecibelConverter extends DFTResultsConverter
@Override
public void receive( float[] results )
{
float dc = Math.abs( results[ 0 ] );
float[] processed = new float[ results.length / 2 ];
/* Output from JTransforms 3.0 has the lower and upper halves of the
* spectrum swapped. */
int half = processed.length / 2;
/* Ensure we have power in the DC power bin (bin 0), otherwise don't
* dispatch the results */
if( dc > 0 )
for( int x = 0; x < results.length; x += 2 )
{
float[] processed = new float[ results.length / 2 + 1 ];
/**
* Output from JTransforms 3.0 has the lower and upper halves of the
* spectrum swapped.
*/
int half = processed.length / 2;
float magnitude = (float)Math.sqrt( results[ x ] *
results[ x ] + results[ x + 1 ] * results[ x + 1 ] );
for( int x = 0; x < processed.length - 2; x ++ )
/* Place upper half of magnitudes in lower half of results, vice-versa */
if( x / 2 >= half )
{
int index = ( x + 1 ) * 2;
double magnitude2 = ( ( results[ index ] * results[ index ] ) +
( results[ index + 1 ] * results[ index + 1 ] ) );
if( x < half )
{
processed[ x + half ] = 10.0f *
(float)( Math.log10( magnitude2 / dc ) );
}
else
{
processed[ x - half ] = 10.0f *
(float)( Math.log10( magnitude2 / dc ) );
}
processed[ x / 2 - half ] = magnitude;
}
else
{
processed[ x / 2 + half ] = magnitude;
}
}
/* Use the DC component as the largest magnitude value to keep the
* display from jumping when a strong bursting signal exists */
float largestMagnitude = processed[ half ];
if( largestMagnitude > 0 )
{
/* Convert magnitudes to normized power spectrum dBm */
for( int i = 0; i < processed.length; i++ )
{
processed[ i ] = 20.0f *
(float)Math.log10( processed[ i ] / largestMagnitude );
}
/**
* Place scaled dc component in last bin of processed array as
* scaling reference
*/
processed[ results.length / 2 ] = processed[ half ];
/**
* Repair the erroneous DC component bin by using the average of
* the neighboring bins
*/
processed[ half ] = ( processed[ half - 1 ] +
processed[ half + 1 ] / 2.0f );
dispatch( processed );
}

View File

@@ -1,57 +0,0 @@
package spectrum.menu;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import spectrum.SpectralDisplayAdjuster;
public class AmplificationItem extends JSlider implements ChangeListener
{
private static final long serialVersionUID = 1L;
private SpectralDisplayAdjuster mAdjuster;
private int mDefaultValue;
public AmplificationItem( SpectralDisplayAdjuster adjuster, int defaultValue )
{
super( JSlider.HORIZONTAL, 1, 100, adjuster.getAmplification() );
mDefaultValue = defaultValue;
mAdjuster = adjuster;
setMajorTickSpacing( 10 );
setMinorTickSpacing( 5 );
setPaintTicks( true );
addChangeListener( this );
addMouseListener( new MouseListener()
{
@Override
public void mouseClicked( MouseEvent event )
{
if( event.getClickCount() == 2 )
{
AmplificationItem.this.setValue( mDefaultValue );
}
}
public void mouseReleased( MouseEvent arg0 ) {}
public void mousePressed( MouseEvent arg0 ) {}
public void mouseExited( MouseEvent arg0 ) {}
public void mouseEntered( MouseEvent arg0 ) {}
} );
}
@Override
public void stateChanged( ChangeEvent event )
{
int value = ((JSlider)event.getSource()).getValue();
mAdjuster.setAmplification( value );
}
}

View File

@@ -9,23 +9,24 @@ import javax.swing.event.ChangeListener;
import spectrum.SpectralDisplayAdjuster;
public class BaselineItem extends JSlider implements ChangeListener
public class DBScaleItem extends JSlider implements ChangeListener
{
private static final long serialVersionUID = 1L;
private SpectralDisplayAdjuster mAdjuster;
private int mDefaultValue;
public BaselineItem( SpectralDisplayAdjuster adjuster, int defaultValue )
public DBScaleItem( SpectralDisplayAdjuster adjuster, int defaultValue )
{
super( JSlider.HORIZONTAL, 1, 100, adjuster.getBaseline() );
super( JSlider.HORIZONTAL, -160, -30, adjuster.getDBScale() );
mDefaultValue = defaultValue;
mAdjuster = adjuster;
setMajorTickSpacing( 10 );
setMinorTickSpacing( 5 );
setMajorTickSpacing( 40 );
setMinorTickSpacing( 10 );
setPaintTicks( true );
setPaintLabels( true );
addChangeListener( this );
@@ -36,7 +37,7 @@ public class BaselineItem extends JSlider implements ChangeListener
{
if( event.getClickCount() == 2 )
{
BaselineItem.this.setValue( mDefaultValue );
DBScaleItem.this.setValue( mDefaultValue );
}
}
@@ -52,6 +53,6 @@ public class BaselineItem extends JSlider implements ChangeListener
{
int value = ((JSlider)event.getSource()).getValue();
mAdjuster.setBaseline( value );
mAdjuster.setDBScale( value );
}
}