Project showcase
SNA jr.

SNA jr. © GPL3+

A simple self contained Scalar Network Analyzer. It is used for testing and alignment of RF circuits, including amplifiers and filters.

  • 6,518 views
  • 2 comments
  • 17 respects

Components and supplies

About this project

I had started working on several projects involving Radio Frequency circuitry and  needed some simple test equipment to help in aligning and testing.  I had completed an antenna analyzer that used a Arduino Nano, small TFT display, and a AD9850 DDS signal generator module. After a bit of research into the different options, I decided to change what I had to make a simple Scalar Network Analyzer.  A SNA is basically a signal generator with detector that can be swept across the frequency of interest and the frequency response of the network plotted.  Most SNA circuits use some sort of a LOG amplifier detector to give a gain-loss reading in dB.  I decided to see if I could use a couple of simple diode RF detectors instead and use the Arduino to compute the dB. values.  The resolution of the Arduino ADC  would limit the range of values I could measure, but would be adequate for the projects I will be working on

I did a circuit board layout, etched and built a single sided circuit board to test the operation of the circuit.  With only a few changes to my existing scan and display routine, I was able to get usable results on testing several types of RF filters.

I  added a simple menu system using a combination of long and short presses on the rotary encoder button.  I added several different function options for the display, and added the functionality to use the system as a signal generator.  Later updates to the software provided for use with a Return Loss Bridge for checking the frequency response of antennas.  And with a simple pickup coil, provided some of the functionality of a dip-meter.

The last software option I added was a live view of the sweep response to aid in aligning filters.

More details on this project and use are in several posts on my blog: http://KV4QB.blogspot.com

Build instructions, circuit board files, Arduino sketch and required include files are available at https://www.dropbox.com/sh/16bxycnl2xg7vqi/AADcMnY9LNpBBfRuFJkzlVD-a?dl=0 

Code

SNA jr. Arduino sketchArduino
/*********************************************************************
 *
 * Simple SNA for the  HF amateur bands
 * portions of this software are covered by the GNU General Public License ,
 * BEERWARE, or other open source licenses
 * DuWayne  KV4QB
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <duwayne@kv4qb.us> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.   DuWayne
 * ----------------------------------------------------------------------------
 *
 *
 * Libraries used Adafruit LCD and Graphics Libraries

 * rotary.h from AD7C
 *
 *
 *************/

#include <SPI.h>
#include <rotary.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h> // Hardware-specific library
// pins used by TFT Display
#define TFT_CS 6
#define TFT_DC 10
#define TFT_RST 7
#define Backlight 9 // Analog output pin that the LED is attached to

// Color definitions
#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

Adafruit_ST7735 display = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);


// AD9850 info
#define W_CLK A5   //  connect to AD9850 module word load clock pin (CLK)
#define FQ_UD A4   //  connect to freq update pin (FQ)
#define DATA A3   // connect to serial data load pin (DATA)
#define DDS_RESET A2 //- connect to reset pin (RST) 
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }


//Global variables

// used by sweep and PC input
long int frq;
double Fstart_MHz  = 1000000;  // Start Frequency for sweep
double Fstop_MHz   = 30000000;  // Stop Frequency for sweep
double current_freq_MHz;      // Temp variable used during sweep
double Fstep_MHz = 10000;             //size of Sweep step
double VFOstep_Khz = 100000;             //size of VFO step

int num_steps = 160; // Number of steps to use in the sweep  change for screen size
int Vinz = 0;            // correct for any DC offset
int Voutz =0;

// used in gain loss calculation
double RF_vin = 0;
double RF_vout = 0;
double db;               // db gain loss ref to v out
double dbPoint[160];       //sweep points  db*10
double max_db;           // used to normalize data

// used by encoder and pushbutton control
int buttonstate = 0;
double encoder;

//used by various display procedures
int c_pos;
int p;
double f1;
double f2;
double dbValue;


int RunOnce = 1;          // for anything I want to run once at startup

float SupplyVoltage = (0); // Power supply voltage
int backlightTimer = 5000;        // counts the cycles without input (turn off backlight after about 5 seconds of no rf)

// Setup for rotary encoder with push button
Rotary r = Rotary(2, 3); // sets the pins the rotary encoder uses.  Must be interrupt pins.
#define EncoderBtn 4


// Analog inputs for gain loss calculation
#define Vin  A0
#define Vout A1

// Analog input for battery monitor
#define vin_BAT A6

#define R1   (10)  // from GND to vin_BAT, express in 100R  (10 = 1000 Ohm)
#define R2    (47)  // from + power supply to vin_BAT, express in 100R  (47 = 4700 Ohm)
#define VoltSupplyMini (550)       // minimum battery voltage expressed in 100mV (if lower, alarm is generated)


// system modalities
#define mSWEEP 0
#define mNORM  1
#define mFAST  2
#define mVFO   3
#define mDIP   4
int modality = mSWEEP ;

// display modes   either sweep or settings
#define dmSWEEP    0
#define dmSETTING  1
int  dMODE  = dmSWEEP ;

// settings
#define sSTART  1
#define sEND    2
#define sSTEP   3
#define sMODE   4

int sITEM = sMODE ;

void setup() {

  Serial.begin(57600);                    // connect to the serial port   only for testing   comment out for final build
  Serial.println("KV4QB SNA Jr.");

  // initialize interrupts
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();

  // set up encoder and pushbutton pins
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  pinMode(3, INPUT);
  digitalWrite(3, HIGH);
  pinMode(EncoderBtn, INPUT);
  digitalWrite(EncoderBtn, HIGH);
  //
  // setup inputs for reading RF_out  RF_in and battery
  pinMode(Vin, INPUT);
  pinMode(Vout, INPUT);
  pinMode(vin_BAT, INPUT);

  // Use this initializer if you're using a 128x160 TFT
  display.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab

  display.setRotation(1);    // set orientation of display
  analogWrite(Backlight, 120);

  // start out in settings  and select mode
  dMODE = dmSETTING;
  sITEM = sSTART;

  // setup AD9850 module pins and initialze
  pinMode(FQ_UD, OUTPUT);
  digitalWrite(FQ_UD, LOW);
  pinMode(W_CLK, OUTPUT);
  digitalWrite(W_CLK, LOW);
  pinMode(DATA, OUTPUT);
  digitalWrite(DATA, LOW);
  pinMode(DDS_RESET, OUTPUT);
  pulseHigh(DDS_RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);  // this pulse enables serial mode on the AD9850
}

//
//   END of Setup
//
//    Main program loop
void loop()
{
  //check battery
  measuresupplyvolt();

  // show Splash screen  only do once
   SplashScreen();
  RunOnce = 0;

  //  process pushbutton
  buttonstate = digitalRead(EncoderBtn);
  if (buttonstate == LOW) {
    delay(800);
    buttonstate = digitalRead(EncoderBtn);   //held over .8 second then toggle  sweep screen or settings
    if (buttonstate == LOW) {
      if (dMODE == dmSWEEP) {
        dMODE = dmSETTING;
        display.fillScreen(BLUE);
        dispSettingScreen();
      }
      else  {
        dMODE = dmSWEEP;
        display.fillScreen(BLUE);
        if  (modality  == mVFO) {
          dispVFOScreen();
          VFO_VM();
        }
        else
          dispScanScreen();
      }
      delay(100);
    }
    //   Got  correct display mode from long press now process short push
    //   first take care of settings
    //   Note you have to press button to enable settings change or go to display screen
    else if (dMODE == dmSETTING) {  //  process changes to settings
      if (sITEM == sSTART) {
        setStartFreq();
        sITEM =  sEND ;
      }
      else if (sITEM == sEND) {
        setEndFreq();
        sITEM   = sSTEP;
      }
      else if (sITEM == sSTEP) {
        setStepSize();
        sITEM = sMODE;
      }
      else if (sITEM == sMODE) {
        setModality();
        sITEM = sSTART;
      }
    }
    // Not a settings change
    // start data acquisition
    if (dMODE == dmSWEEP) {
      display.fillScreen(BLUE);
      if   (modality  ==  mVFO)
        VFO_VM();
      else if   (modality  ==  mDIP)
        find_dip();
      else if   (modality  ==  mFAST)
        Fast_Sweep();
      else
        Perform_sweep();
    }
  }

  //  button press processed  now use rotary
  //  to scroll through acquired data
  if (dMODE == dmSWEEP)
    scrollSweep();
}
//
//   end of loop
//
//                  *******      Functions    ************
//
// interrupt service routine for encoder
ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result) {
    if (result == DIR_CW) {
      encoder--;
    }
    else {
      encoder++;
    }
  }
}
//
//  Do a scan of band  compute gain loss for each point store to array and display sweep
//
void Perform_sweep() {
  int x;
  int x1 = 0;
  int y;
  int y1 ;
  // show screen for selected modality
  if (modality == mSWEEP)
    dispScanScreen();
  else if (modality == mNORM)
    dispScanScreen();
  // Find step size for sweep
  Fstep_MHz = (Fstop_MHz - Fstart_MHz) / num_steps;

  // Start scan loop
  max_db = -100;      // set peak finder for possible normalize of data
  for (int i = 0; i <= num_steps; i++) {
    // Calculate frequency for each step in scan
    current_freq_MHz = Fstart_MHz + (i * Fstep_MHz);
    sendFrequency(current_freq_MHz);
    delay(4);  // Wait a little for settling
    RF_vin  = 0;    //clear last reading
    RF_vout = 0;
    // Read the forawrd and output and return voltages , repeat to help elminate noise

    RF_vout  = RF_vout  + (analogRead(Vout) - Voutz);
    RF_vin = RF_vin + (analogRead(Vin) - Vinz);
    RF_vout  = RF_vout  + (analogRead(Vout) - Voutz);
    RF_vin = RF_vin + (analogRead(Vin) - Vinz);

    if (RF_vout <= 0)RF_vout = 1;   //prevemt possible divide by 0 or overflow errors
    if (RF_vin <= 0)RF_vin = 1;
    // Calculate relative rf signal level
    db = 20 * log10(RF_vin / RF_vout);
    if (max_db < db)  max_db = db;
    if (modality == mSWEEP)
      dbPoint[i] = (db * 100);
    else  dbPoint[i] = (db - max_db) * 100; // normalize data

    // Check for button pressed during a sweep
    buttonstate = digitalRead(EncoderBtn);
    // if button pressed during sweep enter mode to adjust op amp gain
    if (buttonstate == LOW) {
      sendFrequency(Fstart_MHz);
      while (digitalRead(EncoderBtn) == LOW)
        setLevels();    // display values of ADC 2 reps to reduce noise
      display.fillScreen(BLUE);
      dispScanScreen();
    }
  }
  dispScanScreen();
  drawSweep();
}

//scroll through sweep
void scrollSweep() {
  if (encoder != 0) {
    //   clear old values from screen
    display.fillRect(1, 1, 159, 16, BLUE);
    display.drawLine(c_pos , 20, c_pos , 127, BLUE);
    c_pos = (encoder + c_pos);
    encoder = 0;
    //   display.fillScreen(BLUE);
    p = c_pos;
    if (c_pos >= (num_steps - 1)) {
      c_pos = num_steps - 1; //Upper scan limit
    }
    if (c_pos <= 1) {
      c_pos = 1;    // Lower scan limit
    }
    f1 =  ( Fstart_MHz  + ( c_pos *  Fstep_MHz ));
    display.setCursor(2, 6);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.print((f1 / 1000000), 4);
    display.setCursor(112, 6);
    dbValue =  (dbPoint[p] / 100);
    display.print(dbValue, 1);
    display.print("db");
    drawSweep();
    drawGrid();
    display.drawLine(c_pos , 27, c_pos , 127, MAGENTA);
  }
}

//Show and set levels of input amplifiers
//
void setLevels () {
  // display start and stop frequencies on top of display
  display.fillScreen(BLUE);
  display.setCursor(2, 4);
  display.setTextSize(2);
  display.setTextColor(YELLOW);
  display.print((Fstart_MHz / 1000000), 3 );
  display.setTextSize(1);
  display.print(" MHz." );
  // Read the forawrd and reverse voltages , repeat to help elminate noise
  RF_vout =0;
  RF_vin = 0;
  for (int j = 0; j <= 7; j++) {
    RF_vout = RF_vout + (analogRead(Vout) - Voutz);
    RF_vin  = RF_vin  + (analogRead(Vin) - Vinz);
  }
  RF_vout = RF_vout / 8;
  RF_vin  = RF_vin  / 8;
  display.setCursor(2, 22);
  display.setTextSize(1);
  display.println("RF_vout");
  display.println(" ");
  display.setTextSize(2);
  display.println( analogRead(Vout));
  display.setTextSize(1);
  display.println(" ");
  display.println("RF_vin");
  display.println(" ");
  display.setTextSize(2);
  display.println( analogRead(Vin));
  display.setTextSize(1);
  display.println("");
  display.println("Batt =");
  display.setTextSize(2);
  display.print((SupplyVoltage / 100));
  display.print("v");
  delay(200);
}

//
// Draw the sweep waveform  divide by 50 gives approximate 10 db  per divisions in Sweep mode
//
void drawSweep() {
  int x;
  int x1 = 0;
  int y;
  int y1 = 27 - (dbPoint[0] / 50) ;
  for (int i = 0; i <= num_steps; i++) {
    y = 27 - (dbPoint[i] / 50) ;
    display.drawLine(x1, y1, i, y, YELLOW);
    x1 = i;
    y1 = y;
  }
}

//
// set output frequency to AD9850
// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
//
void sendFrequency(double frequency) {
  int32_t freq = frequency * 4295067295 / 125000000; // note 125 MHz clock on 9850.  You can make 'slight' tuning variations here by adjusting the clock frequency.
  for (int b = 0; b < 4; b++, freq >>= 8) {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
  pulseHigh(FQ_UD);  // Done!  Should see output
}
// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data) {
  for (int i = 0; i < 8; i++, data >>= 1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }
}

//
// display Scan screen with frequency range
//
void dispScanScreen() {
  // display start and stop frequencies on top of display
  //display.fillScreen(BLUE);
  display.setTextSize(1);
  display.setTextColor(YELLOW);
  display.setCursor(2, 6);
  display.print((Fstart_MHz / 1000000), 3);
  display.setCursor(112, 6);
  display.print((Fstop_MHz / 1000000), 3);
  drawGrid();
}

//
// Draw the scan grid  modify for each frequency band width
//
void drawGrid() {
  int xinc;
  display.setTextColor(CYAN);
  xinc = num_steps / 6; // scale for screen
  for (int i = 0; i <= 7; i++)
    display.drawLine((i * xinc), 27, (i * xinc), 127, CYAN);
  // these values give approximatly 10 db level markings
  for (int i = 1; i <= 6; i++)
    display.drawLine(1, 6 + (i * 20), num_steps - 3, 6 + (i * 20), CYAN);
}

//
// Power SupplyVoltage measure voltage and test for low volts
//display low voltage
//
void measuresupplyvolt () {
  // Read power supply voltage
  SupplyVoltage = analogRead(vin_BAT);
  SupplyVoltage = map(SupplyVoltage, 0, 1023, 0, (500 * (float R2 + float R1) / float R1)); // compute battery voltage using voltage divider values
  //SupplyVoltage = SupplyVoltage  + diode ;    if you have a reverse voltage diode add the voltage drop
  if (SupplyVoltage <= 500) return;       // not running on batteries !
  if   (SupplyVoltage  <= VoltSupplyMini) {
    //display.fillScreen(BLUE);
    display.setCursor(40, 10);
    display.print("LOW BATTERY !");
    display.setCursor(40, 10);
    delay (500);
    display.setTextColor(BLUE);
    display.print("LOW BATTERY !");
    display.setTextColor(YELLOW);
  }
}


//
// Splash screen  with battery voltage
//
void SplashScreen() {
  if (RunOnce == 1) {
    display.setTextColor(YELLOW);
    display.fillScreen(BLUE);
    display.setCursor(24, 35);
    display.setTextSize(3);
    display.println("KV4QB");
    display.setTextSize(2);
    display.setCursor(5, 70);
    display.print("  SNA Jr");
    display.setCursor(25, 7);
    display.setTextSize(1);

    display.setCursor(30, 100);
    display.print("Batt =");
    display.print((SupplyVoltage / 100));
    display.print("v");
    delay(2500);
    RunOnce = 0;
    display.fillScreen(BLUE);
    dispSettingScreen();
  }
}
//
//  Functions related to settings
//
//
// display settings screen
void dispSettingScreen() {
  display.setTextSize(1);
  if (sITEM == sSTART)                // active setting in  yellow
    display.setTextColor(YELLOW);     // inactiove settings in cyan
  else
    display.setTextColor(CYAN);
  display.setCursor(2, 4);
  display.print("Start Frequency Mhz.");
  display.setCursor(12, 16);
  display.setTextSize(2);
  display.print((Fstart_MHz / 1000000), 3);
  if (sITEM == sEND)
    display.setTextColor(YELLOW);
  else
    display.setTextColor(CYAN);
  display.setTextSize(1);
  display.setCursor(2, 36);
  display.print("Stop Frequency Mhz.");
  display.setTextSize(2);
  display.setCursor(12, 48);
  display.print((Fstop_MHz / 1000000), 3);
  display.setTextSize(1);
  if (sITEM == sSTEP)
    display.setTextColor(YELLOW);
  else
    display.setTextColor(CYAN);
  display.setCursor(2, 66);
  display.print("Step Khz.");
  display.setTextSize(2);
  display.setCursor(12, 76);
  display.print((VFOstep_Khz / 1000), 0);
  display.setTextSize(1);
  if (sITEM == sMODE)
    display.setTextColor(YELLOW);
  else
    display.setTextColor(CYAN);
  display.setCursor(2, 94);
  display.print("Mode");
  display.setTextSize(2);
  display.setCursor(12, 106);
  if (modality == 0)
    display.print("SWEEP.R");
  else  if (modality == 1)
    display.print("SWEEP.N");
  else  if (modality == 2)
    display.print("SWEEP.FAST");
  else if (modality == 3)
    display.print("VFO");
  else if (modality == 4)
    display.print("DIP");
}

//
//   change settings functions
//

//   set start frequency
void setStartFreq() {
  dispSettingScreen();                      // mark other settings inactive
  display.setTextColor(YELLOW);
  display.setCursor(2, 16);
  display.setTextSize(2);
  while (1) {
    if (encoder != 0) {
      delay(10);
      Fstart_MHz = Fstart_MHz + (encoder * VFOstep_Khz);
      if (Fstart_MHz > 30000000) Fstart_MHz = 30000000;
      if (Fstart_MHz < 1000000) Fstart_MHz = 1000000;
      encoder = 0;
      display.fillRect(1, 16, 127, 16, BLUE);
      display.setCursor(12, 16);
      display.print((Fstart_MHz / 1000000), 3);
    }
    buttonstate = digitalRead(EncoderBtn);
    if (buttonstate == LOW)
      return;
  }
}

//   setEndfrequency
void setEndFreq() {
  dispSettingScreen();
  display.setTextColor(YELLOW);
  display.setTextSize(2);
  while (1) {                    // use encoder to set frequency   press button to exit
    if (encoder != 0) {
      delay(10);
      Fstop_MHz = Fstop_MHz + (encoder * VFOstep_Khz);
      if (Fstop_MHz > 30000000) Fstop_MHz = 30000000;
      if (Fstop_MHz < 1000000) Fstop_MHz = 1000000;
      encoder = 0;
      display.fillRect(1, 48, 127, 16, BLUE);
      display.setCursor(12, 48);
      display.print((Fstop_MHz / 1000000), 3);
    }
    buttonstate = digitalRead(EncoderBtn);
    if (buttonstate == LOW)
      return;
  }
}

//  set Step Size
void setStepSize() {
  dispSettingScreen();
  display.setTextColor(YELLOW);
  display.setTextSize(2);
  while (1) {                                    // use encoder to set frequency   press button to exit
    if (encoder != 0) {
      delay(10);
      VFOstep_Khz = VFOstep_Khz * 10;
      if (VFOstep_Khz > 1000000) VFOstep_Khz = 1000;
      encoder = 0;
      display.fillRect(1, 76, 127, 16, BLUE);
      display.setCursor(12, 76);
      display.print(( VFOstep_Khz / 1000), 0);
    }
    buttonstate = digitalRead(EncoderBtn);
    if (buttonstate == LOW)
      return;
  }
}

// Set Modality
void setModality() {
  dispSettingScreen();
  display.setTextColor(YELLOW);
  display.setTextSize(2);
  while (1) {
    if (encoder != 0) {
      modality++;
      if (modality  > 4)
        modality  = 0;
      encoder = 0;
      display.fillRect(1, 106, 160, 16, BLUE);
      display.setCursor(12, 106);
      if (modality == 0)
        display.print("SWEEP.R");
      else  if (modality == 1)
        display.print("SWEEP.N");
      else  if (modality == 2)
        display.print("SWEEP.FAST");
      else  if (modality == 3)
        display.print("VFO");
      else display.print("DIP");
    }
    buttonstate = digitalRead(EncoderBtn);
    if (buttonstate == LOW)
      return;
  }
}

// VFO function with simple rf voltmeter

void dispVFOScreen() {
  current_freq_MHz = Fstart_MHz;
  display.setTextSize(1);
  display.setTextColor(YELLOW);     // inactiove settings in cyan
  display.setCursor(2, 8);
  display.print(" VFO Frequency Mhz.");
  display.setCursor(12, 20);
  display.setTextSize(2);
  display.print( (current_freq_MHz / 1000000), 6);
  display.setTextSize(1);
  display.setCursor(12, 40);
  display.print("Step Khz.");
  display.setTextSize(2);
  display.setCursor(12, 52);
  display.print((VFOstep_Khz / 1000), 3);
  display.setTextSize(1);
  display.setTextSize(1);
  display.setCursor(12, 74);
  display.print("Relative RF IN");
  display.setTextSize(2);
  display.setCursor(12, 86);
  display.print(db, 1);
  display.fillRect(1, 106, num_steps, 8, YELLOW);
}


//   VFO Voltmeter

void VFO_VM() {
  int last_db;
  int scale ;
  current_freq_MHz = Fstart_MHz;
  sendFrequency(current_freq_MHz);
  while (1) {
    buttonstate = digitalRead(EncoderBtn);        // check for button press
    if (buttonstate == LOW) {
      delay(250);
      buttonstate = digitalRead(EncoderBtn);      // then check for long press and exit
      if (buttonstate == LOW) return;
      else {                                      // short press   change step size
        display.fillRect(1, 52, num_steps, 16, BLUE);
        VFOstep_Khz = VFOstep_Khz * 10;
        if (VFOstep_Khz > 1000000) VFOstep_Khz = 10;
        display.setCursor(12, 52);
        display.print((VFOstep_Khz / 1000), 3);
      }
    }
    if (encoder != 0) {             // look for frequency change from encoder
      delay(10);
      current_freq_MHz = current_freq_MHz + (encoder * VFOstep_Khz);
      if (current_freq_MHz > 30000000) current_freq_MHz = 30000000;
      if (current_freq_MHz < 500000) current_freq_MHz = 500000;
      encoder = 0;
      display.fillRect(1, 18, 127, 16, BLUE);
      display.setCursor(12, 18);
      display.print((current_freq_MHz / 1000000), 5);
      display.print("0");
      sendFrequency(current_freq_MHz);
    }
    RF_vin = 0;    //clear last reading before starting reading voltages
    RF_vout = 0;
    // Read the  output and return voltages , repeat to help elminate noise

    RF_vout  = RF_vout  + (analogRead(Vout) - Voutz);
    RF_vin = RF_vin + (analogRead(Vin) - Vinz);
    RF_vout  = RF_vout  + (analogRead(Vout) - Voutz);
    RF_vin = RF_vin + (analogRead(Vin) - Vinz);

    if (RF_vout <= 0)RF_vout = 2;   //prevemt possible divide by 0 errors
    if (RF_vin <= 0)RF_vin = 2;
    // Calculate relative rf signal level
    db = 20 * log10(RF_vin / RF_vout);
    if (int(db * 10 ) != last_db) {            // only update if changed from last reading
      display.setTextSize(2);
      display.fillRect(12, 86, 127, 16, BLUE);
      display.setCursor(12, 86);
      display.print(db, 1);                    // display value in db
      display.setTextSize(1);                  // then percent full scale
      display.print("db ");
      display.print(((RF_vin / RF_vout ) * 100), 1);
      display.print("%");
      display.setTextSize(2);
      last_db = int(db * 10);
      delay(50);
      display.fillRect(1, 106, num_steps, 8, YELLOW);   // show percent full scale as bar
      scale = (RF_vin / RF_vout ) * (num_steps - 3);
      display.fillRect(2, 108, scale, 4, BLACK);
    }
  }
}


//     Find dip frequency
void find_dip() {
  double dip_freq;
  double min_db;
  // Start and End frequency full range
  Fstart_MHz  =  1000000;
  Fstop_MHz   = 30000000;
  Fstep_MHz = 50000;       // stgep 50Khz
  min_db = 100;      //    inital value for peak detector
  display.fillScreen(BLUE);
  display.setTextSize(2);
  display.setTextColor(YELLOW);
  display.setCursor(12, 2);
  display.print("Finding Dip");
  display.setCursor(1, 8);

  for (int i = 0; i <= 1000; i++) {
    // Calculate frequency for each step in scan
    current_freq_MHz = Fstart_MHz + (i * Fstep_MHz);
    sendFrequency(current_freq_MHz);
    delay(1);  // Wait a little for settling
    RF_vin = 0;    //clear last reading
    RF_vout = 0;
    // Read the forawrd and output and return voltages , repeat to help elminate noise
    //for (int j = 0; j <= 1; j++) {
    RF_vout  = RF_vout  + (analogRead(Vout) - Voutz);
    RF_vin = RF_vin + (analogRead(Vin) - Vinz);
    RF_vout  = RF_vout  + (analogRead(Vout) - Voutz);
    RF_vin = RF_vin + (analogRead(Vin) - Vinz);
    // }
    if (RF_vout <= 0)RF_vout = 1;   //prevemt possible divide by 0 or overflow errors
    if (RF_vin  <= 0)RF_vin  = 1;
    // Calculate relative rf signal level
    db = 20 * log10(RF_vin / RF_vout);
    if (min_db > db) {             // look for dip
      min_db = db;
      dip_freq = current_freq_MHz;
    }
  }
  Fstart_MHz  =  dip_freq - 1000000;
  Fstop_MHz   = dip_freq + 1000000;
  display.fillScreen(BLUE);
  c_pos = 80;
  dispScanScreen();
  Perform_sweep();
}
//   Fast cpntinusous sweep for aliogiing filters
//
void Fast_Sweep() {
  //  int x;
  //  int x1 = 0;
  int y;
  int y1 ;
  // show screen for selected modality
  display.fillScreen(BLUE);
  dispScanScreen();
  // Find step size for sweep
  Fstep_MHz = (Fstop_MHz - Fstart_MHz) / num_steps;

  // Start scan loop
  buttonstate = digitalRead(EncoderBtn);
  while (buttonstate == HIGH) {
    for (int i = 0; i <= num_steps; i++) {
      // Calculate frequency for each step in scan
      current_freq_MHz = Fstart_MHz + (i * Fstep_MHz);
      sendFrequency(current_freq_MHz);
      delay(1);  // Wait a little for settling
      y = 27 - (dbPoint[i] / 50) ;
      y1 = 27 - (dbPoint[i + 1] / 50) ;
      display.drawLine(i, y, i + 1, y1, BLUE);
      // Read the forawrd and output and return voltages , repeat to help elminate noise
      RF_vout  = 0;
      RF_vin = 0;
      RF_vout  = RF_vout  + (analogRead(Vout) - Voutz);
      RF_vin = RF_vin + (analogRead(Vin) - Vinz);
      if (RF_vout <= 0)RF_vout = 1;   //prevemt possible divide by 0 errors
      if (RF_vin  <= 0)RF_vin  = 1;
      // Calculate relative rf signal level
      db = 20 * log10(RF_vin / RF_vout);
      dbPoint[i] = (db * 100);
      y = 27 - (dbPoint[i] / 50) ;
      y1 = 27 - (dbPoint[i - 1] / 50) ;
      display.drawLine(i - 1, y1, i , y, YELLOW);
      // Check for button pressed during a sweep
      buttonstate = digitalRead(EncoderBtn);
      // if button pressed during sweep exit while loop
    }
    drawGrid();  // refresh grid at end of sweep
  }
  // scanning stopped redraw screen   wait for another short press to restart sweep or long press to exit
  dispScanScreen();
  drawSweep();
}

Custom parts and enclosures

SNA jr Circuit board image suitable for toner transer
Image that can be used to make circuit boards using toner transfer method
EAGLE layout for circuit board
SNA%20JR%20%20DDS%20large%20format.brd
Circuit board parts placement

Schematics

SNA jr. schematic
Sna%20jr%20large%20format%20schematic%20

Comments

Similar projects you might like

Make your own Power Inverter using Arduino

Project showcase by Team Shailza

  • 25,924 views
  • 6 comments
  • 15 respects

Soldering Iron Controller for Hakko 907

Project tutorial by Alexander

  • 30,914 views
  • 22 comments
  • 69 respects

Windows 10 IoT Core : Hydroflyer

Project showcase by Anurag S. Vasanwala

  • 17,503 views
  • 2 comments
  • 53 respects

Multiple mode Environmental Sensor Deck with MKR1000

Project tutorial by Team ConsoleTeam

  • 11,340 views
  • 13 comments
  • 46 respects

Windows 10 IoT Core: UltraSonic Distance Mapper

Project showcase by Anurag S. Vasanwala

  • 51,781 views
  • 23 comments
  • 138 respects

Water Quality Monitoring and Notification System

Project showcase by emmanuel ani

  • 50,622 views
  • 38 comments
  • 112 respects
Add projectSign up / Login