WIP - identifier framework and restructuring P25 messages to provide

identifiers.
This commit is contained in:
Denny
2018-08-31 04:50:58 -04:00
parent f963d821a1
commit 9acdf22b91
9 changed files with 87 additions and 42 deletions

View File

@@ -760,26 +760,28 @@ public class FilterFactory
* Polyphase M2 synthesizer sync filter. Designed for multiple M2 oversampled channel inputs and
* an M*channel count output.
*
* @param channelBandwidth per channel
* @param channels count
* @param channelSampleRate per input channel
* @param channelBandwidth per input channel
* @param channels input count
* @param tapsPerChannel minumum. This may be increased to meet the band edge -6.02dB requirement
* @return filter
* @throws FilterDesignException
*/
public static float[] getSincM2Synthesizer(double channelBandwidth, int channels, int tapsPerChannel)
throws FilterDesignException
public static float[] getSincM2Synthesizer(double channelSampleRate, double channelBandwidth, int channels,
int tapsPerChannel) throws FilterDesignException
{
int filterLength = (channels * tapsPerChannel) - 1;
double cutoff = (channelBandwidth * 1.05) / (channelSampleRate * (double)channels);
//Design the prototype synthesizer with 105% of the channel bandwidth produced by the channelizer.
float[] taps = FilterFactory.getKaiserSinc(filterLength, channelBandwidth * 1.05, 80.0);
float[] taps = FilterFactory.getKaiserSinc(filterLength, cutoff, 80.0);
//This is an odd length filter - increase the length by 1 by pre-padding a zero coefficient
float[] extendedTaps = new float[taps.length + 1];
System.arraycopy(taps, 0, extendedTaps, 1, taps.length);
//Adjust the overall gain of the filter to an objective of 1.0 divided by the number of channels
return normalize(extendedTaps, 1.0f);
return extendedTaps;
}
/**
@@ -918,17 +920,18 @@ public class FilterFactory
mLog.debug("Filter Length: " + (extendedTaps.length));
mLog.debug("Requested Cutoff Frequency: " + (sampleRate * bandEdge));
mLog.debug("Actual Cutoff Frequency: " + (sampleRate * cutoffFrequency));
mLog.debug("Attenuation at 0.0 OBJECTIVE: " + 0.0);
mLog.debug("Attenuation at 1.0 OBJECTIVE: " + PERFECT_RECONSTRUCTION_GAIN_AT_BAND_EDGE);
mLog.debug("Attenuation at 1.00 Channels: " + evaluate(taps, bandEdge * 1.00) + "\tFrequency: " + (sampleRate * bandEdge * 1.0));
mLog.debug("Attenuation at 1.25 Channels: " + evaluate(taps, bandEdge * 1.25) + "\tFrequency: " + (sampleRate * bandEdge * 1.25));
mLog.debug("Attenuation at 1.50 Channels: " + evaluate(taps, bandEdge * 1.50) + "\tFrequency: " + (sampleRate * bandEdge * 1.5));
mLog.debug("Attenuation at 1.75 Channels: " + evaluate(taps, bandEdge * 1.75) + "\tFrequency: " + (sampleRate * bandEdge * 1.75));
mLog.debug("Attenuation at 2.00 Channels: " + evaluate(taps, bandEdge * 2.00) + "\tFrequency: " + (sampleRate * bandEdge * 2.0));
mLog.debug("Attenuation at 0.25 Channels: " + evaluate(taps, bandEdge * 0.25) + "\tFrequency: " + (sampleRate * bandEdge * 0.25) + " [" + (bandEdge * 0.25) + "]");
mLog.debug("Attenuation at 0.50 Channels: " + evaluate(taps, bandEdge * 0.50) + "\tFrequency: " + (sampleRate * bandEdge * 0.50) + " [" + (bandEdge * 0.50) + "]");
mLog.debug("Attenuation at 0.75 Channels: " + evaluate(taps, bandEdge * 0.75) + "\tFrequency: " + (sampleRate * bandEdge * 0.75) + " [" + (bandEdge * 0.75) + "]");
mLog.debug("Attenuation OBJECTIVE: " + PERFECT_RECONSTRUCTION_GAIN_AT_BAND_EDGE);
mLog.debug("Attenuation at 1.00 Channels: " + evaluate(taps, bandEdge * 1.00) + "\tFrequency: " + (sampleRate * bandEdge * 1.0) + " [" + (bandEdge * 1.0) + "]");
mLog.debug("Attenuation at 1.25 Channels: " + evaluate(taps, bandEdge * 1.25) + "\tFrequency: " + (sampleRate * bandEdge * 1.25) + " [" + (bandEdge * 1.25) + "]");
mLog.debug("Attenuation at 1.50 Channels: " + evaluate(taps, bandEdge * 1.50) + "\tFrequency: " + (sampleRate * bandEdge * 1.5) + " [" + (bandEdge * 1.5) + "]");
mLog.debug("Attenuation at 1.75 Channels: " + evaluate(taps, bandEdge * 1.75) + "\tFrequency: " + (sampleRate * bandEdge * 1.75) + " [" + (bandEdge * 1.75) + "]");
mLog.debug("Attenuation at 2.00 Channels: " + evaluate(taps, bandEdge * 2.00) + "\tFrequency: " + (sampleRate * bandEdge * 2.0) + " [" + (bandEdge * 2.0) + "]");
}
//Adjust the overall gain of the filter to an objective of 1.0 times the number of channels
return normalize(extendedTaps, 1.0f * (float)channels);
return extendedTaps;
}
/**

View File

@@ -213,12 +213,14 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
switch(indexes.size())
{
case 1:
return new OneChannelOutputProcessor(mChannelCalculator.getChannelSampleRate(), indexes);
return new OneChannelOutputProcessor(mChannelCalculator.getChannelSampleRate(), indexes,
mChannelCalculator.getChannelCount());
case 2:
try
{
float[] filter = getOutputProcessorFilter(2);
return new TwoChannelOutputProcessor(mChannelCalculator.getChannelSampleRate(), indexes, filter);
return new TwoChannelOutputProcessor(mChannelCalculator.getChannelSampleRate(), indexes, filter,
mChannelCalculator.getChannelCount());
}
catch(FilterDesignException fde)
{
@@ -504,8 +506,8 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
if(taps == null)
{
taps = FilterFactory.getSincM2Synthesizer(mChannelCalculator.getChannelBandwidth(), channels,
POLYPHASE_SYNTHESIZER_TAPS_PER_CHANNEL);
taps = FilterFactory.getSincM2Synthesizer(mChannelCalculator.getChannelSampleRate(),
mChannelCalculator.getChannelBandwidth(), channels, POLYPHASE_SYNTHESIZER_TAPS_PER_CHANNEL);
mOutputProcessorFilters.put(channels, taps);
}

View File

@@ -42,6 +42,7 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
private int mInputChannelCount;
private IOscillator mFrequencyCorrectionMixer;
private boolean mFrequencyCorrectionEnabled;
private double mGain = 1.0;
/**
* Base class for polyphase channelizer output channel processing. Provides built-in frequency translation
@@ -51,9 +52,10 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
* @param sampleRate of the output channel. This is used to match the oscillator's sample rate to the output
* channel sample rate for frequency translation/correction.
*/
public ChannelOutputProcessor(int inputChannelCount, double sampleRate)
public ChannelOutputProcessor(int inputChannelCount, double sampleRate, double gain)
{
mInputChannelCount = inputChannelCount;
mGain = gain;
//TODO: swap this out and use the LowPhaseNoiseOscillator
mFrequencyCorrectionMixer = new Oscillator(0, sampleRate);
@@ -62,6 +64,11 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
mChannelResultsQueue = new OverflowableReusableBufferTransferQueue<>((int)(sampleRate * 3), (int)(sampleRate * 0.5));
}
protected double getGain()
{
return mGain;
}
@Override
public int getPolyphaseChannelIndexCount()
{

View File

@@ -38,10 +38,11 @@ public class OneChannelOutputProcessor extends ChannelOutputProcessor
*
* @param sampleRate of the output sample stream.
* @param channelIndexes containing a single channel index.
* @param gain value to apply. Typically this is the same as the channelizer's channel count.
*/
public OneChannelOutputProcessor(double sampleRate, List<Integer> channelIndexes)
public OneChannelOutputProcessor(double sampleRate, List<Integer> channelIndexes, double gain)
{
super(1, sampleRate);
super(1, sampleRate, gain);
setPolyphaseChannelIndices(channelIndexes);
}
@@ -91,6 +92,8 @@ public class OneChannelOutputProcessor extends ChannelOutputProcessor
getFrequencyCorrectionMixer().mixComplex(channelBuffer.getSamples());
}
channelBuffer.applyGain(getGain());
reusableComplexBufferAssembler.receive(channelBuffer);
}
catch(IllegalArgumentException iae)

View File

@@ -49,12 +49,13 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
*
* @param sampleRate of the output sample stream.
* @param channelIndexes containing two channel indices.
* @param gain to apply to output. Typically this is equal to the channelizer's channel count.
*/
public TwoChannelOutputProcessor(double sampleRate, List<Integer> channelIndexes, float[] filter)
public TwoChannelOutputProcessor(double sampleRate, List<Integer> channelIndexes, float[] filter, double gain)
{
//Set the frequency correction oscillator to 2 x output sample rate since we'll be correcting the frequency
//after synthesizing both input channels
super(2, sampleRate);
super(2, sampleRate, gain);
setPolyphaseChannelIndices(channelIndexes);
setSynthesisFilter(filter);
@@ -141,6 +142,8 @@ public class TwoChannelOutputProcessor extends ChannelOutputProcessor
ReusableComplexBuffer lowPassFiltered = mLowPassFilter.filter(synthesized);
lowPassFiltered.applyGain(getGain());
reusableComplexBufferAssembler.receive(lowPassFiltered);
buffer.decrementUserCount();

View File

@@ -1,7 +1,7 @@
package io.github.dsheirer.dsp.filter.design;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
import io.github.dsheirer.dsp.filter.fir.remez.RemezFIRFilterDesigner;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
@@ -81,28 +81,39 @@ public class FilterViewer extends Application
// catch(FilterDesignException fde)
// {
// mLog.error("Error");
// }
// try
// {
// RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
//
// if(designer.isValid())
// {
// taps = designer.getImpulseResponse();
// }
// }
// catch(FilterDesignException fde)
// {
// mLog.error("Filter design error", fde);
// }
//
// if(taps == null)
// {
// throw new IllegalStateException("Couldn't design filter");
// }
try
{
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
// taps = FilterFactory.getSincM2Synthesizer(0.25, 2, 9);
// taps = FilterFactory.getSincM2Channelizer(12500.0, 2, 9, true);
taps = FilterFactory.getSincM2Synthesizer( 25000.0, 12500.0, 2, 9);
if(designer.isValid())
{
taps = designer.getImpulseResponse();
}
}
catch(FilterDesignException fde)
catch(FilterDesignException e)
{
mLog.error("Filter design error", fde);
e.printStackTrace();
}
if(taps == null)
{
throw new IllegalStateException("Couldn't design filter");
}
return taps;
}
}

View File

@@ -281,7 +281,7 @@ public class SynthesizerViewer extends JFrame
{
try
{
float[] taps = FilterFactory.getSincM2Synthesizer(12500.0, 2, 12);
float[] taps = FilterFactory.getSincM2Synthesizer( 25000.0, 12500.0, 2, 12);
mSynthesizer = new TwoChannelSynthesizerM2(taps);
}
catch(FilterDesignException fde)

View File

@@ -56,4 +56,17 @@ public class ReusableComplexBuffer extends ReusableFloatBuffer
{
return getSamples().length / 2;
}
/**
* Applies the gain value to the samples contained in this buffer
*/
public void applyGain(double gain)
{
float[] samples = getSamples();
for(int x = 0; x < samples.length; x++)
{
samples[x] *= gain;
}
}
}

View File

@@ -416,14 +416,17 @@ public class USBTransferProcessor implements TransferCallback
while(transfer != null)
{
if(mRunning.get() && mComplexBufferListener != null)
if(mRunning.get())
{
ByteBuffer nativeBuffer = transfer.buffer();
ReusableComplexBuffer reusableComplexBuffer =
mNativeBufferConverter.convert(nativeBuffer, transfer.actualLength());
mComplexBufferListener.receive(reusableComplexBuffer);
if(mComplexBufferListener != null)
{
mComplexBufferListener.receive(reusableComplexBuffer);
}
}
transfer.buffer().rewind();