Tuesday, November 08, 2016

Arduino Scalar Network Analyser - proof of concept

Got this idea since needed to check the low-pass filter performance of the Bitx on LF

Basically followed the projects from the following links:

http://rheslip.blogspot.ie/2015/08/the-simple-scalar-network-analyser.html
http://www.changpuak.ch/electronics/Arduino-Shield-TOBI.php

Here's a quick deployment for testing:



Didn't implemented all the parts and according to schematics shown in the previous url's since it was just a proof of concept.
Basically what I did was the AD9850 DDS without buffer and the AD8307 log detector connected to the Arduino running the code changed to conform my AD9850 connection and the Python aplication running on PC.

On the previous image one AM 9Mhz crystal filter is placed between the DDS output and the log detector input. The software running on PC takes care of setting the sweep on the DDS and collection of power level from the AD8307, generating the power to frequency graph (or vice-versa).


So without correct termination and calibration you can get an idea of the filter bandwith.

Tested with an 8 Mhz  crystal in series and this is the result:


If on a full sweep sometimes it's not perceptible where where the "peak" is:


 Just for fun a 47 Ohm resistor in series betwen the DDS and Log detector:






As refered I had to change the Arduino code to fit my DDS connections and the way dds set frequency.
In addition to that since the Python code on the PC is using a fixed com port I setup the arduino to come up allways as /dev/ttyArduino.
In the future I might box it up and tighten the loose ends, that is; include the buffer amp on the DDS, probably changing the code to allow also a manual sweep...

In the mean time my changed code on the python script (DIY60MhzSNA.py) bellow:

# change this to the appropriate serial port for your setup
SERIALPORT = "/dev/ttyArduino"

Link to download: http://www.changpuak.ch/electronics/Arduino/NWA-DUE/DIY60MHzSNA.zip

Since I use Linux (didn't tested the code on win...that is; on legacy OS :)
and for it to come up allways on /dev/ttyArduino if you use recent kernels/distro you might want to add a file on your /etc/udev/rules.d/ with the following contents:

SUBSYSTEM=="tty",ENV{ID_SERIAL}=="1a86_USB2.0-Serial", SYMLINK+="ttyArduino"

Change your serial to whatever you have (look for dmesg output) or look for the documentation on udev, otherwise look for the port when Arduino is connected and change the Python code.
To run the code just: python DIY60MHzSNA.py

Arduino connection to DDS (re-used from other projects):


...output of AD8307 is going to Arduino A 7



Arduino code bellow (watch out on copy past since blogger tends to break formatting):

// AD9850 and AD8307 VNA
//
// for manual control and computer control with DIY60MHzSNA.py
// direct link for python software here: http://www.changpuak.ch/electronics/Arduino/NWA-DUE/DIY60MHzSNA.zip
// for the ad8307 and buffer amp, here: http://rheslip.blogspot.ie/2015/08/the-simple-scalar-network-analyser.html
// 
// Code changed by Ricardo - CT2GQV - 2016
// From the original code and description bellow:
//
// AD9851 DDS and AD8307 power meter
// sept 2013 RH
// small adjustments to match this project:
// http://www.changpuak.ch/electronics/Arduino-Shield-TOBI.php
// 02.11.2015 Alexander Frank
  
int AD8307 = A7;
char inputcmd[100];  // serial data input
int cmdindex=0;

#define W_CLK 8       // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 9       // Pin 9 - connect to freq update pin (FQ)
#define DATA 10       // Pin 10 - connect to serial data load pin (DATA)
#define RESET 11      // Pin 11 - connect to reset pin (RST).

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

void dBm_power()
{
  float dBm=0;
  int i;
  for (i=0;i<20 analogread="" average="" br="" dbm="" float="" i="" nbsp="">  dBm=dBm/i;
  dBm = dBm - 869;
  dBm = ( dBm * 0.1014342 ) - 6.6 ;   
  Serial.print(" "); // may help Python parser
  Serial.print(dBm);
  Serial.println(" "); // may help Python parser
}
void raw_power()
{
  Serial.print(" "); // may help Python parser
  Serial.print(analogRead(AD8307));
  Serial.println(" "); // may help Python parser
}
  // 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 data="" i="">>=1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }


// frequency calc from datasheet page 8 = * /2^32
// my original code was senfrequency();
void SetFrequency(double frequency) {
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850
  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
}


void setup()
{
  Serial.begin(9600);  
  pinMode(FQ_UD, OUTPUT);
  pinMode(W_CLK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RESET, OUTPUT);

  pulseHigh(RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);  // this pulse enables serial mode - Datasheet page 12 figure 10
  SetFrequency(1000000); // 1 MHz default
}

void loop()   // Arduino superloop - where everything gets done
{
  char ch;
  long int temp;


// serial command interpreter
// enter a number to set the frequency, anything else shows power
  while (Serial.available()) {
    ch=(char)Serial.read();
    if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') &&
            (ch <= 'Z'))) inputcmd[cmdindex++]=ch;
    if (ch == '\n') {    // parse command if its a newline
      inputcmd[cmdindex]=0; // terminate the string
      if ((temp=atol(inputcmd)) > 0) SetFrequency(temp);
      else dBm_power(); 
      //else raw_power();  // python has trouble with floats
      cmdindex=0; // reset command line     
    }
  }
}



-- That's it, a nice little project for some tracing fun! I would prefer a "R&S" but there's no budget :)

Have a nice week!