From 424526d259d61a947ba7fa1bfa2a2c40431953fa Mon Sep 17 00:00:00 2001 From: Christopher Horner Date: Mon, 30 Jan 2017 19:07:27 -0800 Subject: [PATCH 1/3] Speed up acquisition time... Removed all delay() calls, as the AD9850 DDS has microscopic settling time for frequency changes and serial communications. Changes reduce acquisition time for a 1-30 MHz scan from 11.74 seconds to 1.65 seconds. --- Firmware/standard_firmware/standard_firmware.ino | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Firmware/standard_firmware/standard_firmware.ino b/Firmware/standard_firmware/standard_firmware.ino index 3c5589c..d79e81d 100644 --- a/Firmware/standard_firmware/standard_firmware.ino +++ b/Firmware/standard_firmware/standard_firmware.ino @@ -255,12 +255,9 @@ void Perform_sweep() { // Reset the DDS digitalWrite(RESET, HIGH); - delay(1); digitalWrite(RESET, LOW); - delay(10); SetDDSFreq(Fstart); - delay(100); - + // REV_nosig = analogRead(A0); // FWD_nosig = analogRead(A1); // if(mode==0){ @@ -284,7 +281,6 @@ void Perform_sweep() { if (digitalRead(BAND) == LOW) { mode_pressed = 1; } - delay(10); // Read the forawrd and reverse voltages REV = analogRead(A0); FWD = analogRead(A1); @@ -326,7 +322,6 @@ void Perform_sweep() { lcd.setCursor(15, 1); lcd.print("."); - delay(100); lcd.setCursor(15, 1); lcd.print(" "); lcd.setCursor(0, 1); @@ -336,7 +331,6 @@ void Perform_sweep() { lcd.print(":1 "); digitalWrite(13, HIGH); - //delay(10); digitalWrite(13, LOW); } From eb3c784801b34403ec65007b34a45e202e9ca71b Mon Sep 17 00:00:00 2001 From: Christopher Horner Date: Wed, 1 Feb 2017 20:08:38 -0800 Subject: [PATCH 2/3] Compensation/calibration routines - added automated calibration routines to setup(). Measures the FWD/REV ADC values when no input is appled to compensate for idle noise. These offsets are subtracted from the later FWD/REV reads. - added diode mismatch compensation values, empirically read at the ADC when a shorted antenna port is being drive. The ratio of measured value (REV/FWD) is used to compensate the FWD value. --- .../standard_firmware/standard_firmware.ino | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/Firmware/standard_firmware/standard_firmware.ino b/Firmware/standard_firmware/standard_firmware.ino index d79e81d..66ddd5d 100644 --- a/Firmware/standard_firmware/standard_firmware.ino +++ b/Firmware/standard_firmware/standard_firmware.ino @@ -42,6 +42,14 @@ long num_steps = 1001; // Number of steps to use in the sweep char incoming_char; // Character read from serial stream byte mode_pressed = 0; int mode = 1; +int fwdOffset = 0; +int revOffset = 0; +// Short the output, then measure FWD and REV over a sweep for these values. If not, set both equal to 1. +int fwdDiodeComp = 224; +int revDiodeComp = 211; +//Short the diode cathodes together, measure FWD and REV over a sweep for these values. If not, set both equal to 1. +int fwdGainComp = 1; +int revGainComp = 1; void setup() { // set up the LCD's number of columns and rows: @@ -68,6 +76,27 @@ void setup() { digitalWrite(RESET, HIGH); digitalWrite(RESET, LOW); + // calibrate REV/FWD offset +// lcd.clear(); +// lcd.setCursor(0, 0); +// lcd.print("Calibrating..."); + + SetDDSFreq(1L); + delay(1); + for (int i = 0; i < 1000; i++) { + fwdOffset += analogRead(A1); + revOffset += analogRead(A0); + } + fwdOffset = fwdOffset / 1000; + revOffset = revOffset / 1000; + +// lcd.setCursor(0, 1); +// lcd.print("FWD: "); +// lcd.print(fwdOffset); +// lcd.print(" REV: "); +// lcd.print(revOffset); +// delay(2000); + //Initialise the incoming serial number to zero serial_input_number = 0; lcd.clear(); @@ -147,7 +176,7 @@ void loop() { } num_steps = 1000; - switch(mode){ + switch (mode) { case 1: // Full sweep 1-30 MHz lcd.clear(); @@ -257,19 +286,8 @@ void Perform_sweep() { digitalWrite(RESET, HIGH); digitalWrite(RESET, LOW); SetDDSFreq(Fstart); + delay(1); -// REV_nosig = analogRead(A0); -// FWD_nosig = analogRead(A1); -// if(mode==0){ -// Serial.print("FWD "); -// Serial.print(FWD_nosig); -// Serial.print(", REV "); -// Serial.println(REV_nosig); -// Serial.flush(); -// } - - - // Start loop for (long i = 0; i <= num_steps; i++) { // Calculate current frequency @@ -277,15 +295,20 @@ void Perform_sweep() { // Set DDS to current frequency SetDDSFreq(current_freq); + delay(1); // Wait a little for settling if (digitalRead(BAND) == LOW) { mode_pressed = 1; } - // Read the forawrd and reverse voltages - REV = analogRead(A0); - FWD = analogRead(A1); - if (REV >= FWD) { + // Read the reverse and foward voltages and calibrate them + REV = (analogRead(A0) - revOffset); + FWD = (analogRead(A1) - fwdOffset); + + FWD = (revDiodeComp * FWD) / fwdDiodeComp; + REV = (fwdGainComp * REV) / revGainComp; + + if (REV >= FWD) { // To avoid a divide by zero or negative VSWR then set to max 999 VSWR = 999; } else { @@ -340,7 +363,7 @@ void SetDDSFreq(long Freq_Hz) { // Send one byte at a time for (int b = 0; b < 4; b++, f >>= 8) { -// SPI.transfer(f & 0xFF); + // SPI.transfer(f & 0xFF); send_byte(f & 0xFF); } From b4a897f9601207c4d26249f5f2c8e4a66ecedbb4 Mon Sep 17 00:00:00 2001 From: Christopher Horner Date: Thu, 2 Feb 2017 22:06:08 -0800 Subject: [PATCH 3/3] Refined compensation routines, prettified the display, and code cleanup - The two compensation ratios (Gain and Diode) turned out to be frequency dependent, requiring equations to determine the compenstation ratio during the sweep (left in the mean value and linear methods of compensation as comments). - Changed display routines to provide a more readable output with fixed sizes and scaling/ - Moved the ADC readings more stable by adding an averaging routing. - Removed the "throwaway readings" routine, as the problem seems to have solved itself. - removed unused code and variables. --- .../standard_firmware/standard_firmware.ino | 116 +++++++++--------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/Firmware/standard_firmware/standard_firmware.ino b/Firmware/standard_firmware/standard_firmware.ino index 66ddd5d..efc489c 100644 --- a/Firmware/standard_firmware/standard_firmware.ino +++ b/Firmware/standard_firmware/standard_firmware.ino @@ -5,7 +5,7 @@ // 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, +// 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. @@ -38,18 +38,21 @@ long Fstart = 1000000; // Start Frequency for sweep long Fstop = 30000000; // Stop Frequency for sweep unsigned long current_freq; // Temp variable used during sweep long serial_input_number; // Used to build number from serial stream -long num_steps = 1001; // Number of steps to use in the sweep +long num_steps = 101; // Number of steps to use in the sweep char incoming_char; // Character read from serial stream byte mode_pressed = 0; int mode = 1; -int fwdOffset = 0; -int revOffset = 0; -// Short the output, then measure FWD and REV over a sweep for these values. If not, set both equal to 1. -int fwdDiodeComp = 224; -int revDiodeComp = 211; -//Short the diode cathodes together, measure FWD and REV over a sweep for these values. If not, set both equal to 1. -int fwdGainComp = 1; -int revGainComp = 1; + +// CALIBRATION VALUES +// set AD9850 to zero output, measure FWD and REV over a long period for these values. If not, set both equal to 0. +int fwdOffset = 6; //6 compensates for idle noise on the fwd diode and amplifier +int revOffset = 4; //4 compensates for idle noise on the fwd diode and amplifier +// Short the antenna port to ground, measure FWD and REV over a sweep for this ratio (REV/FWD). If not, set equal to 1. +// see comments in PerformSweep() about alternative compensation schemes....there is a frequency dependent noise component. +double diodeComp = 0.9414309839; +// Short the diode cathodes together, measure FWD and REV over a sweep for this ratio (FWD/REV). If not, set both equal to 1. +// see comments in PerformSweep() about alternative compensation schemes....there is a frequency dependent noise component. +double gainComp = 0.995193251; void setup() { // set up the LCD's number of columns and rows: @@ -76,27 +79,6 @@ void setup() { digitalWrite(RESET, HIGH); digitalWrite(RESET, LOW); - // calibrate REV/FWD offset -// lcd.clear(); -// lcd.setCursor(0, 0); -// lcd.print("Calibrating..."); - - SetDDSFreq(1L); - delay(1); - for (int i = 0; i < 1000; i++) { - fwdOffset += analogRead(A1); - revOffset += analogRead(A0); - } - fwdOffset = fwdOffset / 1000; - revOffset = revOffset / 1000; - -// lcd.setCursor(0, 1); -// lcd.print("FWD: "); -// lcd.print(fwdOffset); -// lcd.print(" REV: "); -// lcd.print(revOffset); -// delay(2000); - //Initialise the incoming serial number to zero serial_input_number = 0; lcd.clear(); @@ -265,7 +247,6 @@ void loop() { Fstart = 28000000; Fstop = 30000000; break; - } } } @@ -273,42 +254,53 @@ void loop() { void Perform_sweep() { int FWD = 0; int REV = 0; - int REV_nosig = 0; - int FWD_nosig = 0; double VSWR; double minVSWR; long minFreq; - long Fstep = (Fstop - Fstart) / num_steps; minVSWR = 999; minFreq = Fstart; - // Reset the DDS - digitalWrite(RESET, HIGH); - digitalWrite(RESET, LOW); - SetDDSFreq(Fstart); - delay(1); - // Start loop for (long i = 0; i <= num_steps; i++) { // Calculate current frequency - current_freq = Fstart + i * Fstep; + current_freq = Fstart + i * ((Fstop - Fstart) / num_steps); // Set DDS to current frequency SetDDSFreq(current_freq); delay(1); + + //discard a few measurements + for (int j = 0; j < 19; j++) { + analogRead(A1); + analogRead(A0); + } + // Wait a little for settling if (digitalRead(BAND) == LOW) { mode_pressed = 1; } - // Read the reverse and foward voltages and calibrate them - REV = (analogRead(A0) - revOffset); - FWD = (analogRead(A1) - fwdOffset); + // Average the reverse and foward voltages and calibrate them + for (int k = 0; k < 50; k++) { + REV += (analogRead(A0) - revOffset); + FWD += (analogRead(A1) - fwdOffset); + } + FWD /= 50; + REV /= 50; + + // Mean compensation values + // FWD = diodeComp * FWD; + // REV = gainComp * REV; + + // Linear compensation equatiions + // FWD = FWD * (2e-9 * current_freq + 0.9231) ; + // REC = REV *(2e-10 * current_freq + 0.9916); - FWD = (revDiodeComp * FWD) / fwdDiodeComp; - REV = (fwdGainComp * REV) / revGainComp; + // Polynomial compensation equations + FWD = FWD * (8.9070e-17 * current_freq * current_freq - 8.1425e-10 * current_freq + 0.9832); + REV = REV * (-2.7626e-18 * current_freq * current_freq + 3.1516e-10 * current_freq + 0.9912); - if (REV >= FWD) { + if (REV >= FWD) { // To avoid a divide by zero or negative VSWR then set to max 999 VSWR = 999; } else { @@ -339,22 +331,26 @@ void Perform_sweep() { Serial.print("Freq "); Serial.print(minFreq); Serial.print(", VSWR "); - Serial.println(minVSWR); + Serial.println(minVSWR, 3); Serial.flush(); } - lcd.setCursor(15, 1); - lcd.print("."); - lcd.setCursor(15, 1); - lcd.print(" "); + // display results lcd.setCursor(0, 1); - lcd.print(minFreq); - lcd.print(","); - lcd.print(minVSWR); - lcd.print(":1 "); - - digitalWrite(13, HIGH); - digitalWrite(13, LOW); + lcd.print("F:"); + if (minFreq < 10e6) { + lcd.setCursor(3, 1); + } + else + lcd.setCursor(2, 1); + lcd.print(minFreq / 1e6, 3); + lcd.setCursor(9, 1); + lcd.print("V:"); + if (minVSWR > 1) + lcd.setCursor(11, 1); + else + lcd.setCursor(10, 1); + lcd.print(minVSWR, 3); } void SetDDSFreq(long Freq_Hz) {