diff --git a/src/dsp/filter/channelizer/output/ChannelOutputProcessor.java b/src/dsp/filter/channelizer/output/ChannelOutputProcessor.java
new file mode 100644
index 00000000..a4c84694
--- /dev/null
+++ b/src/dsp/filter/channelizer/output/ChannelOutputProcessor.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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.output;
+
+import dsp.mixer.Oscillator;
+import sample.complex.Complex;
+
+public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputProcessor
+{
+ private Oscillator mFrequencyCorrectionMixer;
+
+ /**
+ * Base class for polyphase channelizer output channel processing. Provides built-in frequency translation
+ * oscillator support to apply frequency correction to the channel sample stream as requested by sample consumer.
+ *
+ * @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 sampleRate)
+ {
+ mFrequencyCorrectionMixer = new Oscillator(0, sampleRate);
+ }
+
+ /**
+ * Provides frequency correction of the inphase component or simply returns the inphase argument value when no
+ * frequency correction value has been specified.
+ *
+ * @param inphase value of the sample to translate/correct
+ * @param quadrature value of the sample to translate/correct
+ * @return corrected inphase value
+ */
+ protected float getFrequencyCorrectedInphase(float inphase, float quadrature)
+ {
+ //Only apply frequency correction if the oscillator is set to a non-zero frequency offset
+ if(mFrequencyCorrectionMixer.enabled())
+ {
+ return Complex.multiplyInphase(inphase, quadrature, mFrequencyCorrectionMixer.inphase(),
+ mFrequencyCorrectionMixer.quadrature());
+ }
+ else
+ {
+ return inphase;
+ }
+ }
+
+ /**
+ * Provides frequency correction of the quadrature component or simply returns the quadrature argument value when no
+ * frequency correction value has been applied,
+ *
+ * @param inphase value of the sample to translate/correct
+ * @param quadrature value of the sample to translate/correct
+ * @return translated inphase value
+ */
+ protected float getFrequencyCorrectedQuadrature(float inphase, float quadrature)
+ {
+ //Only apply frequency correction if the oscillator is set to a non-zero frequency offset
+ if(mFrequencyCorrectionMixer.enabled())
+ {
+ return Complex.multiplyQuadrature(inphase, quadrature, mFrequencyCorrectionMixer.inphase(),
+ mFrequencyCorrectionMixer.quadrature());
+ }
+ else
+ {
+ return quadrature;
+ }
+ }
+
+ /**
+ * Specifies a frequency correction value to be applied to channel samples output from this polyphase channelizer
+ * output processor.
+ *
+ * @param frequencyCorrection offset value
+ */
+ @Override
+ public void setFrequencyCorrection(long frequencyCorrection)
+ {
+ mFrequencyCorrectionMixer.setFrequency(frequencyCorrection);
+ }
+
+}
diff --git a/src/dsp/filter/channelizer/output/ChannelOutputProcessorFactory.java b/src/dsp/filter/channelizer/output/ChannelOutputProcessorFactory.java
index 323fd8a2..4dc141c2 100644
--- a/src/dsp/filter/channelizer/output/ChannelOutputProcessorFactory.java
+++ b/src/dsp/filter/channelizer/output/ChannelOutputProcessorFactory.java
@@ -21,7 +21,7 @@ package dsp.filter.channelizer.output;
public class ChannelOutputProcessorFactory
{
/**
- * Factory for obtaining polyphase channelizer results processors to perform any post-processing
+ * Factory for obtaining polyphase channelizer output processors to perform any post-processing
* that may be required to perform frequency translation and/or resampling of channel results.
*/
public static IPolyphaseChannelOutputProcessor getProcessor(int sampleRate, long frequency)
diff --git a/src/dsp/filter/channelizer/output/DoubleChannelOutputProcessor.java b/src/dsp/filter/channelizer/output/DoubleChannelOutputProcessor.java
new file mode 100644
index 00000000..40df765a
--- /dev/null
+++ b/src/dsp/filter/channelizer/output/DoubleChannelOutputProcessor.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.output;
+
+import sample.complex.IComplexSampleListener;
+
+import java.util.List;
+
+public class DoubleChannelOutputProcessor extends ChannelOutputProcessor
+{
+ private int mChannelOffset1;
+ private int mChannelOffset2;
+
+ /**
+ * Processor to extract two channels from a polyphase channelizer, synthesize/recombine the channels, apply
+ * frequency translation and frequency correction, down-sample by a factor of two and output an I/Q complex sample.
+ *
+ * @param sampleRate of the output sample stream.
+ * @param channelIndexes containing two channel indices.
+ */
+ public DoubleChannelOutputProcessor(int sampleRate, List channelIndexes)
+ {
+ super(sampleRate);
+ setPolyphaseChannelIndices(channelIndexes);
+ }
+
+ /**
+ * Updates this processor to extract the two specified channel indexes.
+ *
+ * @param indexes containing a single channel index value.
+ * @throws IllegalArgumentException if the list of indexes does not contain a single channel index.
+ */
+ public void setPolyphaseChannelIndices(List indexes)
+ {
+ if(indexes.size() != 2)
+ {
+ throw new IllegalArgumentException("Double channel output processor requires two indexes to " +
+ "process - provided indexes " + indexes.toString());
+ }
+
+ //Set the channelized output results offsets to twice the channel index to account for each channel having
+ //an I/Q pair
+ mChannelOffset1 = indexes.get(0) * 2;
+ mChannelOffset2 = indexes.get(1) * 2;
+ }
+
+ /**
+ * Extract the channel from the channel results array, apply frequency translation, and deliver the
+ * extracted frequency-corrected channel I/Q sample set to the complex sample listener.
+ *
+ * @param channels to process containing an array of channel I/Q sample pairs (I0,Q0,I1,Q1...In,Qn)
+ * @param listener to receive the extracted, frequency-translated channel results
+ */
+ @Override
+ public void process(float[] channels, IComplexSampleListener listener)
+ {
+// if(channels.length < mChannelOffset + 1)
+// {
+// throw new IllegalArgumentException("Polyphase channelizer output channels array is not large enough to " +
+// "cover this single channel output processor with channel offset [" + mChannelOffset + "]");
+// }
+//
+// float i = channels[mChannelOffset];
+// float q = channels[mChannelOffset + 1];
+
+ listener.receive(getFrequencyCorrectedInphase(i, q), getFrequencyCorrectedQuadrature(i, q));
+ }
+}
diff --git a/src/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java b/src/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java
index 64f911f8..d5473ff1 100644
--- a/src/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java
+++ b/src/dsp/filter/channelizer/output/IPolyphaseChannelOutputProcessor.java
@@ -31,9 +31,10 @@ public interface IPolyphaseChannelOutputProcessor
void process(float[] channels, IComplexSampleListener listener);
/**
- * Specifies the positive or negative frequency correction that should be applied to samples extracted from
- * the polyphase channelizer output results.
- * @param frequency
+ * Specifies the frequency correction (+/-) that should be applied to samples extracted from the polyphase
+ * channelizer output results.
+ *
+ * @param frequencyCorrection correction value
*/
- void setFrequencyCorrection(long frequency);
+ void setFrequencyCorrection(long frequencyCorrection);
}
diff --git a/src/dsp/filter/channelizer/output/SingleChannelOutputProcessor.java b/src/dsp/filter/channelizer/output/SingleChannelOutputProcessor.java
index a3713158..289382a4 100644
--- a/src/dsp/filter/channelizer/output/SingleChannelOutputProcessor.java
+++ b/src/dsp/filter/channelizer/output/SingleChannelOutputProcessor.java
@@ -18,16 +18,13 @@
******************************************************************************/
package dsp.filter.channelizer.output;
-import dsp.mixer.Oscillator;
-import sample.complex.Complex;
import sample.complex.IComplexSampleListener;
import java.util.List;
-public class SingleChannelOutputProcessor implements IPolyphaseChannelOutputProcessor
+public class SingleChannelOutputProcessor extends ChannelOutputProcessor
{
private int mChannelOffset;
- private Oscillator mFrequencyCorrectionMixer;
/**
* Processor to extract a single channel from a polyphase channelizer and produce an output I/Q complex sample
@@ -38,12 +35,12 @@ public class SingleChannelOutputProcessor implements IPolyphaseChannelOutputProc
*/
public SingleChannelOutputProcessor(int sampleRate, List channelIndexes)
{
- mFrequencyCorrectionMixer = new Oscillator(0, sampleRate);
+ super(sampleRate);
setPolyphaseChannelIndices(channelIndexes);
}
/**
- * Updates this processor to extract a specified channel index.
+ * Updates this processor to extract a single, specified channel index.
* @param indexes containing a single channel index value.
* @throws IllegalArgumentException if the list of indexes does not contain a single channel index.
*/
@@ -61,8 +58,8 @@ public class SingleChannelOutputProcessor implements IPolyphaseChannelOutputProc
}
/**
- * Extracts the channel from the channel results array, applies frequency translation, and delivers the
- * extracted frequency-translated channel sample to the complex sample listener.
+ * Extract the channel from the channel results array, apply frequency translation, and deliver the
+ * extracted frequency-corrected channel I/Q sample set to the complex sample listener.
*
* @param channels to process containing an array of channel I/Q sample pairs (I0,Q0,I1,Q1...In,Qn)
* @param listener to receive the extracted, frequency-translated channel results
@@ -70,36 +67,15 @@ public class SingleChannelOutputProcessor implements IPolyphaseChannelOutputProc
@Override
public void process(float[] channels, IComplexSampleListener listener)
{
- if(channels.length >= (mChannelOffset + 1))
+ if(channels.length < mChannelOffset + 1)
{
- //Only perform frequency translation if the frequency correction mixer has a non-zero frequency value
- if(mFrequencyCorrectionMixer.isEnabled())
- {
- mFrequencyCorrectionMixer.rotate();
-
- float i = Complex.multiplyInphase(channels[mChannelOffset], channels[mChannelOffset + 1],
- mFrequencyCorrectionMixer.inphase(), mFrequencyCorrectionMixer.quadrature());
-
- float q = Complex.multiplyQuadrature(channels[mChannelOffset], channels[mChannelOffset + 1],
- mFrequencyCorrectionMixer.inphase(), mFrequencyCorrectionMixer.quadrature());
-
- listener.receive(i, q);
- }
- else
- {
- listener.receive(channels[mChannelOffset], channels[mChannelOffset + 1]);
- }
+ throw new IllegalArgumentException("Polyphase channelizer output channels array is not large enough to " +
+ "cover this single channel output processor with channel offset [" + mChannelOffset + "]");
}
- }
- /**
- * Specifies a frequency correction/translation value to be applied to channel samples output from the
- * polyphase channelizer.
- * @param frequency
- */
- @Override
- public void setFrequencyCorrection(long frequency)
- {
- mFrequencyCorrectionMixer.setFrequency(frequency);
+ float i = channels[mChannelOffset];
+ float q = channels[mChannelOffset + 1];
+
+ listener.receive(getFrequencyCorrectedInphase(i, q), getFrequencyCorrectedQuadrature(i, q));
}
}
diff --git a/src/dsp/mixer/Oscillator.java b/src/dsp/mixer/Oscillator.java
index 70383bec..865f4bcf 100644
--- a/src/dsp/mixer/Oscillator.java
+++ b/src/dsp/mixer/Oscillator.java
@@ -58,7 +58,7 @@ public class Oscillator
*
* @return true if the current frequency value is non-zero.
*/
- public boolean isEnabled()
+ public boolean enabled()
{
return mEnabled;
}