From afae1654d500ded6933d467dd1cdcb14776a441b Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 1 Apr 2017 15:10:02 -0400 Subject: [PATCH] WIP --- .../filter/channelizer/ChannelizerViewer.java | 8 +- ....java => ComplexPolyphaseChannelizer.java} | 13 +- .../channelizer/PolyphaseChannelizer.java | 224 ------------------ 3 files changed, 12 insertions(+), 233 deletions(-) rename src/dsp/filter/channelizer/{PolyphaseChannelizer2.java => ComplexPolyphaseChannelizer.java} (92%) delete mode 100644 src/dsp/filter/channelizer/PolyphaseChannelizer.java diff --git a/src/dsp/filter/channelizer/ChannelizerViewer.java b/src/dsp/filter/channelizer/ChannelizerViewer.java index 6d726a54..7164e57b 100644 --- a/src/dsp/filter/channelizer/ChannelizerViewer.java +++ b/src/dsp/filter/channelizer/ChannelizerViewer.java @@ -208,7 +208,7 @@ public class ChannelizerViewer extends JFrame public class ChannelArrayPanel extends JPanel implements Listener { - private PolyphaseChannelizer2 mPolyphaseChannelizer; + private ComplexPolyphaseChannelizer mPolyphaseChannelizer; private ChannelDistributor mChannelDistributor; public ChannelArrayPanel(float[] taps) @@ -219,7 +219,7 @@ public class ChannelizerViewer extends JFrame bufferSize++; } - mPolyphaseChannelizer = new PolyphaseChannelizer2(taps, mChannelCount); + mPolyphaseChannelizer = new ComplexPolyphaseChannelizer(taps, mChannelCount, 1); mChannelDistributor = new ChannelDistributor(bufferSize, mChannelCount); mPolyphaseChannelizer.setChannelDistributor(mChannelDistributor); @@ -296,8 +296,8 @@ public class ChannelizerViewer extends JFrame public static void main(String[] args) { - int channelCount = 100; - int channelsPerRow = 25; + int channelCount = 4; + int channelsPerRow = 4; final ChannelizerViewer frame = new ChannelizerViewer(channelCount, channelsPerRow); diff --git a/src/dsp/filter/channelizer/PolyphaseChannelizer2.java b/src/dsp/filter/channelizer/ComplexPolyphaseChannelizer.java similarity index 92% rename from src/dsp/filter/channelizer/PolyphaseChannelizer2.java rename to src/dsp/filter/channelizer/ComplexPolyphaseChannelizer.java index 5fd700c2..117b0382 100644 --- a/src/dsp/filter/channelizer/PolyphaseChannelizer2.java +++ b/src/dsp/filter/channelizer/ComplexPolyphaseChannelizer.java @@ -30,9 +30,9 @@ import sample.complex.ComplexBuffer; import java.text.DecimalFormat; -public class PolyphaseChannelizer2 implements Listener +public class ComplexPolyphaseChannelizer implements Listener { - private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelizer2.class); + private final static Logger mLog = LoggerFactory.getLogger(ComplexPolyphaseChannelizer.class); private RealFIRFilter[] mInphaseFilters; private RealFIRFilter[] mQuadratureFilters; @@ -57,9 +57,12 @@ public class PolyphaseChannelizer2 implements Listener * @param channels - number of filters/channels to output. Since this filter bank oversamples each filter * output, this number must be even (divisible by the oversample rate). */ - public PolyphaseChannelizer2(float[] taps, int channels) + public ComplexPolyphaseChannelizer(float[] taps, int channels, int oversample) { - assert(channels % 2 == 0); + if(oversample > 1 && channels % 2 != 0) + { + throw new IllegalArgumentException("Channel count must be a multiple of 2 when oversampling"); + } mChannelCount = channels; @@ -184,7 +187,7 @@ public class PolyphaseChannelizer2 implements Listener mLog.debug(sb.toString()); - PolyphaseChannelizer2 channelizer = new PolyphaseChannelizer2(taps, 8); + ComplexPolyphaseChannelizer channelizer = new ComplexPolyphaseChannelizer(taps, 8, 1); Oscillator oscillator = new Oscillator(channelCenter, 2 * sampleRate); diff --git a/src/dsp/filter/channelizer/PolyphaseChannelizer.java b/src/dsp/filter/channelizer/PolyphaseChannelizer.java deleted file mode 100644 index 2390cb00..00000000 --- a/src/dsp/filter/channelizer/PolyphaseChannelizer.java +++ /dev/null @@ -1,224 +0,0 @@ -/******************************************************************************* - * sdrtrunk - * Copyright (C) 2014-2017 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 - * - ******************************************************************************/ -package dsp.filter.channelizer; - -import dsp.filter.FilterFactory; -import dsp.filter.design.FilterDesignException; -import dsp.filter.fir.FIRFilterSpecification; -import dsp.filter.fir.real.RealFIRFilter; -import dsp.filter.fir.remez.RemezFIRFilterDesigner; -import dsp.mixer.Oscillator; -import org.jtransforms.fft.FloatFFT_1D; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import sample.Listener; -import sample.complex.ComplexBuffer; - -import java.text.DecimalFormat; - -public class PolyphaseChannelizer implements Listener -{ - private final static Logger mLog = LoggerFactory.getLogger(PolyphaseChannelizer.class); - - private RealFIRFilter[] mFilters; - private int mFilterPointer = 0; - private int mChannelCount; - private int mBlockSize; - private float[] mFilteredSamples; - private boolean mToggle = false; - private FloatFFT_1D mFFT; - private ChannelDistributor mChannelDistributor; - - private DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0000"); - - /** - * Creates a polyphase filter bank that divides the input frequency band into evenly spaced channels that - * are oversampled by 2x for output. - * - * @param taps of a low-pass filter designed for the inbound sample rate with a cutoff frequency - * equal to the channel bandwidth (sample rate / filters). If you need to synthesize (combine two or more - * filte outputs) a new bandwidth signal from the outputs of this filter, then the filter should be designed - * as a nyquist filter with -6 dB attenuation at the channel bandwidth cutoff frequency - * - * @param channels - number of filters/channels to output. Since this filter bank oversamples each filter - * output, this number must be even (divisible by the oversample rate). - */ - public PolyphaseChannelizer(float[] taps, int channels) - { - assert(channels % 2 == 0); - - mChannelCount = channels; - - initFilters(taps); - } - - public void filter(float inphase, float quadrature) - { - int iIndex = 2 * mFilterPointer; - int qIndex = iIndex + 1; - - mFilteredSamples[iIndex] = mFilters[iIndex].filter(inphase); - mFilteredSamples[qIndex] = mFilters[qIndex].filter(quadrature); - - if(mFilterPointer == 0) - { - calculate(); - mFilterPointer = mChannelCount - 1; - mToggle = !mToggle; - } - else if(mFilterPointer == mBlockSize) - { - calculate(); - mFilterPointer--; - } - else - { - mFilterPointer--; - } - } - - @Override - public void receive(ComplexBuffer complexBuffer) - { - float[] samples = complexBuffer.getSamples(); - - for(int x = 0; x < samples.length; x += 2) - { - filter(samples[x], samples[x + 1]); - } - } - - private void calculate() - { - float[] samples = new float[mFilters.length]; - - if(mToggle) - { - System.arraycopy(mFilteredSamples, 0, samples, mChannelCount, mChannelCount); - System.arraycopy(mFilteredSamples, mChannelCount, samples, 0, mChannelCount); - } - else - { - System.arraycopy(mFilteredSamples, 0, samples, 0, mFilteredSamples.length); - } - - //FFT is executed in-place where the output overwrites the input - mFFT.complexForward(samples); - - dispatch(samples); - } - - private void dispatch(float[] channels) - { - if(mChannelDistributor != null) - { - mChannelDistributor.receive(channels); - } - } - - public void setChannelDistributor(ChannelDistributor channelDistributor) - { - mChannelDistributor = channelDistributor; - } - - private double magnitude(float real, float imaginary, int fftSize) - { - return Math.sqrt(Math.pow(real, 2.0) + Math.pow(imaginary, 2.0)); - } - - /** - * Distributes the filter taps to each of the polyphase filters - * - * @param taps - */ - private void initFilters(float[] taps) - { - int tapCount = (int)Math.ceil((double)taps.length / (double)mChannelCount); - - float[][] coefficients = new float[mChannelCount][tapCount]; - - for(int tap = 0; tap < tapCount; tap++) - { - for(int filter = 0; filter < mChannelCount; filter++) - { - int index = tap * mChannelCount + filter; - - if(index < taps.length) - { - coefficients[filter][tap] = taps[index]; - } - } - } - - mFilters = new RealFIRFilter[mChannelCount * 2]; - - for(int filter = 0; filter < mChannelCount; filter++) - { - //Inphase filter - mFilters[2 * filter] = new RealFIRFilter(coefficients[filter], 1.0f); - - //Quadrature filter - mFilters[2 * filter + 1] = new RealFIRFilter(coefficients[filter], 1.0f); - } - - mFilteredSamples = new float[mFilters.length]; - mFFT = new FloatFFT_1D(mChannelCount); - mBlockSize = mChannelCount / 2; - mFilterPointer = mChannelCount -1; - } - - public static void main(String[] args) - { - mLog.debug("Starting ..."); - - int symbolRate = 4800; - int samplesPerSymbol = 2; - int symbolCount = 4; - int channels = 10; - int channelBandwidth = 12500; - int sampleRate = channels * channelBandwidth; - - //Alpha is the residual channel bandwidth left over from the symbol rate and samples per symbol - float alpha = ((float)channelBandwidth / (float)(symbolRate * samplesPerSymbol)) - 1.0f; - - float[] taps = FilterFactory.getRootRaisedCosine(samplesPerSymbol * channels, symbolCount, alpha); - - int channelCenter = (int)(12500 * 1.5); - - StringBuilder sb = new StringBuilder(); - sb.append("\nPolyphase Channelizer\n"); - sb.append("Sample Rate:" + sampleRate + " Channels:" + channels + " Channel Rate:" + channelBandwidth + "\n"); - sb.append("Alpha: " + alpha + " Tap Count:" + taps.length + "\n"); - sb.append("Channel:" + channelCenter); - - mLog.debug(sb.toString()); - - PolyphaseChannelizer channelizer = new PolyphaseChannelizer(taps, 8); - - Oscillator oscillator = new Oscillator(channelCenter, 2 * sampleRate); - - for(int x = 0; x < 2000; x++) - { - channelizer.filter(oscillator.getComplex().inphase(), oscillator.getComplex().quadrature()); - oscillator.rotate(); - } - - mLog.debug("Finished!"); - } -}