Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/channelization: Add channels to instruments #568

Closed
wants to merge 57 commits into from

Conversation

spauka
Copy link
Contributor

@spauka spauka commented Apr 11, 2017

Implements #273

This merge implements channelization in much the way that was discussed in #273, and commits two sample instruments that demonstrate the key features. Briefly, the syntax allows the creation of lists of channels within an instrument and manipulation of those channels. Examples of usage appear at the bottom of the commit.

Changes proposed in this pull request:

For example:

>>> import qcodes as qc
>>> from Harvard.Decadac import Decadac
>>> d = Decadac("DAC", "ASRL4::INSTR")
Connected to Harvard DecaDAC (hw ver: 0, serial: 0) in 0.47s
>>> # Set a single channel
>>> d.channels[0].volt.set(-1)
>>> # Get a single channel
>>> d.channels.volt[0].get()
-1.00006103515625
>>> # Get multiple channels simultaneously
>>> d.channels.volt.get()
(1.00006103515625, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
>>> # Get a subset of channels
>>> d.channels[0:4].volt.get()
(-1.00006103515625, 0.0, 0.0, 0.0)
>>> # Combining different subsets is also possible
>>> fine = d.channels[0:2] + d.channels[4:6]
>>> fine.volt.get()
(-1.00006103515625, 0.0, 0.0, 0.0)
>>> # This also works with measure and loop
>>> qc.Measure(d.channels[0].volt).run()
DataSet:
   location = 'data/2017-04-11/#001_{name}_11-04-36'
   <Type>   | <array_id>           | <array.name> | <array.shape>
   Setpoint | single_set           | single       | (1,)
   Measured | DAC_Slot0_Chan0_volt | volt         | (1,)
acquired at 2017-04-11 11:04:36

Things left

  • Channel metadata is not correctly extracted from an instrument snapshot.
  • Test cases need to be written.

@giulioungaretti

WilliamHPNielsen and others added 8 commits April 11, 2017 10:19
* feat: Add a Keysight_34465A driver

Add a first file for a driver for the Keysight 34465A DMM and a
benchmarking notebook

* Add trigger parameters to driver

Add four trigger parameters to the driver.

* refactor: Remove 'READ?' as volt get_cmd

Make a more general get_cmd for the volt parameter. Using simply 'READ?' is wrong in many cases.

* feat: Add sampling parameters

Add four parameters for sampling.

* fix: Fix wrong volt parameter get_cmd

* WIP: Add Array parameter

* feat: Add functioning data buffer parameter

* Move notebook

* Respond to review
Initial commit of two new classes to allow for channelization of
instruments. This includes ChannelList, a container for channels
in an instrument, and InstrumentChannel which implements a base
class for an instance of a channel.
Add a driver for the Lakeshore Model 336 temperature controller
using new channelization implementation.
Commits a channelized version of the Harvard DecaDAC driver
using the new channelization implementation. Note that this driver
at the present time also fixes a number of open bugs in the previous
driver, including occasional crashes (microsoft#546), incorrectly reading
DAC voltages (microsoft#563), reset (microsoft#478).

This commit also adds a number of new features to the driver
including:
- Feature and version detection
- Access to calibrated high-resolution mode of DAC
- Parameter read from memory
- Validation of writes
Fix bug in slicing/adding code, not correctly passing along
channel list name.
- Removed useless methods
- Whitespace
@giulioungaretti
Copy link
Contributor

@spauka looking great. Did not check in super detail but ticks all the boxes!

I will tag @MerlinSmiles, since he had strong opinions about this as well!

@MerlinSmiles
Copy link
Contributor

@spauka this looks really great! I haven't tested anything on this, but i'm really happy to see this.

What does the 0 in .get(0) do here: ?

>>> # Get a single channel
>>> d.channels.volt[0].get(0)

I have one point that I did not see covered. And that is access to the channels in another notation, (the slicing you show is great, but not the only useful way :)
I'm thinking of the following:
magnet.x.field.get()
The dac is a bit special and I see you split it in slots with 4 channels, that would then be:
d.slot1.ch0.volt.get()
I see a mismatch with the dac.channels you defined in the driver as this list is extended with all the channels. Not sure how to handle this.

One could of course make it on the driver level and define self.x = self.channels['x'] but if that is possible on one instrument I assume it should consistently be possible on many instruments.

Now im thinking of another syntax also:

d.volt.get()
>>>(1,0,0,0...)
```
would also be cool.
But maybe implemented on the driver level as parameters. But again consistency...

@giulioungaretti thanks for tagging, super excited :)

@spauka
Copy link
Contributor Author

spauka commented Apr 11, 2017

@MerlinSmiles For each of your points:

The 0 in .get(0) was a typo. Comments above edited.

Regarding different ways of addressing channels, agreed, there should be a way of having "named" channels. I suspect that the solution I am working on to store channel metadata will solve this, new commits coming soon.

However, I think it also makes sense to keep separate the idea of named and numbered channels, i.e. addressing the DAC as dac.chan0 makes less sense than magnet.x.

For the last syntax d.volt.get(), sounds good, but it doesn't necessarily make sense to break all channel parameters out in this way. Perhaps we can explicitly define such parameters in the instrument?

Anyway, let me know whether the below commits address your points...

@MerlinSmiles
Copy link
Contributor

@spauka totally agree with you!


self._parent = parent
self._name = name
if not isinstance(chan_type, type) != type or not issubclass(chan_type, InstrumentChannel):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can see the first part of this condition will always be True?

not isinstance(chan_type, type) != type -> not bool != type -> not False.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's true. Fixed in a future commit :)

@jenshnielsen
Copy link
Collaborator

@spauka What's the status of this. It would be great to have it land soon. It's a much requested feature. I pointed out a small issue above and there is a conflict in the decadac driver now since we merged #552

@jenshnielsen
Copy link
Collaborator

I'm happy to help writing some of the tests of anything else if you don't have the time

@spauka
Copy link
Contributor Author

spauka commented May 30, 2017

@jenshnielsen sorry, got a bit distracted by other projects for the last few weeks but am currently doing work on implementing snapshotting. Any help you can give on tests would be much appreciated.

spauka added 4 commits May 30, 2017 16:26
Allows certain channel lists to be excluded from snapshots. This is
helpful when, for example, there are multiple ways to access the same
channel.
This feature is implemented by creating the idea of a submodule in the
instrument class. This is just a class which implements the Instrument
class, and may be a channel list or may just implement a logical
collection of parameters within a parent instrument.

For example, looking at the Lakeshore Model_336 driver, each channel can
either be accessed as a member of a channel list, or by using the name
of the channel:
```python3
therm = Model_336("therm", "...")
# These two accesses are equivalent
therm.A.temperature()
therm.channels[0].temperature()
```
@spauka
Copy link
Contributor Author

spauka commented May 30, 2017

Channel lists should now be snapshotable. This is implemented by creating the concept of a submodule in an instrument, where a submodule is just a class that implements the Instrument class.

A side effect of this is that it is now also possible to create sub-instruments, which may be logical groupings of parameters, inside instruments.

To see an example of this, see the Lakeshore.Model_336 driver, wherein temperature channels may be accessed in two ways:

therm = Model_336("therm", "...")
# The below two lines access the same parameter
therm.A.temperature()
therm.channels[0].temperature()
# The next statement evaluates to true
therm.A == therm.channels[0]

@jenshnielsen
Copy link
Collaborator

@spauka Great I will start working on some tests

channels.append(channel)
self.add_submodule(chan_name, channel)
channels.lock()
self.add_submodule("channels", channels)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails for me with TypeError: Submodules must be subclasses of instrument. I guess the check in add_submodule should be a bit more permissive?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are correct, submodules need to be subclasses of Metadatable, Instrument is too restrictive. This is fixed in 4a3e517

spauka and others added 2 commits May 30, 2017 22:33
Submodule objects must be Metadatables at minimum, instrument is too
restrictive for channels.
And error clearly if you try to measure multiple multiparameters
@jenshnielsen
Copy link
Collaborator

Work in progress support for slicing Array parameters and tests are in https://github.com/jenshnielsen/Qcodes/tree/feat/channelization_with_array

Seems to work good but names are currently incorrect for array and multi parameters saved to dataset via loop. (missing channel prefix in names i.e. this and that instead of ChanA_this and ChanA_that and so on

@jenshnielsen
Copy link
Collaborator

I pushed some changes to spauka#2 adding support for ArrayParameters

@jenshnielsen
Copy link
Collaborator

@WilliamHPNielsen is experimenting on porting the QDac driver

@WilliamHPNielsen
Copy link
Contributor

WilliamHPNielsen commented Jun 9, 2017

I added three commits to @jenshnielsen's PR that:

  • Add a channelised QDac driver
  • Add a set method to MultiChannelInstrumentParameter
  • Add a notebook for the channelised QDac

I learned that it could be very de-confusing for some instrument drivers if the channel list could be optionally 1-indexed.

WilliamHPNielsen and others added 5 commits June 12, 2017 13:32
Make the paramclass returned by __getattr__ be customisable.
Add a channelised driver for the QDac. This requires changing the base code
for channels a bit to allow for custom MultiChannelInstrumentParameter
subclasses.
@WilliamHPNielsen
Copy link
Contributor

The QDac driver now contains its own subclass of MultiChannelInstrumentParameter and a change to channels.py that allows for this to happen.

@spauka I think we should merge soon, did you have a chance to look at the Decadac driver?

@WilliamHPNielsen
Copy link
Contributor

PEP8 would be nice, but I think we can merge now. @jenshnielsen ?

@jenshnielsen
Copy link
Collaborator

Yes It would be nice to have spauka#2 merged into this before merging I think

@spauka
Copy link
Contributor Author

spauka commented Jun 15, 2017 via email

Add support for  array parameters to MultiChannelInstrumentParameter
@jenshnielsen
Copy link
Collaborator

Landed via #640 Thank you very much @spauka

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants