pico-usdx-bandscope/pico_uSDX_RX_test.ino

182 wiersze
6.2 KiB
C++

//2023_5_11 JR3XNW
//pico RX uSDX Filters for each mode + AGC.
const int speakerPin = 14; //Audio output GP14 pico 19-pin
const int inputPinI = 26; //I Signal ADC0 pico31 pin
const int inputPinQ = 27; //Q signal ADC1 pico332 pin
const int sampleRate = 8000; //sample rate
const int pwmFrequency = 30000; //PWM20000
const int pushSwitchPin = 15; //Reception mode change push switch (LSB→USB→CW→AM)
const float targetAmplitude = 0.5;//0.5-0.8
const int numTaps = 31; //Number of filter taps
const float hilbertCoeffs[numTaps] = {
-0.001328193331496, 0.000000000000000, -0.002284533986424,
0.000000000000000, -0.003313586555888, 0.000000000000000,
-0.004387527896369, 0.000000000000000, -0.005470862958678,
0.000000000000000, -0.006500296593254, 0.000000000000000,
-0.007388063473212, 0.000000000000000, -0.008023180743934,
0.000000000000000, -0.008266448739536, 0.000000000000000,
-0.007942155320414, 0.000000000000000, -0.006729329308188,
0.000000000000000, -0.004233803027843, 0.000000000000000,
0.000000000000000, -0.005656339687371, 0.000000000000000,
-0.016018448245468, 0.000000000000000, -0.031105779790221,
0.000000000000000
};
const float lsbFilterCoeffs[numTaps] = {
-1.57196597e-03, -1.45104171e-03, 1.12478657e-03, 4.46246491e-03,
2.57714059e-03, -6.99319701e-03, -1.30293770e-02, 7.20713963e-18,
2.47619628e-02, 2.56472800e-02, -1.88013680e-02, -6.76180323e-02,
-3.71204042e-02, 1.08307805e-01, 2.91780827e-01, 3.75846238e-01,
2.91780827e-01, 1.08307805e-01, -3.71204042e-02, -6.76180323e-02,
-1.88013680e-02, 2.56472800e-02, 2.47619628e-02, 7.20713963e-18,
-1.30293770e-02, -6.99319701e-03, 2.57714059e-03, 4.46246491e-03,
1.12478657e-03, -1.45104171e-03, -1.57196597e-03
};
const float usbFilterCoeffs[numTaps] = {
-1.57196597e-03, -1.45104171e-03, 1.12478657e-03, 4.46246491e-03,
2.57714059e-03, -6.99319701e-03, -1.30293770e-02, 7.20713963e-18,
2.47619628e-02, 2.56472800e-02, -1.88013680e-02, -6.76180323e-02,
-3.71204042e-02, 1.08307805e-01, 2.91780827e-01, 3.75846238e-01,
2.91780827e-01, 1.08307805e-01, -3.71204042e-02, -6.76180323e-02,
-1.88013680e-02, 2.56472800e-02, 2.47619628e-02, 7.20713963e-18,
-1.30293770e-02, -6.99319701e-03, 2.57714059e-03, 4.46246491e-03,
1.12478657e-03, -1.45104171e-03, -1.57196597e-03
};
const float cwFilterCoeffs[numTaps] = {
-6.47960382e-04, -1.44397905e-03, -2.70225797e-03, -4.44074475e-03,
-6.19148454e-03, -6.95915901e-03, -5.37067609e-03, 2.39068677e-18,
1.02068182e-02, 2.55224470e-02, 4.51695882e-02, 6.72889150e-02,
8.91803923e-02, 1.07780639e-01, 1.20271316e-01, 1.24672294e-01,
1.20271316e-01, 1.07780639e-01, 8.91803923e-02, 6.72889150e-02,
4.51695882e-02, 2.55224470e-02, 1.02068182e-02, 2.39068677e-18,
-5.37067609e-03, -6.95915901e-03, -6.19148454e-03, -4.44074475e-03,
-2.70225797e-03, -1.44397905e-03, -6.47960382e-04
};
const float amFilterCoeffs[numTaps] = {
-1.20126129e-03, 2.04889442e-03, -2.07510535e-03, 4.91080693e-18,
4.75453597e-03, -9.87450755e-03, 9.95675888e-03, -1.43918829e-17,
-1.89225390e-02, 3.62143751e-02, -3.46864198e-02, 2.48038628e-17,
6.84829915e-02, -1.52932377e-01, 2.22972391e-01, 7.50524525e-01,
2.22972391e-01, -1.52932377e-01, 6.84829915e-02, 2.48038628e-17,
-3.46864198e-02, 3.62143751e-02, -1.89225390e-02, -1.43918829e-17,
9.95675888e-03, -9.87450755e-03, 4.75453597e-03, 4.91080693e-18,
-2.07510535e-03, 2.04889442e-03, -1.20126129e-03
};
float applyFilter(float input, const float *coeffs, float *buffer) {
// Shift elements in the buffer
for (int i = numTaps - 1; i > 0; i--) {
buffer[i] = buffer[i - 1];
}
buffer[0] = input;
float output = 0;
for (int i = 0; i < numTaps; i++) {
output += buffer[i] * coeffs[i];
}
return output;
}
float buffer[numTaps] = {0};
float agcGain = 1.0;
enum DemodulationMode { LSB, USB, CW, AM };
DemodulationMode currentMode = LSB;
void setup() {
pinMode(25, OUTPUT); // pico built-in LED
pinMode(speakerPin, OUTPUT);
pinMode(inputPinI, INPUT);
pinMode(inputPinQ, INPUT);
pinMode(pushSwitchPin, INPUT_PULLUP);
analogReadResolution(12);
analogWriteResolution(8);
analogWriteFreq(pwmFrequency);
}
float applyHilbertTransform(float input, const float *coeffs, float *buffer) {
memmove(&buffer[1], &buffer[0], (numTaps - 1) * sizeof(float));
buffer[0] = input;
float output = 0;
for (int i = 0; i < numTaps; i++) {
output += buffer[i] * coeffs[i];
}
return output;
}
float applyAGC(float input) {
float error = targetAmplitude - abs(input);
agcGain += 0.001 * error;
if (agcGain < 0.1) {
agcGain = 0.1;
}
return input * agcGain;
}
float applyLowPassFilter(float input, const float *coeffs, float *buffer) {
memmove(&buffer[1], &buffer[0], (numTaps - 1) * sizeof(float));
buffer[0] = input;
float output = 0;
for (int i = 0; i < numTaps; i++) {
output += buffer[i] * coeffs[i];
}
return output;
}
void loop() {
digitalWrite(25, HIGH); // Built-in LED lights up during sampling
float inputI, inputQ;
float output = 0.0; // initialize output
inputI = analogRead(inputPinI);
inputQ = analogRead(inputPinQ);
inputI = (inputI / 2047.5) - 1.0;
inputQ = (inputQ / 2047.5) - 1.0;
if (digitalRead(pushSwitchPin) == LOW) {
delay(50); // Debounce delay
currentMode = static_cast<DemodulationMode>((currentMode + 1) % 4);
while (digitalRead(pushSwitchPin) == LOW); // Wait for switch release
delay(50); // Debounce delay
}
// Apply the Hilbert Transform
float hilbertOutput = applyFilter(output, hilbertCoeffs, buffer);
switch (currentMode) {
case LSB:
output = inputI - inputQ;
applyFilter(output, lsbFilterCoeffs, buffer);
break;
case USB:
output = inputI + inputQ;
applyFilter(output, usbFilterCoeffs, buffer);
break;
case CW:
output = inputI * inputQ;
applyFilter(output, cwFilterCoeffs, buffer);
break;
case AM:
output = sqrt(inputI * inputI + inputQ * inputQ);
applyFilter(output, amFilterCoeffs, buffer);
break;
}
// Apply AGC
float agcOutput = applyAGC(hilbertOutput);
uint8_t pwmOutput = (uint8_t)((agcOutput + 1.0) * 127.5);
analogWrite(speakerPin, pwmOutput);
delayMicroseconds(1000000 / sampleRate);
}