Coder Social home page Coder Social logo

Comments (7)

dvincentwest avatar dvincentwest commented on September 6, 2024

I very much appreciate the thoughts. I've spent most of the day thinking about this and I think its an important thing to try to get right as early as possible.

I am inclined to give it a try focusing on Agilent 2-port PNAs (where should the 'instrument class' lines be drawn?). Perhaps I can ask for your further thoughts when I have a working model system.

from scikit-rf.

elstanto avatar elstanto commented on September 6, 2024

Sounds good, I'm happy for that.

Sure. I have a PNA-X (N5247A) and an 8753 I can try things out on at some point too.

from scikit-rf.

arsenovic avatar arsenovic commented on September 6, 2024

i dont follow your psuedo code exactly, but i think i get the idea.

there are a lot of subtle issues i have run into with instruments, like timing, need to cache large get's, non-uniformity of commands between vendors, etc. but the current state of drivers is mostly ad-hoc and i think a refactoring would increase the uniformity, thereby removing a lot of wasted code.

there is also an annoying hack in skrf for python-ivi. i added python-ivi so that VI's could be used over TCP/IP, and because pyvisa broke backwards compatibility at one point.

if someone wants to attack this beast, i would recommend looking at the lantz project. they put a lot of effort into solving many generic VI problems.

from scikit-rf.

dvincentwest avatar dvincentwest commented on September 6, 2024

@Helgrind taking your comments to heart I decided to try to think about what your driver architechture proposal would look like, and I'm at a point where I think further comment would be useful. If nothing else this was a fun exercise.

I went through the initial simplified driver I created for qt apps and extracted all of the SCPI commands. I then looked at the keysight command tree and wrote out the command in its read/write form with optional variables. Then, I had to give it a short name for the dict key. I wrote a short SCPI preprocessor that could accept kwargs for the various SCPI arguments and treat them accordingly.

My first question is does this start to look like what you were thinking, or did you have something totally different in mind regarding SCPI commands for an instrument class?

The value in this as I see it is that it (possibly) creates a simpler syntax for the most common commands. The problem is that to use it correctly requires either:

  1. people to know the syntax of the instrument specific SCPI (in which case, why not just use SCPI directly) (although to your it allows you to edit individual scpi commands only one time when needed which then propagate to the rest of the driver, I can see the value in that)
  2. it requires people to learn a new API (use 'channel', instead of 'cnum' or 'format' instead of 'char', just for this project. I assume that is the purpose of efforts like IVI, that unfortunately haven't hung on tight enough keep their momentum going in the Python world.

As per @arsenovic suggestion to learn LabPy, I haven't considered that at this point, as I don't want to spend a ton of time on this aspect while there are a lot of things left to do on the qtapps.

For now, any comments about the value of an SCPI pre-processor versus something else you had in mind would be appreciated. Code is below:


import re

SCPI_COMMANDS = {
    # "key": "pre-SCPI command"
    "data":                 ":CALCulate<cnum>:DATA <char>,<data>",
    "create_meas":          ":CALCulate<cnum>:PARameter:DEFine:EXTended <'mname'>,<'param'>",
    "delete_meas":          ":CALCulate<cnum>:PARameter:DELete <'mname'>",
    "meas_format":          ":CALCulate<cnum>:FORMat <char>",
    "meas_name_list":       ":CALCulate<cnum>:PARameter:CAT:EXT",
    "select_meas_by_num":   ":CALCulate<cnum>:PARameter:MNUM:SEL <mnum>",
    "select_meas_by_name":  ":CALCulate<cnum>:PARameter:SELect <'name'>",
    "snp_data":             ":CALCulate<cnum>:DATA:SNP:PORTs <'ports'>",
    "display_trace":        ":DISPlay:WINDow<wnum>:TRACe<tnum>:FEED <'name'>",
    "averaging_count":      ":SENSe<cnum>:AVERage:COUNt <num>",
    "averaging_state":      ":SENSe<cnum>:AVERage:STATe <onoff>",
    "start_frequency":      ":SENSe<cnum>:FREQuency:STARt <num>",
    "stop_frequency":       ":SENSe<cnum>:FREQuency:STOP <num>",
    "groups_count":         ":SENSe<cnum>:SWEep:GROups:COUNt <num>",
    "sweep_mode":           ":SENSe<cnum>:SWEep:MODE <char>",
    "sweep_time":           ":SENSe<cnum>:SWEep:TIME <num>",
    "sweep_type":           ":SENSe<cnum>:SWEep:TYPE <char>",
    "sweep_points":         ":SENSE<cnum>:SWEep:POINts <num>",
    "available_channels":   ":SYSTem:CHANnels:CATalog",
    "active_channel":       ":SYSTem:ACTive:CHANnel",
    "meas_name_from_number": ":SYSTem:MEASurement<n>:NAME",
    "meas_number_list":     ":SYSTem:MEASurement:CATalog? <cnum>",
    "trigger_source":       ":TRIGger:SOURce <char>",
}

cmd_pattern = re.compile('<(\w+)>', re.ASCII)
arg_pattern = re.compile('<([\'"]?\w+[\'"]?)>', re.ASCII)
kwarg_pattern = re.compile('[\'"]?(\w+)[\'"]?', re.ASCII)

def preprocess_scpi(command, **kwargs):
    base_command = SCPI_COMMANDS[command].split(" ")
    cmd = base_command[0]
    if len(base_command) > 1:
        args = base_command[1]
    else:
        args = ""
    
    split_command = cmd_pattern.split(cmd)
    for i in range(1, len(split_command), 2):
        split_command[i] = str(kwargs.get(split_command[i], ""))
    scpi_command = "".join(split_command)
    
    split_args = arg_pattern.findall(args)
    new_args = []
    for i, arg in enumerate(split_args):
        kwarg = kwarg_pattern.search(arg).group(1)
        value = kwargs.get(kwarg, "")
        if value:
            if type(value) in (list, tuple):
                value = ",".join(map(str, value))
            new_args.append(arg.replace(kwarg, str(value)))
    scpi_args = ",".join(new_args)
    return scpi_command, scpi_args

def write(command, **kwargs):
    scpi_string = " ".join(preprocess_scpi(command, **kwargs)).strip()
#     resource.write(scpi_string)
    print(scpi_string)
    
def query(command, **kwargs):
    scpi_string = "? ".join(preprocess_scpi(command, **kwargs)).strip()
#     return resource.query(scpi_string)
    print(scpi_string)
        
write("create_meas", cnum=1, mname="CH1_S11_1", param="S11")
>>> :CALCulate1:PARameter:DEFine:EXTended 'CH1_S11_1','S11'
query("active_channel")
>>> :SYSTem:ACTive:CHANnel?
query("snp_data", cnum=1, ports=(1,2))
>>> :CALCulate1:DATA:SNP:PORTs? '1,2'

from scikit-rf.

dvincentwest avatar dvincentwest commented on September 6, 2024

#97 has been initiated
@Helgrind I followed your suggestions and went down the rabbit hole. In the qtapps/skrf_qtwidgets/analyzers directory there is now a keysight_pna package defining a class for these modern analyzers. I have created 2 child drivers that simply modify the visa_addresses and the number of ports. They both seem to work without further modification.

There are some example notebooks in the ..analyzers/driver development subdirectory that test the main functions for the qtapps. I would be curious if they work out of the box with your equipment

The sweep triggering still needs some work, as things can get a little complicated if more than one channel or averaging in point mode is turned on. I try to auto-calculate the full sweep time, but its not complete yet.

Everything else seems to be working quite well. I'm curious if you can fire up the data_grabber.py and acquire data from your instrument.

from scikit-rf.

elstanto avatar elstanto commented on September 6, 2024

Hi David,

Thanks for taking my comments into consideration, and implementation! They stemmed from seeing application level code which used explicit SCPI commands. I thought that it would better to abstract those in case different instruments used different command sets. For example, some VNAs set frequency in response not source, etc. If explicit SCPI commands are required at the application level, then there should also be a function from the interface class (to use my example) which allows a custom command or query to be run. It should also be possible to directly inherit from an identical instrument for the purposes of creating a new named driver for another model. For example, PNA-X might inherit from PNA, and then could add some changes to the dictionary or more commands or override a standard VNA method or implement a new method.

I'm afraid I won't have much time to look through code or test at the moment (I feel bad about this but I have lots of work on, also our VNAs are broken at the moment :'( ).

As far as an SCPI preprocessor, I think this is required for embedded values to work. Surely users don't have to work with cnum etc in the main code, just in the SCPI command in the driver file. The preprocessor can replace that term with whatever variable scikit-rf currently uses?

from scikit-rf.

dvincentwest avatar dvincentwest commented on September 6, 2024

New architecture pathway has been decided, probably time to close this and push ahead with the direction we are on.

from scikit-rf.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.