Node-tree based parameter structure in instruments
- Dominant language
- Python
- Stars
- 459
- Forks
- 359
- Avg merge
- 3d 6h
- Merged PRs (30d)
- 73
Description
@jenshnielsen @WilliamHPNielsen
As discussed with @alan-geller and @sohailc .
Any work on this requires #600 to be merged (@nulinspiratie) .
Can be seen as a generalization of channel parameters (#640 #641 ) @spauka .
Relevant for future DCL QuTech drivers @nyxus .
I would like to propose supporting a node/tree based structure for parameters in an instrument.
This is motivated by the need to group certain parameters on a more generic level than channels.
## Motivation
A concrete example would an instrument like the `AWG5014` that has a parameter `ch1_m1_high` (channel 1 marker 1 high). It would be convenient to group parameters in a node structure. This would mean that instead of using underscores in the name of the parameter the instrument would have nodes with attributes, so `ch1_m1_high` would become `ch1.m1.high`.
Such a grouping of parameters would have several advantages.
- Autocomplete of large instruments would be more managable and would immediately show the relevant groups of parameters to a user.
- Possible to natively match structure that exists in many instruments (see e.g., colon separated commands in VISA protocols and the Zurich Instruments python API).
- Possible to add documentation to `nodes` or groups of parameters.
- Provides structure to datafiles (where snapshots are saved).
- Provides structure that can be used in instrument monitoring capabilities.
- I think this is simpler to understand than the Channel parameter (that does not work as per comment in #600 ). This argument requires reading the section below.
## Proposed implementation/required changes
To make the node based parameters work changes are required to the following methods
- `add_parameter`
- `snapshot`
- `print_readable_snapshot`
- datasaving/loading -> especially urgent as that is currently being redesigned.
- A new `parameter_node` object.
- `Instrument.get` and `Instrument.set`
I will now go over these points individually.
### add_parameter
The `Instrument.add_parameter` method would need to support adding parameters to nodes in a simple way. I would propose only changing the way the `name` argument of the `add_parameter` method works.
The name would be split based on the period `.` character (as conventional in python), the last part of the name would be the name of the parameter. Anything before that corresponds to a node.
The example of pseudo code below shows how it should work
```
ins.add_parameter(name='ch1.m1.high', **kwargs)
-> separate string based on period "." character
-> check if ch1 exists as a parameter in the instrument.
-> if ch1 does not exist, create a "node"
-> if ch1 is a regular parameter raise exception
-> if ch1 is a node parameter continue
-> recursively call this "add_node" part until you get to the `parameter` "high", there add the parameter as it is done now.
```
### snapshot
Support a nested structure for the dictionary that contains the parameter nodes with parameters in them.
### print_readable_snapshot
Preserve the nesting in a readable way. To give an example I give below (part of) a snapshot of our VectorSwitchMatrix and how it could look using a nested structure.
```
VSM:
parameter value
--------------------------------------------------------------------------------
IDN : {'driver': " returning the snapshot of the nodes and parameters it contains (this ensures that the higher level snapshots remain working).
- get/set -> see below for how instrument get/set should work.
I'm not sure if a node is more like an instrument (something that can contain parameters) or like a parameter (it can be get/set and is added to an instrument).
### Instrument get/set
The get/set methods should support nested extraction of values. To give an example.
VSM.get('in1.out1.att) should return the nested value.
#### Fancy extensions to get/set
Above I have described the basic idea and functionality that I would like. When working this out it is only natural to think of how the get/set could be made more powerful. I consider this beyond the scope of an initial implementation but as we ( @alan-geller , @sohailc ) discussed them and they could be quite powerful I think it is worth mentioning.
- allow asterix `*` character in get/set commands, setting a value to all parameters that match the description e.g., `VSM.set('in*.out*.switch, 'OFF')` to set all switches to off. Similarly use it to `get` all values that match the description. I would say that the return format should then be a dict containing the full parameter names (including parent nodes) as keys and the return values as values.
- Allow setting using a list or dict of values. An example would be `VSM.set('in1.out*.att', [0, 2]) in which case the 0 and 2 values are mapped to out1 and out2 respectively (sorted alphabetically). Note that it is important ot use a list type here as the parameters are not guaranteed to be single valued.
Contributor guide
Research direction
The issue names Instrument.add_parameter, snapshot, print_readable_snapshot, datasaving/loading, ParameterNode, and Instrument.get/set; start by tracing those entry points and read prerequisite #600 plus related #640 and #641. Done means the proposed node-tree behavior works consistently for parameter creation, access, snapshots, readable output, and persistence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend-api-design, data
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100