Showing posts with label instrument remote control. Show all posts
Showing posts with label instrument remote control. Show all posts

Tuesday, December 29, 2020

LXI - Rigol DSA815 Spectrum Analyzer - remote control

 Following on the series for "GPIB" control of instruments, this post is about LXI control, in particular the Rigol DSA815-TG spectrum analyzer. It is more Linux oriented but commands can be ported to other systems.
Did this out of need since I could not find a single explanatory source of information for all the commands listed besides the programing guide and as all programing guides, they never have a simple; "how to to this"
Most of the command are using the "lxi" tool v1.21. You can use also the gui version "lxi-gui"

LXI is nothing more than LAN extensions for instrumentation control. Same end result as GPIB or Serial port control, that is, you have a system that controls and queries the instrument, only the medium is different on this case, it uses a more modern approach, the Ethernet/LAN.

Recently acquired a Rigol DSA815-TG 1.5Ghz spectrum analyzer and although at the moment I only use computer control for taking some screenshots would be interesting to know how to take more advantage of instrument remote control.

First thing you will need is connect your instrument via the LAN port to your local network, in my case I just connect it back to back to my laptop. Then you will need to set the IP via instrument panel, in my case I used a static IP in the same range as the Ethernet port of the laptop.

Laptop was configured with IP 192.168.1.65 / netmask 255.255.255.0 (/24 for the hard core one)

In case you don't know your instrument IP, case configured by DHCP for example, you can use the "lxi" tool discover command to "automatically" discover the instruments available on you local are network.

==
# lxi discover
Searching for LXI devices - please wait...
 
Broadcasting on interface lo
Broadcasting on interface enp9s0
  Found "Rigol Technologies,DSA815,DSA8A22XXXXXX,00.01.19.00.02" on address 192.168.1.81
Broadcasting on interface wlp12s0
 
Found 1 device
==

If you are more inclined to review some additional protocol specifications,you can find it here.
A simple wireshark capture allows to have an idea of the inner workings of the discovery process.

 


 

At this stage you can query the instrument with the classic "*IDN?" command:
 

==
#  lxi scpi --address 192.168.1.81 "*IDN?"
A: Rigol Technologies,DSA815,DSA8A22XXXXXX,00.01.19.00.02
==
Note: I replaced part of the instrument identifier string with X's.

 

You can also use a normal "telnet" to port 5555 and make de same query:
==
# telnet 192.168.1.81 5555
Trying 192.168.1.81...
Connected to 192.168.1.81.
Escape character is '^]'.
*IDN?
Rigol Technologies,DSA815,DSA8A22XXXXX,00.01.19.00.02
==

Now let's take some data from the instrument, a screenshot for a start, using the lxi tool screenshot option:

==
 # lxi screenshot --address 192.168.1.81 trace.bmp
==

Result is is "trace.bmp file saved on the current working directory:


The screenshot will literary take a screenshot of what's visible on the screen be it a trace or a configuration screen.

Even more complicated screenshot for the command line die hard's:
==
# echo ":PRIV:SNAP? BMP" | nc -w 5 192.168.1.81 5555 | dd bs=1 skip=11 of=screen.bmp
==

Continuing with some other commands...

Display brightness query:

==
# lxi scpi --address 192.168.1.81 "DISP:BRIG?"
==
Note: answer with be a numeric value of the the setting, in my case is "1"

If you need to change to "2" the screen brightness:
==
# lxi scpi --address 192.168.1.81 "DISPlay:BRIGhtness 2"
==


Turning the tracking generator/TG on:

==
# lxi scpi --address 192.168.1.81 "OUTP:STATE 1"
==

Querying the tracking generator/TG status:
==
# lxi scpi --address 192.168.1.81 "OUTP:STATE?"
==
Output will be 1 or 0 if ON or OFF.


Setting and querying the start frequency:

==
# lxi scpi --address 192.168.1.81 "FREQ:START 124Mhz"
==
Query:
==
# lxi scpi --address 192.168.1.81 "FREQ:START?"
==
Note: it will answer the previous set frequency: "124000000"

For stop frequency should be "FREQuency:STOP", bellow for a 450Mhz stop frequency
==
# lxi scpi --address 192.168.1.81 "FREQ:STOP 450Mhz"
==
The result will be like this on the spectrum analyzer:


 Now we need to take/download traces: this for me is the most interesting part since we can take the traces and then compute over the results, for instance in SWR (when trial license expires ) or 3db bandwidth for example.


Download data of trace 1
==
# lxi scpi --address 192.168.1.81 ":TRACe:DATA? TRACe1"
==
Output, (shortened version) will be similar to this:
#9000009014 -2.017071e+01, -5.862679e+01, -6.025334e+01, -6.129734e+01, -6.015621e+01, -6.299181e+01, -5.941000e+01, -6.174416e+01, -5.768233e+01, -6.222626e+01, -6.008302e+01, -6.109689e+01, -6.196978e+01, -6.302518e+01, -6.228621e+01, -6.230527e+01, -6.312371e+01, -6.304392e+01, -6.187805e+01, -6.133699e+01, -6.096120e+01, -5.720531e+01, -5.873640e+01, -6.165216e+01, -5.796873e+01, -5.905419e+01, -5.763849e+01, -6.094759e+01, -6.073965e+01,..

You can "pipe" the command to file this way:
==
# lxi scpi --address 192.168.1.81 ":TRACe:DATA? TRACe1" > trace1.csv
==
Open "trace1.csv" on a spreadsheet software and plot a graph:


To download trace 3 for example:
==
# lxi scpi --address 192.168.1.81 ":TRACe:DATA? TRACe3"
==
If nothing is set for that trace the output will look like this:
#9000009014 -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02, -4.000000e+02,...(continues)


As last command on this series, let's query the instrument language:
==
 # lxi scpi --address 192.168.1.81 "SYST:LANG?"
==
Output is on my case: "ENGl"

==========

- In the future will try to add more commands in this document and write some scripts for automation, maybe even a GUI program. 

- If you copy past the command in this post, don't forget to set your instrument IP instead of the one I used (192.168.1.81)

- Rigol DSA800 programing guide can be downloaded at: https://www.batronix.com/files/Rigol/Spektrum-Analysatoren/DSA800/DSA800_ProgrammingGuide_EN.pdf

Hope this helps someone,

Have a nice day!

 

 

 



Saturday, March 28, 2020

GPIB - USB GPIB controler arduino based

This will be part of a series for test instrument remote control, I started this with my own "instrument" design and code a USB temperature measurement on this blog post and bellow hardware:



 This time and because I have several branded instruments with GPIB bus control, decided to try this nice project  that consist of an Arduino connected to a GPIB plug and acting as a poor man GPIB controller.

The idea of the original project was to create an affordable alternative to more expensive solution of USB to GPIB, PCMCIA or even PCI GPIB cards that still a bit on the expensive side for the common amateur.

Basically only had to follow the instructions on the project page, I used an GPIB cable cut in half since it was cheaper than just buying the plugs and can still make a second unit with the half left:





... I chose to label all the cables to pin numbers to keep it easy, otherwise I could had messed up. The cabling stayed a bit squeezed because I under estimated the box size needed.


Used a 1.5m GPIB instrument cable with plugs in both ends.

Another view of the "mess":


For the usage of the system, bellow an example with the Agilent 6621A power supply on GPIB address 1:



Basically, you set the GPIB instrument address (you want to comunicate with) with "++addr" in my case the power supply is set to 1, then you set output 1 to 5 volts (VSET1,5) and then "ask" the instrument to read the output 1 value (VOUT?1 and ++read). The 9.99v on the image was the output of a previous testing setting to 10V.

For the configuration of the USB port and output I get on a Linux system it's like this:

115200 baud 8N1, in my case the device is loaded under /dev/ttyACM0


 I had some testing with other Instruments:

R & S NRVS power meter:

Marconi 6960A power meter:




Besides the number of pins to connect from the GPIB plug to the Arduino the hardest part is going trough the instruments GPIB programing manual and trying to check which of the commands work. Interesting enough the one that should be standard; get instrument id (ID?) I never got and answer using this board when testing.

Right now this project is a backup option/solution because I manage to get a very cheap PCI32 GPIB card and am using it at the moment. I will provide some more info on that on the future. 

Have a nice day and stay safe!


Sunday, November 03, 2019

USB temperature measurement with LM35 and Arduino

Just needed a way to output temperate measurement from an LM35 on the serial or USB port.

Nothing fancy here, some code on the Arduino to read an analog input from the sensor and output it on the USB, the usb connection on the Arduino will also take care of powering the circuit.

The output temperature range will be a limited due to max power supply (5v) and of the gain stage (5x) to "increase" resolution of the Arduino ADC and reduce uncertain on the ADC conversion. In practice temperature range will be around 0 to 70 C positive.

Finished, boxed product, just one cable to the sensor and the Arduino inside:



Code running and pooling data to the desktop:

Inside:


Circuit:



Opamp gain stage (5x) for the LM35:


 There's a second opamp in the LM358 that could be used for a second sensor.

Input (10mv per *C, so that is 20.9 *C) and output after opamp:








5.018 gain in practice (1049mv/209mv) and 5.1 in theory. I used a 8.2k and 2K resistors so the gain will be 4.1 + 1

I also created some code to read the values on the desktop using python:

Could be handy for OSD display/overlay on video but mostly will be used for automation measurement.
You can use also any terminal program reading /dev/ttyUSB0 (or other device where the Arduino/circuit is connected):


 By adding the gain stage the fluctuation on the reading is mostly reduced (as image above), much less as when the LM35 output is directly connected to the ADC, could  see around 1 *C or more variance in the initial testing.

[Arduino code]:

 // read temperature from an LM35 sensor
// there is external opapmp with 5x gain to compensate Arduino ADC resolution.
// CT2GQV 2019
// based on code for the LM35 sensor read and adapted to external opapmp
// if no amp on the signal from LM35 then remove lines:   temp_val1 = temp_val1/5;


int lm35_1 = A1;  
int lm35_2 = A2;


void setup() {
  Serial.begin(9600);
}

void loop() {
  int temp_adc_val1;
  int temp_adc_val2;
  float temp_val1;
  float temp_val2;
  temp_adc_val1 = analogRead(lm35_1);    // read sensor 1

// debug
//Serial.print("ADC:"); Serial.print(temp_adc_val1);

  temp_adc_val2 = analogRead(lm35_2);  // read sensor 2
 
  temp_val1 = (temp_adc_val1 * 4.88);    /* Convert adc value to equivalent voltage */
  temp_val1 = temp_val1/5; // we scale the voltage by 5 times with external opamp
  temp_val1 = (temp_val1/10);    /* LM35 gives output of 10mv/°C */


// For second sensor on A2 uncoment the next 4 lines line
//  temp_val2 = (temp_adc_val2 * 4.88);    /* Convert adc value to equivalent voltage */
//  temp_val2 = temp_val2/5;  // scaling by 5 since the opamp will amplify 5x
//  temp_val2 = (temp_val2/10);    /* LM35 gives output of 10mv/°C */
// Serial.print("T2:"); Serial.println(temp_val2);

  Serial.print(temp_val1); Serial.println(" *C");
  delay(1000);
}


[Python code for screen display]:

#!/usr/bin/python
from serial import *
from Tkinter import *
# adaptation from here:
# http://robotic-controls.com/learn/python-guis/tkinter-serial

serialPort = "/dev/ttyUSB0"
baudRate = 9600
ser = Serial(serialPort , baudRate, timeout=0, writeTimeout=0) #ensure non-blocking

#make a TkInter Window
root = Tk()
root.wm_title("- Temperature -")

label = Label(root,text="waiting data...", fg="light green", bg ="dark green", font = "Helvetica 18 bold italic")
label.pack()

serBuffer = ""

def readSerial():
    while True:
        c = ser.read() # attempt to read a character from Serial
       
        #was anything read?
        if len(c) == 0:
            break
       
        # get the buffer from outside of this function
        global serBuffer
       
        # check if character is a delimeter
        if c == '\r':
            c = '' # don't want returns. chuck it
           
        if c == '\n':
            serBuffer += "\n" # add the newline to the buffer

            label.config(text=serBuffer)           

            #add the line to the TOP of the log
#            log.insert('0.0', serBuffer)
            serBuffer = "" # empty the buffer
        else:
            serBuffer += c # add to the buffer
   
    root.after(10, readSerial) # check serial again soon

# after initializing serial, an arduino may need a bit of time to reset
root.after(100, readSerial)

button = Button(root, text=' EXIT ', width=35, command=root.destroy)
button.pack()

root.mainloop()
# end code

--
Have a nice week!