|
|
|
@ -1,34 +1,34 @@ |
|
|
|
|
/*
|
|
|
|
|
* RadioIQMixer_F32.h |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* 8 April 2020 Bob Larkin |
|
|
|
|
* With much credit to: |
|
|
|
|
* Chip Audette (OpenAudio) Feb 2017 |
|
|
|
|
* and of course, to PJRC for the Teensy and Teensy Audio Library |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* This quadrature mixer block is suitable for both transmit and receive. |
|
|
|
|
* |
|
|
|
|
* A basic building block is a pair of mixers with the |
|
|
|
|
* LO going to the mixers at the same frequency, but differing in phase
|
|
|
|
|
* LO going to the mixers at the same frequency, but differing in phase |
|
|
|
|
* by 90 degrees. This provides two outputs I and Q that are offset in |
|
|
|
|
* frequency but also 90 degrees apart in phase. The LO are included |
|
|
|
|
* in the block, but there are no post-mixing filters. |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* The frequency is set by .frequency(float freq_Hz) |
|
|
|
|
* There is provision for varying |
|
|
|
|
* the phase between the sine and cosine oscillators. Technically this is no |
|
|
|
|
* longer sin and cos, but that is what real hardware needs. |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* The amplitudeC(a) allows balancing of I and Q channels. |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* The output levels are 0.5 times the input level. |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* Status: Tested in doSimple==1 |
|
|
|
|
* Tested in FineFreqShift_OA.ino, T3.6 and T4.0
|
|
|
|
|
*
|
|
|
|
|
* Tested in FineFreqShift_OA.ino, T3.6 and T4.0 |
|
|
|
|
* |
|
|
|
|
* Inputs: 0 is signal |
|
|
|
|
* Outputs: 0 is I 1 is Q |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* Functions, available during operation: |
|
|
|
|
* void frequency(float32_t fr) Sets LO frequency Hz |
|
|
|
|
* void iqmPhaseS(float32_t ps) Sets Phase of Sine in radians |
|
|
|
@ -37,13 +37,14 @@ |
|
|
|
|
* void useSimple(bool s) Faster if 1, but no phase/amplitude adjustment |
|
|
|
|
* void setSampleRate_Hz(float32_t fs_Hz) Allows dynamic sample rate change for this function |
|
|
|
|
* void useTwoChannel(bool 2Ch) Uses 2 input cannels, I & Q, if true. Apr 2021 |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* Time: T3.6 For an update of a 128 sample block, doSimple=1, 46 microseconds |
|
|
|
|
* T4.0 For an update of a 128 sample block, doSimple=1, 20 microseconds |
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
* Rev Apr2021 Allowed for 2-channel I-Q input. Defaults to 1 Channel. "real." |
|
|
|
|
* Rev 30Jan23 Corrected setSampleRate_Hz(sr) to do so! RSL |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _radioIQMixer_f32_h |
|
|
|
|
#define _radioIQMixer_f32_h |
|
|
|
|
|
|
|
|
@ -83,7 +84,7 @@ public: |
|
|
|
|
doSimple = false; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// phaseS_C_r is the number of radians that the cosine output leads the
|
|
|
|
|
// sine output. The default is M_PI_2 = pi/2 = 1.57079633 radians,
|
|
|
|
|
// corresponding to 90.00 degrees cosine leading sine.
|
|
|
|
@ -110,7 +111,7 @@ public: |
|
|
|
|
// complex input. With twoChannel===true channel 1 is Q.
|
|
|
|
|
void useTwoChannel(bool _2Ch) { |
|
|
|
|
twoChannel = _2Ch; |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Speed up calculations by setting phaseS_C=90deg, amplitude=1
|
|
|
|
|
void useSimple(bool s) { |
|
|
|
@ -120,19 +121,20 @@ public: |
|
|
|
|
amplitude_pk = 1.0f; |
|
|
|
|
} |
|
|
|
|
return; |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void setSampleRate_Hz(float32_t fs_Hz) { |
|
|
|
|
sample_rate_Hz = fs_Hz; // Added 30Jan23 RSL
|
|
|
|
|
// Check freq range
|
|
|
|
|
if (freq > sample_rate_Hz/2.0f) freq = sample_rate_Hz/2.f; |
|
|
|
|
// update phase increment for new frequency
|
|
|
|
|
phaseIncrement = 512.0f * freq / fs_Hz; |
|
|
|
|
phaseIncrement = 512.0f * freq / sample_rate_Hz; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void showError(uint16_t e) { // Serial.print errors in update()
|
|
|
|
|
errorPrintIQM = e; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
virtual void update(void); |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|