From 9166634e13781191701bebe2919b52ae64af3177 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Wed, 17 Feb 2016 18:12:12 +0100 Subject: [PATCH 01/56] first commit of the alazar driver, work in progress --- qcodes/instrument_drivers/AlazarTech/ATS.py | 252 ++++++++++++++++++ .../instrument_drivers/AlazarTech/ATS9870.py | 11 + .../instrument_drivers/AlazarTech/__init__.py | 0 3 files changed, 263 insertions(+) create mode 100644 qcodes/instrument_drivers/AlazarTech/ATS.py create mode 100644 qcodes/instrument_drivers/AlazarTech/ATS9870.py create mode 100644 qcodes/instrument_drivers/AlazarTech/__init__.py diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py new file mode 100644 index 000000000000..12da86e047ae --- /dev/null +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -0,0 +1,252 @@ +import ctypes + +from qcodes.instrument.base import Instrument +from qcodes.instrument.parameter import Parameter + +# TODO logging + +class AlazarTech_ATS(Instrument): + + def __init__(self, name): + super().__init__(name) + # Make sure the dll is located at "C:\\WINDOWS\\System32\\ATSApi" + self._ATS9870_dll = ctypes.cdll.LoadLibrary('C:\\WINDOWS\\System32\\ATSApi') + + # TODO make the board id more general such that more than one card per system configurations are supported + self._handle = self._ATS9870_dll.AlazarGetBoardBySystemID(1, 1) + if not self._handle: + raise Exception("AlazarTech_ATS not found") + + # TODO do something with board kind here + + # TODO is the succes code always 512 (for any board)? + self._succes = 512 + + def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimation=None, coupling=None, + channel_range=None, impedence=None, bwlimit=None, trigger_operation=None, + trigger_engine1=None, trigger_source1=None, trigger_slope1=None, trigger_level1=None, + trigger_engine2=None, trigger_source2=None, trigger_slope2=None, trigger_level2=None, + external_trigger_coupling=None, trigger_range=None, trigger_delay=None, timeout_ticks=None): + + # region set parameters from args + + if clock_source is not None: + self.parameters['clock_source']._set(clock_source) + if sample_rate is not None: + self.parameters['sample_rate']._set(sample_rate) + if clock_edge is not None: + self.parameters['clock_edge']._set(clock_edge) + if decimation is not None: + self.parameters['decimation']._set(decimation) + + if coupling is not None: + for i, v in enumerate(coupling): + self.parameters['coupling'+str(i)]._set(v) + if channel_range is not None: + for i, v in enumerate(channel_range): + self.parameters['range'+str(i)]._set(v) + if impedence is not None: + for i, v in enumerate(impedence): + self.parameters['impedence'+str(i)]._set(v) + if bwlimit is not None: + for i, v in enumerate(bwlimit): + self.parameters['bwlimit'+str(i)]._set(v) + + if trigger_operation is not None: + self.parameters['trigger_operation']._set(trigger_operation) + if trigger_engine1 is not None: + self.parameters['trigger_engine1']._set(trigger_engine1) + if trigger_source1 is not None: + self.parameters['trigger_source1']._set(trigger_source1) + if trigger_slope1 is not None: + self.parameters['trigger_slope1']._set(trigger_slope1) + if trigger_level1 is not None: + self.parameters['trigger_level1']._set(trigger_level1) + + if trigger_engine2 is not None: + self.parameters['trigger_engine2']._set(trigger_engine2) + if trigger_source2 is not None: + self.parameters['trigger_source2']._set(trigger_source2) + if trigger_slope2 is not None: + self.parameters['trigger_slope2']._set(trigger_slope2) + if trigger_level2 is not None: + self.parameters['trigger_level2']._set(trigger_level2) + + if external_trigger_coupling is not None: + self.parameters['external_trigger_coupling']._set(external_trigger_coupling) + if trigger_range is not None: + self.parameters['trigger_range']._set(trigger_range) + if trigger_delay is not None: + self.parameters['trigger_delay']._set(trigger_delay) + if timeout_ticks is not None: + self.parameters['timeout_ticks']._set(timeout_ticks) + # endregion + + return_code = self._ATS9870_dll.AlazarSetCaptureClock(self._handle, + self.parameters['clock_source']._get_byte(), + self.parameters['sample_rate']._get_byte(), + self.parameters['clock_edge']._get_byte(), + self.parameters['decimation']._get_byte()) + self._result_handler(error_code=return_code, error_source="AlazarSetCaptureClock") + self.parameters['clock_source']._set_updated() + self.parameters['sample_rate']._set_updated() + self.parameters['clock_edge']._set_updated() + self.parameters['decimation']._set_updated() + + # TODO some alazar cards have a different number of channels :( + for i in [1, 2]: + return_code = self._ATS9870_dll.AlazarInputControl(self._handle, + i, + self.parameters['coupling'+str(i)]._get_byte(), + self.parameters['range'+str(i)]._get_byte(), + self.parameters['impedence'+str(i)]._get_byte()) + self._result_handler(error_code=return_code, error_source="AlazarInputControl " + str(i)) + self.parameters['coupling'+str(i)]._set_updated() + self.parameters['range'+str(i)]._set_updated() + self.parameters['impedence'+str(i)]._set_updated() + + return_code = self._ATS9870_dll.AlazarSetBWLimit(self._handle, + i, + self.parameters['bwlimit'+str(i)]._get_byte()) + self._result_handler(error_code=return_code, error_source="AlazarSetBWLimit " + str(i)) + self.parameters['bwlimit'+str(i)]._set_updated() + + return_code = self._ATS9870_dll.AlazarSetTriggerOperation(self._handle, + self.parameters['trigger_operation']._get_byte(), + self.parameters['trigger_engine1']._get_byte(), + self.parameters['trigger_source1']._get_byte(), + self.parameters['trigger_slope1']._get_byte(), + self.parameters['trigger_level1']._get_byte(), + self.parameters['trigger_engine2']._get_byte(), + self.parameters['trigger_source2']._get_byte(), + self.parameters['trigger_slope2']._get_byte(), + self.parameters['trigger_level2']._get_byte()) + self._result_handler(error_code=return_code, error_source="AlazarSetTriggerOperation") + self.parameters['trigger_operation']._set_updated() + self.parameters['trigger_engine1']._set_updated() + self.parameters['trigger_source1']._set_updated() + self.parameters['trigger_slope1']._set_updated() + self.parameters['trigger_level1']._set_updated() + self.parameters['trigger_engine2']._set_updated() + self.parameters['trigger_source2']._set_updated() + self.parameters['trigger_slope2']._set_updated() + self.parameters['trigger_level2']._set_updated() + + return_code = self._ATS9870_dll.AlazarSetExternalTrigger(self._handle, + self.parameters['external_trigger_coupling']._get_byte(), + self.parameters['trigger_range']._get_byte()) + self._result_handler(error_code=return_code, error_source="AlazarSetExternalTrigger") + self.parameters['external_trigger_coupling']._set_updated() + self.parameters['trigger_range']._set_updated() + + return_code = self._ATS9870_dll.AlazarSetTriggerDelay(self._handle, + self.parameters['trigger_delay']._get_byte()) + self._result_handler(error_code=return_code, error_source="AlazarSetTriggerDelay") + self.parameters['trigger_delay']._set_updated() + + return_code = self._ATS9870_dll.AlazarSetTriggerTimeOut(self._handle, + self.parameters['timeout_ticks']._get_byte()) + self._result_handler(error_code=return_code, error_source="AlazarSetTriggerTimeOut") + self.parameters['timeout_ticks']._set_updated() + + # TODO config AUXIO + + def _result_handler(self, error_code=0, error_source=""): + # region error codes + error_codes = {513: 'ApiFailed', 514: 'ApiAccessDenied', 515: 'ApiDmaChannelUnavailable', + 516: 'ApiDmaChannelInvalid', 517: 'ApiDmaChannelTypeError', 518: 'ApiDmaInProgress', + 519: 'ApiDmaDone', 520: 'ApiDmaPaused', 521: 'ApiDmaNotPaused', + 522: 'ApiDmaCommandInvalid', 523: 'ApiDmaManReady', 524: 'ApiDmaManNotReady', + 525: 'ApiDmaInvalidChannelPriority', 526: 'ApiDmaManCorrupted', + 527: 'ApiDmaInvalidElementIndex', 528: 'ApiDmaNoMoreElements', + 529: 'ApiDmaSglInvalid', + 530: 'ApiDmaSglQueueFull', 531: 'ApiNullParam', 532: 'ApiInvalidBusIndex', + 533: 'ApiUnsupportedFunction', 534: 'ApiInvalidPciSpace', 535: 'ApiInvalidIopSpace', + 536: 'ApiInvalidSize', 537: 'ApiInvalidAddress', 538: 'ApiInvalidAccessType', + 539: 'ApiInvalidIndex', 540: 'ApiMuNotReady', 541: 'ApiMuFifoEmpty', + 542: 'ApiMuFifoFull', + 543: 'ApiInvalidRegister', 544: 'ApiDoorbellClearFailed', 545: 'ApiInvalidUserPin', + 546: 'ApiInvalidUserState', 547: 'ApiEepromNotPresent', + 548: 'ApiEepromTypeNotSupported', + 549: 'ApiEepromBlank', 550: 'ApiConfigAccessFailed', 551: 'ApiInvalidDeviceInfo', + 552: 'ApiNoActiveDriver', 553: 'ApiInsufficientResources', + 554: 'ApiObjectAlreadyAllocated', + 555: 'ApiAlreadyInitialized', 556: 'ApiNotInitialized', + 557: 'ApiBadConfigRegEndianMode', 558: 'ApiInvalidPowerState', 559: 'ApiPowerDown', + 560: 'ApiFlybyNotSupported', + 561: 'ApiNotSupportThisChannel', 562: 'ApiNoAction', 563: 'ApiHSNotSupported', + 564: 'ApiVPDNotSupported', 565: 'ApiVpdNotEnabled', 566: 'ApiNoMoreCap', + 567: 'ApiInvalidOffset', + 568: 'ApiBadPinDirection', 569: 'ApiPciTimeout', 570: 'ApiDmaChannelClosed', + 571: 'ApiDmaChannelError', 572: 'ApiInvalidHandle', 573: 'ApiBufferNotReady', + 574: 'ApiInvalidData', + 575: 'ApiDoNothing', 576: 'ApiDmaSglBuildFailed', 577: 'ApiPMNotSupported', + 578: 'ApiInvalidDriverVersion', + 579: 'ApiWaitTimeout: operation did not finish during timeout interval. Check your trigger.', + 580: 'ApiWaitCanceled', 581: 'ApiBufferTooSmall', + 582: 'ApiBufferOverflow:rate of acquiring data > rate of transferring data to local memory. Try reducing sample rate, reducing number of enabled channels, increasing size of each DMA buffer or increase number of DMA buffers.', + 583: 'ApiInvalidBuffer', 584: 'ApiInvalidRecordsPerBuffer', + 585: 'ApiDmaPending:Async I/O operation was succesfully started, it will be completed when sufficient trigger events are supplied to fill the buffer.', + 586: 'ApiLockAndProbePagesFailed:Driver or operating system was unable to prepare the specified buffer for DMA transfer. Try reducing buffer size or total number of buffers.', + 587: 'ApiWaitAbandoned', 588: 'ApiWaitFailed', + 589: 'ApiTransferComplete:This buffer is last in the current acquisition.', + 590: 'ApiPllNotLocked:hardware error, contact AlazarTech', + 591: 'ApiNotSupportedInDualChannelMode:Requested number of samples per channel is too large to fit in on-board memory. Try reducing number of samples per channel, or switch to single channel mode.'} + # endregion + if error_code == self._succes: + return None + else: + # TODO log error + + if error_code not in error_codes: + raise KeyError(error_source+" raised unknown error "+str(error_code)) + raise Exception(error_source+" raised "+str(error_code)+": "+error_codes[error_code]) + +class AlazarParameter(Parameter): + def __init__(self, name=None, label=None, unit=None, value=None, byte_to_value_dict=None): + super().__init__(name=name, label=label, unit=unit) + self._byte = None + self._uptodate_flag = True + self._byte_to_value_dict = byte_to_value_dict + # TODO check this line + self._value_to_byte_dict = {v: k for k, v in self._byte_to_value_dict} + + self._set(value) + + def get(self): + """ + This method returns the name of the value set for this parameter + :return: value + """ + # TODO test this exception + if self._uptodate_flag is False: + raise Exception('The value of this parameter is not up to date with the actual value in the instrument.' + '\n Most probable cause is illegal usage of ._set() method of this parameter.' + '\n Don\'t use private methods if you do not know what you are doing!') + return self._byte_to_value_dict[self._byte] + + def _get_byte(self): + """ + this method gets the byte representation of the value of the parameter + :return: byte representation + """ + return self._byte + + def _set(self, value): + """ + This method sets the value of this parameter + This method is private to ensure that all values in the instruments are up to date always + :param value: the new value (e.g. 'NPT', 0.5, ...) + :return: None + """ + + # TODO test this exception handling + if value not in self._value_to_byte_dict: + raise KeyError('Value "'+str(value)+'" unknown setting in parameter "'+str(self.name)+'"') + self._byte = self._value_to_byte_dict[value] + self._uptodate_flag = False + return None + + def _set_updated(self): + self._uptodate_flag = True + diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py new file mode 100644 index 000000000000..41d86bf908f7 --- /dev/null +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -0,0 +1,11 @@ +from .ATS import AlazarTech_ATS + + +class AlazarTech_ATS9870(AlazarTech_ATS): + def __init__(self, name): + super().__init__(name) + # TODO check board kind + # add parameters + # TODO make parameter for board type + + diff --git a/qcodes/instrument_drivers/AlazarTech/__init__.py b/qcodes/instrument_drivers/AlazarTech/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 From 522c3af4b3082e7c33db56659f668130e1d854c9 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Thu, 18 Feb 2016 18:05:41 +0100 Subject: [PATCH 02/56] started work on acquire function, not completed --- qcodes/instrument_drivers/AlazarTech/ATS.py | 180 +++++++++++++++++++- 1 file changed, 179 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 12da86e047ae..8b0d5a337b37 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -1,10 +1,18 @@ import ctypes +import logging +import numpy as np +import os from qcodes.instrument.base import Instrument from qcodes.instrument.parameter import Parameter # TODO logging +# these items are important for generalizing this code to multiple alazar cards +# TODO remove 8 bits per sample requirement +# TODO some alazar cards have a different number of channels :( + + class AlazarTech_ATS(Instrument): def __init__(self, name): @@ -93,7 +101,6 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio self.parameters['clock_edge']._set_updated() self.parameters['decimation']._set_updated() - # TODO some alazar cards have a different number of channels :( for i in [1, 2]: return_code = self._ATS9870_dll.AlazarInputControl(self._handle, i, @@ -151,6 +158,132 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio # TODO config AUXIO + def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, buffers_per_acquisition=None, + channel_selection=None, transfer_offset=None, external_startcapture=None, enable_record_headers=None, + alloc_buffers=None, fifo_only_streaming=None, interleave_samples=None, get_processed_data=None): + # region set parameters from args + if mode is not None: + self.parameters['mode']._set(mode) + if samples_per_record is not None: + self.parameters['samples_per_record']._set(samples_per_record) + if records_per_buffer is not None: + self.parameters['records_per_buffer']._set(records_per_buffer) + if buffers_per_acquisition is not None: + self.parameters['buffers_per_acquisition']._set(buffers_per_acquisition) + if channel_selection is not None: + self.parameters['channel_selection']._set(channel_selection) + if transfer_offset is not None: + self.parameters['transfer_offset']._set(transfer_offset) + if external_startcapture is not None: + self.parameters['external_starcapture']._set(external_startcapture) + if enable_record_headers is not None: + self.parameters['enable_record_headers']._set(enable_record_headers) + if alloc_buffers is not None: + self.parameters['alloc_buffers']._set(alloc_buffers) + if fifo_only_streaming is not None: + self.parameters['fifo_only_streaming']._set(fifo_only_streaming) + if interleave_samples is not None: + self.parameters['interleave_samples']._set(interleave_samples) + if get_processed_data is not None: + self.parameters['get_processed_data']._set(get_processed_data) + + # endregion + + if not (self.parameters['mode'].get() == 'TS' or self.parameters['mode'].get() == 'NPT'): + raise Exception("Only the 'TS' and 'NPT' modes are implemented at this point") + + return_code = self._ATS9870_dll.AlazarAbortAsyncRead(self._handle) + self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") + + # get channel info + bps = np.array([0], dtype=np.uint8) # bps bits per sample + max_s = np.array([0], dtype=np.uint32) # max_s memory size in samples + return_code = self._ATS9870_dll.AlazarGetChannelInfo(self._handle, max_s.ctypes.data, bps.ctypes.data) + self._result_handler(error_code=return_code, error_source="AlazarGetChannelInfo") + bps = bps[0] + max_s = max_s[0] + if not bps == 8: + raise Exception("Only 8 bits per sample supported at this moment") + + if self.parameters['mode'].get() == 'NPT': + pretriggersize = 0 # pretriggersize is 0 for NPT always + post_trigger_size = self.parameters['samples_per_record']._get_byte() + return_code = self._ATS9870_dll.AlazarSetRecordSize(self._handle, pretriggersize, post_trigger_size) + self._result_handler(error_code=return_code, error_source="AlazarSetRecordSize") + + if self.parameters['channel_selection']._get_byte() == 3: + number_of_channels = 2 + else: + number_of_channels = 1 + samples_per_buffer = 0 + acquire_flags = self.parameters['mode']._get_byte() | \ + self.parameters['external_startcapture']._get_byte() | \ + self.parameters['enable_record_headers']._get_byte() | \ + self.parameters['alloc_buffers']._get_byte() | \ + self.parameters['fifo_only_streaming']._get_byte() | \ + self.parameters['interleave_samples']._get_byte() | \ + self.parameters['get_processed_data']._get_byte() + if self.parameters['mode'].get() == 'NPT': + samples_per_record = self.parameters['samples_per_record']._get_byte() + records_per_buffer = self.parameters['records_per_buffer']._get_byte() + records_per_acquisition = records_per_buffer * self.parameters['buffers_per_acquisition']._get_byte() + samples_per_buffer = samples_per_record * records_per_buffer + return_code = self._ATS9870_dll.AlazarBeforeAsyncRead(self._handle, + self.parameters['channel_selection']._get_byte(), + self.parameters['transfer_offset']._get_byte(), + samples_per_record, + records_per_buffer, + records_per_acquisition, + acquire_flags) + self._result_handler(error_code=return_code, error_source="AlazarBeforeAsyncRead") + elif self.parameters['mode'].get() == 'TS': + if not self.parameters['samples_per_record']._get_byte() % self.parameters['buffers_per_acquisition'] == 0: + logging.warning("buffers_per_acquisition is not a divisor of samples per record which it should be in" + " TS mode, rounding down in samples per buffer calculation") + samples_per_buffer = int(self.parameters['samples_per_record']._get_byte() / self.parameters['buffers_per_acquisition']) + buffers_per_acquisition = self.parameters['buffers_per_acquisition']._get_byte() + if not self.parameters['records_per_buffer']._get_byte() == 1: + logging.warning('records_per_buffer should be 1 in TS mode, defauling to 1') + self.parameters['records_per_buffer']._set(1) + records_per_buffer = self.parameters['records_per_buffer']._get_byte() + return_code = self._ATS9870_dll.AlazarBeforeAsyncRead(self._handle, + self.parameters['channel_selection']._get_byte(), + self.parameters['transfer_offset']._get_byte(), + samples_per_buffer, + records_per_buffer, + buffers_per_acquisition, + acquire_flags) + self._result_handler(error_code=return_code, error_source="AlazarBeforeAsyncRead") + self.parameters['samples_per_record']._set_updated() + self.parameters['records_per_buffer']._set_updated() + self.parameters['buffers_per_acquisition']._set_updated() + self.parameters['channel_selection']._set_updated() + self.parameters['transfer_offset']._set_updated() + self.parameters['mode']._set_updated() + self.parameters['external_starcapture']._set_updated() + self.parameters['enable_record_headers']._set_updated() + self.parameters['alloc_buffers']._set_updated() + self.parameters['fifo_only_streaming']._set_updated() + self.parameters['interleave_samples']._set_updated() + self.parameters['get_processed_data']._set_updated() + + for buf in self.buflist: + return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) + self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") + + return_code = self._ATS9870_dll.AlazarStartCapture(self._handle) + self._result_handler(error_code=return_code, error_source="AlazarStartCapture") + + while BuffersCompleted < BuffersPerAcquisition: + return_code = self._ATS9870_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, self.waittimeout) + self._result_handler(error_code=return_code, error_source="AlazarWaitAsyncBufferComplete") + + return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) + self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") + + return_code = self._ATS9870_dll.AlazarAbortAsyncRead(self._handle) + self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") + def _result_handler(self, error_code=0, error_source=""): # region error codes error_codes = {513: 'ApiFailed', 514: 'ApiAccessDenied', 515: 'ApiDmaChannelUnavailable', @@ -202,8 +335,11 @@ def _result_handler(self, error_code=0, error_source=""): raise KeyError(error_source+" raised unknown error "+str(error_code)) raise Exception(error_source+" raised "+str(error_code)+": "+error_codes[error_code]) + class AlazarParameter(Parameter): def __init__(self, name=None, label=None, unit=None, value=None, byte_to_value_dict=None): + # TODO implement trivial dictionary + # TODO implement restrictions for trivial dictionary case super().__init__(name=name, label=label, unit=unit) self._byte = None self._uptodate_flag = True @@ -250,3 +386,45 @@ def _set(self, value): def _set_updated(self): self._uptodate_flag = True + +class Buffer: + def __init__(self, bits_per_sample, samples_per_buffer, number_of_channels): + if not bits_per_sample == 8: + raise Exception("Buffer: only 8 bit per sample supported") + if not os.name == 'nt': + raise Exception("Buffer: only Windows supported at this moment") + self._allocated = True + + # try to allocate memory + mem_commit = 0x1000 + page_readwrite = 0x4 + + size_bytes = samples_per_buffer * number_of_channels + + # please see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx for documentation + ctypes.windll.kernel32.VirtualAlloc.argtypes = [ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long] + ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p + self.addr = ctypes.windll.kernel32.VirtualAlloc(0, ctypes.c_long(size_bytes), mem_commit, page_readwrite) + if self.addr is None: + self._allocated = False + e = ctypes.windll.kernel32.GetLastError() + raise Exception("Memory allocation error: " + str(e)) + + ctypes_array = (ctypes.c_uint8 * size_bytes).from_address(self.addr) + self.buffer = np.frombuffer(ctypes_array, dtype=np.uint8) + pointer, read_only_flag = self.buffer.__array_interface__['data'] + + def free_mem(self): + mem_release = 0x8000 + + # see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366892(v=vs.85).aspx + ctypes.windll.kernel32.VirtualFree.argtypes = [ctypes.c_void_p, ctypes.c_long, ctypes.c_long] + ctypes.windll.kernel32.VirtualFree.restype = ctypes.c_int + ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(self.addr), 0, mem_release) + self._allocated = False + + def __del__(self): + if self._allocated: + self.free_mem() + logging.warning("Buffer prevented memory leak; Memory released to Windows.\n" + "Memory should have been released before buffer was deleted.") From b364da918cced36d9a7d03871a5d62032a7b8277 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Wed, 9 Mar 2016 14:51:40 +0100 Subject: [PATCH 03/56] finished acquire method (still untested) --- qcodes/instrument_drivers/AlazarTech/ATS.py | 76 +++++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 8b0d5a337b37..b56a9307e8d4 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -12,6 +12,9 @@ # TODO remove 8 bits per sample requirement # TODO some alazar cards have a different number of channels :( +# TODO tests to do: +# acquisition that would overflow the board if measurement is not stopped quicmly enough +# can this be solved by not reposting the buffers? class AlazarTech_ATS(Instrument): @@ -29,6 +32,7 @@ def __init__(self, name): # TODO is the succes code always 512 (for any board)? self._succes = 512 + self.buffer_list = [] def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimation=None, coupling=None, channel_range=None, impedence=None, bwlimit=None, trigger_operation=None, @@ -160,7 +164,8 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, buffers_per_acquisition=None, channel_selection=None, transfer_offset=None, external_startcapture=None, enable_record_headers=None, - alloc_buffers=None, fifo_only_streaming=None, interleave_samples=None, get_processed_data=None): + alloc_buffers=None, fifo_only_streaming=None, interleave_samples=None, get_processed_data=None, + allocated_buffers=None, buffer_timeout = None): # region set parameters from args if mode is not None: self.parameters['mode']._set(mode) @@ -186,12 +191,19 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b self.parameters['interleave_samples']._set(interleave_samples) if get_processed_data is not None: self.parameters['get_processed_data']._set(get_processed_data) + if allocated_buffers is not None: + self.parameters['allocated_buffers']._set(allocated_buffers) + if buffer_timeout is not None: + self.parameters['buffer_timeout']._set(buffer_timeout) # endregion if not (self.parameters['mode'].get() == 'TS' or self.parameters['mode'].get() == 'NPT'): raise Exception("Only the 'TS' and 'NPT' modes are implemented at this point") + # -----set final configurations----- + + # Abort any previous measurement return_code = self._ATS9870_dll.AlazarAbortAsyncRead(self._handle) self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") @@ -205,12 +217,15 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b if not bps == 8: raise Exception("Only 8 bits per sample supported at this moment") + # Set record size for NPT mode if self.parameters['mode'].get() == 'NPT': pretriggersize = 0 # pretriggersize is 0 for NPT always post_trigger_size = self.parameters['samples_per_record']._get_byte() return_code = self._ATS9870_dll.AlazarSetRecordSize(self._handle, pretriggersize, post_trigger_size) self._result_handler(error_code=return_code, error_source="AlazarSetRecordSize") + + # set acquisition parameters here for NPT, TS mode if self.parameters['channel_selection']._get_byte() == 3: number_of_channels = 2 else: @@ -267,23 +282,67 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b self.parameters['interleave_samples']._set_updated() self.parameters['get_processed_data']._set_updated() - for buf in self.buflist: + # create buffers for acquisition + self.clear_buffers() + for k in range(self.parameters['allocated_buffers']._get_byte()): + try: + self.buffer_list.append(Buffer(bps, samples_per_buffer, number_of_channels)) + except: + self.clear_buffers() + raise + + # post buffers to Alazar + for buf in self.buffer_list: return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") + self.parameters['allocated_buffers']._set_updated() + # -----start capture here----- + + # call the startcapture method return_code = self._ATS9870_dll.AlazarStartCapture(self._handle) self._result_handler(error_code=return_code, error_source="AlazarStartCapture") - while BuffersCompleted < BuffersPerAcquisition: - return_code = self._ATS9870_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, self.waittimeout) + # buffer handling from acquisition + buffers_completed = 0 + buffer_timeout = self.parameters['buffer_timeout']._get_byte() + self.parameters['buffer_timeout']._set_updated() + + buffer_recycling = False + if self.parameters['buffers_per_acquisition']._get_byte()> self.parameters['allocated_buffers']._get_byte(): + buffer_recycling = True + + while buffers_completed < self.parameters['buffers_per_acquisition']._get_byte(): + buf = self.buflist[buffers_completed % self.parameters['allocated_buffers']._get_byte()] + + return_code = self._ATS9870_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, buffer_timeout) self._result_handler(error_code=return_code, error_source="AlazarWaitAsyncBufferComplete") - return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) - self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") + # if buffers must be recycled, extract data and repost them + # otherwise continue to next buffer + if buffer_recycling: + # TODO handle data here + + return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) + self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") + buffers_completed += 1 + # stop measurement here return_code = self._ATS9870_dll.AlazarAbortAsyncRead(self._handle) self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") + # -----cleanup here----- + # extract data if not yet done + if not buffer_recycling: + # TODO handle data here + pass + + # free up memory + self.clear_buffers() + + #return result + return None + def _result_handler(self, error_code=0, error_source=""): # region error codes error_codes = {513: 'ApiFailed', 514: 'ApiAccessDenied', 515: 'ApiDmaChannelUnavailable', @@ -335,6 +394,11 @@ def _result_handler(self, error_code=0, error_source=""): raise KeyError(error_source+" raised unknown error "+str(error_code)) raise Exception(error_source+" raised "+str(error_code)+": "+error_codes[error_code]) + def clear_buffers(self): + for b in self.buffer_list: + b.free_mem() + self.buffer_list = [] + class AlazarParameter(Parameter): def __init__(self, name=None, label=None, unit=None, value=None, byte_to_value_dict=None): From 665901a3aacb3edd9cfd1de456f1a8ff4acfacde Mon Sep 17 00:00:00 2001 From: damazdejong Date: Thu, 10 Mar 2016 18:41:54 +0100 Subject: [PATCH 04/56] typo and added idea in comments --- qcodes/instrument_drivers/AlazarTech/ATS.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index b56a9307e8d4..c33dca88cef0 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -313,13 +313,17 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b buffer_recycling = True while buffers_completed < self.parameters['buffers_per_acquisition']._get_byte(): - buf = self.buflist[buffers_completed % self.parameters['allocated_buffers']._get_byte()] + buf = self.buffer_list[buffers_completed % self.parameters['allocated_buffers']._get_byte()] return_code = self._ATS9870_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, buffer_timeout) self._result_handler(error_code=return_code, error_source="AlazarWaitAsyncBufferComplete") + # TODO last series of buffers must be handled exceptionally (and I want to test the difference) + # TODO by changing buffer recycling for the last series of buffers + # if buffers must be recycled, extract data and repost them # otherwise continue to next buffer + if buffer_recycling: # TODO handle data here From 2637f513f0e6612eab7909623588d55a3dd1f033 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Thu, 24 Mar 2016 22:03:58 +0100 Subject: [PATCH 05/56] the ATS parent class should work now. It is still untested, but all the code and structure is written. More functions would be nice and several todo items are important before actual implementation --- qcodes/instrument_drivers/AlazarTech/ATS.py | 92 +++++++++++++++------ 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index c33dca88cef0..8a8fc04bc0c4 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -6,13 +6,13 @@ from qcodes.instrument.base import Instrument from qcodes.instrument.parameter import Parameter -# TODO logging +# TODO (C) logging # these items are important for generalizing this code to multiple alazar cards -# TODO remove 8 bits per sample requirement -# TODO some alazar cards have a different number of channels :( +# TODO (W) remove 8 bits per sample requirement +# TODO (W) some alazar cards have a different number of channels :( -# TODO tests to do: +# TODO (S) tests to do: # acquisition that would overflow the board if measurement is not stopped quicmly enough # can this be solved by not reposting the buffers? @@ -23,14 +23,14 @@ def __init__(self, name): # Make sure the dll is located at "C:\\WINDOWS\\System32\\ATSApi" self._ATS9870_dll = ctypes.cdll.LoadLibrary('C:\\WINDOWS\\System32\\ATSApi') - # TODO make the board id more general such that more than one card per system configurations are supported + # TODO (W) make the board id more general such that more than one card per system configurations are supported self._handle = self._ATS9870_dll.AlazarGetBoardBySystemID(1, 1) if not self._handle: raise Exception("AlazarTech_ATS not found") - # TODO do something with board kind here + # TODO (M) do something with board kind here - # TODO is the succes code always 512 (for any board)? + # TODO (S) is the succes code always 512 (for any board)? self._succes = 512 self.buffer_list = [] @@ -160,12 +160,12 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio self._result_handler(error_code=return_code, error_source="AlazarSetTriggerTimeOut") self.parameters['timeout_ticks']._set_updated() - # TODO config AUXIO + # TODO (W) config AUXIO def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, buffers_per_acquisition=None, channel_selection=None, transfer_offset=None, external_startcapture=None, enable_record_headers=None, alloc_buffers=None, fifo_only_streaming=None, interleave_samples=None, get_processed_data=None, - allocated_buffers=None, buffer_timeout = None): + allocated_buffers=None, buffer_timeout=None, acquisition_controller=None): # region set parameters from args if mode is not None: self.parameters['mode']._set(mode) @@ -298,18 +298,19 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b self.parameters['allocated_buffers']._set_updated() # -----start capture here----- - + acquisition_controller.pre_start_capture(self) # call the startcapture method return_code = self._ATS9870_dll.AlazarStartCapture(self._handle) self._result_handler(error_code=return_code, error_source="AlazarStartCapture") + acquisition_controller.pre_acquire(self) # buffer handling from acquisition buffers_completed = 0 buffer_timeout = self.parameters['buffer_timeout']._get_byte() self.parameters['buffer_timeout']._set_updated() buffer_recycling = False - if self.parameters['buffers_per_acquisition']._get_byte()> self.parameters['allocated_buffers']._get_byte(): + if self.parameters['buffers_per_acquisition']._get_byte() > self.parameters['allocated_buffers']._get_byte(): buffer_recycling = True while buffers_completed < self.parameters['buffers_per_acquisition']._get_byte(): @@ -318,15 +319,14 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b return_code = self._ATS9870_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, buffer_timeout) self._result_handler(error_code=return_code, error_source="AlazarWaitAsyncBufferComplete") - # TODO last series of buffers must be handled exceptionally (and I want to test the difference) - # TODO by changing buffer recycling for the last series of buffers + # TODO (C) last series of buffers must be handled exceptionally (and I want to test the difference) + # TODO (C) by changing buffer recycling for the last series of buffers # if buffers must be recycled, extract data and repost them # otherwise continue to next buffer if buffer_recycling: - # TODO handle data here - + acquisition_controller.handle_buffer(self, buf.buffer) return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") buffers_completed += 1 @@ -338,14 +338,14 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b # -----cleanup here----- # extract data if not yet done if not buffer_recycling: - # TODO handle data here - pass + for buf in self.buffer_list: + acquisition_controller.handle_buffer(self, buf.buffer) # free up memory self.clear_buffers() - #return result - return None + # return result + return acquisition_controller.post_acquire(self) def _result_handler(self, error_code=0, error_source=""): # region error codes @@ -392,7 +392,7 @@ def _result_handler(self, error_code=0, error_source=""): if error_code == self._succes: return None else: - # TODO log error + # TODO (C) log error if error_code not in error_codes: raise KeyError(error_source+" raised unknown error "+str(error_code)) @@ -406,13 +406,13 @@ def clear_buffers(self): class AlazarParameter(Parameter): def __init__(self, name=None, label=None, unit=None, value=None, byte_to_value_dict=None): - # TODO implement trivial dictionary - # TODO implement restrictions for trivial dictionary case + # TODO (M) implement trivial dictionary + # TODO (M) implement restrictions for trivial dictionary case super().__init__(name=name, label=label, unit=unit) self._byte = None self._uptodate_flag = True self._byte_to_value_dict = byte_to_value_dict - # TODO check this line + # TODO (M) check this line self._value_to_byte_dict = {v: k for k, v in self._byte_to_value_dict} self._set(value) @@ -422,9 +422,10 @@ def get(self): This method returns the name of the value set for this parameter :return: value """ - # TODO test this exception + # TODO (S) test this exception if self._uptodate_flag is False: - raise Exception('The value of this parameter is not up to date with the actual value in the instrument.' + raise Exception('The value of this parameter (' + str(self.name) + ') is not up to date with the actual ' + 'value in the instrument.' '\n Most probable cause is illegal usage of ._set() method of this parameter.' '\n Don\'t use private methods if you do not know what you are doing!') return self._byte_to_value_dict[self._byte] @@ -444,7 +445,7 @@ def _set(self, value): :return: None """ - # TODO test this exception handling + # TODO (S) test this exception handling if value not in self._value_to_byte_dict: raise KeyError('Value "'+str(value)+'" unknown setting in parameter "'+str(self.name)+'"') self._byte = self._value_to_byte_dict[value] @@ -496,3 +497,42 @@ def __del__(self): self.free_mem() logging.warning("Buffer prevented memory leak; Memory released to Windows.\n" "Memory should have been released before buffer was deleted.") + + +class AcquisitionController: + def __init__(self): + """ + :return: nothing + """ + pass + + def pre_start_capture(self, alazar): + """ + + :param alazar: + :return: + """ + raise NotImplementedError("This method should be implemented in the implementation") + + def pre_acquire(self, alazar): + """ + Use this method to prepare yourself for the data acquisition + :param alazar: a reference to the alazar driver + :return: nothing + """ + raise NotImplementedError("This method should be implemented in the implementation") + + def handle_buffer(self, alazar, buffer): + """ + :param buffer: np.array with the data from the alazar card + :return: something, it is ignored in any case + """ + raise NotImplementedError( + "This method should be implemented in the implementation of the AcquisitionController class") + + def post_acquire(self, alazar): + """ + :param alazar: a reference to the alazar driver + :return: this function should return all relevant data that you want to get form the acquisition + """ + raise NotImplementedError("This method should be implemented somewhere") \ No newline at end of file From 00c03ec129f3dc8a0f30a0b0a578cc48ba3eeac7 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Thu, 24 Mar 2016 22:44:22 +0100 Subject: [PATCH 06/56] added signal_to_volt and get_sample_speed --- qcodes/instrument_drivers/AlazarTech/ATS.py | 27 ++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 8a8fc04bc0c4..78e22e31ee14 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -16,6 +16,7 @@ # acquisition that would overflow the board if measurement is not stopped quicmly enough # can this be solved by not reposting the buffers? + class AlazarTech_ATS(Instrument): def __init__(self, name): @@ -35,7 +36,7 @@ def __init__(self, name): self.buffer_list = [] def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimation=None, coupling=None, - channel_range=None, impedence=None, bwlimit=None, trigger_operation=None, + channel_range=None, impedance=None, bwlimit=None, trigger_operation=None, trigger_engine1=None, trigger_source1=None, trigger_slope1=None, trigger_level1=None, trigger_engine2=None, trigger_source2=None, trigger_slope2=None, trigger_level2=None, external_trigger_coupling=None, trigger_range=None, trigger_delay=None, timeout_ticks=None): @@ -57,9 +58,9 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio if channel_range is not None: for i, v in enumerate(channel_range): self.parameters['range'+str(i)]._set(v) - if impedence is not None: - for i, v in enumerate(impedence): - self.parameters['impedence'+str(i)]._set(v) + if impedance is not None: + for i, v in enumerate(impedance): + self.parameters['impedance'+str(i)]._set(v) if bwlimit is not None: for i, v in enumerate(bwlimit): self.parameters['bwlimit'+str(i)]._set(v) @@ -110,11 +111,11 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio i, self.parameters['coupling'+str(i)]._get_byte(), self.parameters['range'+str(i)]._get_byte(), - self.parameters['impedence'+str(i)]._get_byte()) + self.parameters['impedance'+str(i)]._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarInputControl " + str(i)) self.parameters['coupling'+str(i)]._set_updated() self.parameters['range'+str(i)]._set_updated() - self.parameters['impedence'+str(i)]._set_updated() + self.parameters['impedance'+str(i)]._set_updated() return_code = self._ATS9870_dll.AlazarSetBWLimit(self._handle, i, @@ -344,6 +345,10 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b # free up memory self.clear_buffers() + # check if all parameters are up to date + for p in self.parameters: + p.get() + # return result return acquisition_controller.post_acquire(self) @@ -403,6 +408,16 @@ def clear_buffers(self): b.free_mem() self.buffer_list = [] + def signal_to_volt(self, channel, signal): + # TODO (S) check this + return ((signal - 127.5) / 127.5) * (self.parameters["range" + str(channel)]) + + def get_sample_speed(self): + if self.parameters["decimation"] > 0: + return self.parameters["sample_rate"] / self.parameters["decimation"] + else: + return self.parameters["sample_rate"] + class AlazarParameter(Parameter): def __init__(self, name=None, label=None, unit=None, value=None, byte_to_value_dict=None): From 8694caaaf543c05f41cbe63de7f604bd0c9f3f85 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Thu, 24 Mar 2016 22:44:55 +0100 Subject: [PATCH 07/56] added file with acquisitioncontroller example --- .../AlazarTech/ATS_acquisition_controllers.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py new file mode 100644 index 000000000000..b04739c646c9 --- /dev/null +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -0,0 +1,68 @@ +from .ATS import AcquisitionController +import math +import numpy as np + + +# DFT AcquisitionController +class DFT_AcquisitionController(AcquisitionController): + def __init__(self, demodulation_frequency, samples_per_record, records_per_buffer, buffers_per_acquisition): + self.demodulation_frequency = demodulation_frequency + self.samples_per_record = samples_per_record + self.records_per_buffer = records_per_buffer + self.buffers_per_acquisition = buffers_per_acquisition + # TODO (S) this is not very general: + self.number_of_channels = 2 + self.cos_list = None + self.sin_list = None + self.buffer = None + + def pre_start_capture(self, alazar): + sample_speed = alazar.get_sample_speed() + integer_list = np.arange(self.samples_per_record) + + self.cos_list = np.cos(2 * np.pi * self.demodulation_frequency / sample_speed * integer_list) + self.sin_list = np.sin(2 * np.pi * self.demodulation_frequency / sample_speed * integer_list) + self.buffer = np.zeros(self.samples_per_record * self.records_per_buffer * self.number_of_channels) + + def pre_acquire(self, alazar): + # this could be used to start an Arbitrary Waveform Generator, etc... + # using this method ensures that the contents are executed AFTER the Alazar card starts listening for a + # trigger pulse + pass + + def handle_buffer(self, alazar, data): + self.buffer += data + + def post_acquire(self, alazar): + # average all records in a buffer + recordA = np.zeros(self.samples_per_record) + for i in range(self.records_per_buffer): + recordA += self.buffer[i * self.samples_per_record: (i + 1) * self.samples_per_record] / ( + 1. * self.buffers_per_acquisition * self.records_per_buffer) + + recordB = np.zeros(self.samples_per_record) + for i in range(self.records_per_buffer): + recordB += self.buffer[ + i * self.samples_per_record + len(self.buffer) / 2: (i + 1) * self.samples_per_record + len( + self.buffer) / 2] / (1. * self.buffers_per_acquisition * self.records_per_buffer) + + if self.number_of_channels == 2: + # fit channel A and channel B + res1 = self.fit(recordA) + res2 = self.fit(recordB) + return [alazar.signal_to_volt(0, res1[0] + 127.5), alazar.signal_to_volt(1, res2[0] + 127.5), res1[1], res2[1], + (res1[1] - res2[1]) % 360] + else: + raise Exception("Could not find CHANNEL_B during data extraction") + return None + + def fit(self, buf): + # Discrete Fourier Transform + RePart = np.dot(buf - 127.5, self.cos_list) / float(self.samples_per_record) + ImPart = np.dot(buf - 127.5, self.sin_list) / float(self.samples_per_record) + + # the factor of 2 in the amplitude is due to the fact that there is a negative frequency as well + ampl = 2 * np.sqrt(RePart ** 2 + ImPart ** 2) + + # see manual page 52!!! (using unsigned data) + return [ampl, math.atan2(ImPart, RePart) * 360 / (2 * math.pi)] From ae1d458ae4f9c126bb7b63d1389429b48c4b7710 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Thu, 24 Mar 2016 22:45:16 +0100 Subject: [PATCH 08/56] added preliminary list of parameters to add --- .../instrument_drivers/AlazarTech/ATS9870.py | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 41d86bf908f7..a4e8e555b8d4 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -4,8 +4,44 @@ class AlazarTech_ATS9870(AlazarTech_ATS): def __init__(self, name): super().__init__(name) - # TODO check board kind + # TODO (M) check board kind # add parameters - # TODO make parameter for board type + # TODO (M) make parameter for board type + +# -----config----- +# clock source +# sample_rate +# clock_edge +# decimation +# +# coupling{n} +# range{n} +# impedence{n} +# bwlimit{n} +# +# trigger_operation +# trigger_engine1 +# trigger_source1 +# trigger_slope1 +# trigger_level1 +# trigger_engine2 +# trigger_source2 +# trigger_slope2 +# trigger_level2 +# +# external_trigger_coupling +# trigger_range +# +# trigger_delay +# timeout_ticks +# +# ----acquire----- +# mode +# samples_per_record +# channel_selection +# +# more !? +# +# nbuffers From 53e65ec96b1cf1579329cfc69466053fa54c197b Mon Sep 17 00:00:00 2001 From: damazdejong Date: Thu, 24 Mar 2016 23:10:19 +0100 Subject: [PATCH 09/56] the __init__ of this driver now works, fixed some small errors --- qcodes/instrument_drivers/AlazarTech/ATS.py | 5 +++-- qcodes/instrument_drivers/AlazarTech/ATS9870.py | 13 ++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 78e22e31ee14..02aed75399c3 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -420,15 +420,16 @@ def get_sample_speed(self): class AlazarParameter(Parameter): - def __init__(self, name=None, label=None, unit=None, value=None, byte_to_value_dict=None): + def __init__(self, name=None, label=None, unit=None, instrument=None, value=None, byte_to_value_dict=None): # TODO (M) implement trivial dictionary # TODO (M) implement restrictions for trivial dictionary case super().__init__(name=name, label=label, unit=unit) + self.intstrument = instrument self._byte = None self._uptodate_flag = True self._byte_to_value_dict = byte_to_value_dict # TODO (M) check this line - self._value_to_byte_dict = {v: k for k, v in self._byte_to_value_dict} + self._value_to_byte_dict = {v: k for k, v in self._byte_to_value_dict.items()} self._set(value) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index a4e8e555b8d4..52cdffafa61d 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -1,15 +1,22 @@ -from .ATS import AlazarTech_ATS +from .ATS import AlazarTech_ATS, AlazarParameter class AlazarTech_ATS9870(AlazarTech_ATS): def __init__(self, name): super().__init__(name) - # TODO (M) check board kind # add parameters + + self.add_parameter(name='clock_source', parameter_class=AlazarParameter, label='Clock Source', unit=None, + value='EXTERNAL_CLOCK_10_MHz_REF', + byte_to_value_dict={1: 'INTERNAL_CLOCK', + 4: 'SLOW_EXTERNAL_CLOCK', + 5: 'EXTERNAL_CLOCK_AC', + 7: 'EXTERNAL_CLOCK_10_MHz_REF'}) # TODO (M) make parameter for board type + # TODO (M) check board kind + # -----config----- -# clock source # sample_rate # clock_edge # decimation From 0c91e8be0246c5a054079c93d9783127ea108a29 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Mon, 28 Mar 2016 22:25:36 +0200 Subject: [PATCH 10/56] implemented validations of values and automate the guessing of validators to validate that the value is in the values of the dictionary. The driver now calls the validate function of the parameter class to enforce this validation. Solved the problem with sample rates changed the default of some parameters implemented trivial dictionaries. Driver still largely untested --- qcodes/instrument_drivers/AlazarTech/ATS.py | 60 ++++++++++++++----- .../instrument_drivers/AlazarTech/ATS9870.py | 25 +++++++- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 02aed75399c3..2106bd9718c3 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -5,6 +5,7 @@ from qcodes.instrument.base import Instrument from qcodes.instrument.parameter import Parameter +from qcodes.utils import validators # TODO (C) logging @@ -410,26 +411,46 @@ def clear_buffers(self): def signal_to_volt(self, channel, signal): # TODO (S) check this + # TODO (M) use byte value if range{channel} return ((signal - 127.5) / 127.5) * (self.parameters["range" + str(channel)]) def get_sample_speed(self): + if self.parameters['sample_rate'] == 'EXTERNAL_CLOCK': + raise Exception('External clock is used, alazar driver could not determine sample speed.') + + rate = 0 + if self.parameters['sample_rate'] == '1GHz_REFERENCE_CLOCK': + rate = 1e9 + else: + rate = self.parameters['sample_rate'] + if self.parameters["decimation"] > 0: - return self.parameters["sample_rate"] / self.parameters["decimation"] + return rate / self.parameters["decimation"] else: - return self.parameters["sample_rate"] + return rate class AlazarParameter(Parameter): - def __init__(self, name=None, label=None, unit=None, instrument=None, value=None, byte_to_value_dict=None): - # TODO (M) implement trivial dictionary - # TODO (M) implement restrictions for trivial dictionary case - super().__init__(name=name, label=label, unit=unit) - self.intstrument = instrument + def __init__(self, name=None, label=None, unit=None, instrument=None, value=None, byte_to_value_dict=None, vals=None): + if vals is None: + if byte_to_value_dict is None: + vals = validators.Anything() + else: + # TODO (S) test this validator + vals = validators.Enum(byte_to_value_dict.values()) + + super().__init__(name=name, label=label, unit=unit, vals=vals) + self.instrument = instrument self._byte = None self._uptodate_flag = True - self._byte_to_value_dict = byte_to_value_dict - # TODO (M) check this line - self._value_to_byte_dict = {v: k for k, v in self._byte_to_value_dict.items()} + + # TODO (M) check this block + if byte_to_value_dict is None: + self._byte_to_value_dict = TrivialDictionary() + self._value_to_byte_dict = TrivialDictionary() + else: + self._byte_to_value_dict = byte_to_value_dict + self._value_to_byte_dict = {v: k for k, v in self._byte_to_value_dict.items()} self._set(value) @@ -461,9 +482,8 @@ def _set(self, value): :return: None """ - # TODO (S) test this exception handling - if value not in self._value_to_byte_dict: - raise KeyError('Value "'+str(value)+'" unknown setting in parameter "'+str(self.name)+'"') + # TODO (S) test this validation + self.validate(value) self._byte = self._value_to_byte_dict[value] self._uptodate_flag = False return None @@ -551,4 +571,16 @@ def post_acquire(self, alazar): :param alazar: a reference to the alazar driver :return: this function should return all relevant data that you want to get form the acquisition """ - raise NotImplementedError("This method should be implemented somewhere") \ No newline at end of file + raise NotImplementedError("This method should be implemented somewhere") + + +class TrivialDictionary: + def __init__(self): + pass + + def __getitem__(self, item): + return item + + def __contains__(self, item): + # this makes sure that this dictionary contains everything + return True \ No newline at end of file diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 52cdffafa61d..a552647d31a9 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -1,5 +1,5 @@ from .ATS import AlazarTech_ATS, AlazarParameter - +from qcodes.utils import validators class AlazarTech_ATS9870(AlazarTech_ATS): def __init__(self, name): @@ -7,11 +7,30 @@ def __init__(self, name): # add parameters self.add_parameter(name='clock_source', parameter_class=AlazarParameter, label='Clock Source', unit=None, - value='EXTERNAL_CLOCK_10_MHz_REF', + value='INTERNAL_CLOCK', byte_to_value_dict={1: 'INTERNAL_CLOCK', 4: 'SLOW_EXTERNAL_CLOCK', 5: 'EXTERNAL_CLOCK_AC', 7: 'EXTERNAL_CLOCK_10_MHz_REF'}) + self.add_parameter(name='sample_rate', parameter_class=AlazarParameter, label='Sample Rate', unit='S/s', + value=1000000000, + byte_to_value_dict={0x1: 1000, 0x2: 2000, 0x4: 5000, + 0x8: 10000, 0xA: 20000, 0xC: 50000, + 0xE: 100000, 0x10: 200000, 0x12: 500000, + 0x14: 1000000, 0x18: 2000000, 0x1A: 5000000, + 0x1C: 10000000, 0x1E: 20000000, 0x22: 50000000, + 0x24: 100000000, 0x2B: 250000000, 0x30: 500000000, + 0x35: 1000000000, + 0x40: 'EXTERNAL_CLOCK', + 1000000000: '1GHz_REFERENCE_CLOCK'}) + self.add_parameter(name='clock_edge', parameter_class=AlazarParameter, label='Clock Edge', unit=None, + value='CLOCK_EDGE_RISING', + byte_to_value_dict={0: 'CLOCK_EDGE_RISING', + 1: 'CLOCK_EDGE_FALLING'}) + + self.add_parameter(name='decimation', parameter_class=AlazarParameter, label='Decimation', unit=None, + value=0, vals=validators.Ints(0, 100000)) + # TODO (M) make parameter for board type # TODO (M) check board kind @@ -23,7 +42,7 @@ def __init__(self, name): # # coupling{n} # range{n} -# impedence{n} +# impedance{n} # bwlimit{n} # # trigger_operation From 888b01ee04e4087bd6c60f54504ff2ef0b1053d1 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Mon, 28 Mar 2016 23:16:41 +0200 Subject: [PATCH 11/56] rename trigger_range to external_trigger_range --- qcodes/instrument_drivers/AlazarTech/ATS.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 2106bd9718c3..a014f22e30d5 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -12,6 +12,7 @@ # these items are important for generalizing this code to multiple alazar cards # TODO (W) remove 8 bits per sample requirement # TODO (W) some alazar cards have a different number of channels :( +# this ddrive ronly works with 2-channel cards # TODO (S) tests to do: # acquisition that would overflow the board if measurement is not stopped quicmly enough @@ -40,7 +41,7 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio channel_range=None, impedance=None, bwlimit=None, trigger_operation=None, trigger_engine1=None, trigger_source1=None, trigger_slope1=None, trigger_level1=None, trigger_engine2=None, trigger_source2=None, trigger_slope2=None, trigger_level2=None, - external_trigger_coupling=None, trigger_range=None, trigger_delay=None, timeout_ticks=None): + external_trigger_coupling=None, external_trigger_range=None, trigger_delay=None, timeout_ticks=None): # region set parameters from args @@ -88,8 +89,8 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio if external_trigger_coupling is not None: self.parameters['external_trigger_coupling']._set(external_trigger_coupling) - if trigger_range is not None: - self.parameters['trigger_range']._set(trigger_range) + if external_trigger_range is not None: + self.parameters['external_trigger_range']._set(external_trigger_range) if trigger_delay is not None: self.parameters['trigger_delay']._set(trigger_delay) if timeout_ticks is not None: @@ -147,10 +148,10 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio return_code = self._ATS9870_dll.AlazarSetExternalTrigger(self._handle, self.parameters['external_trigger_coupling']._get_byte(), - self.parameters['trigger_range']._get_byte()) + self.parameters['external_trigger_range']._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarSetExternalTrigger") self.parameters['external_trigger_coupling']._set_updated() - self.parameters['trigger_range']._set_updated() + self.parameters['external_trigger_range']._set_updated() return_code = self._ATS9870_dll.AlazarSetTriggerDelay(self._handle, self.parameters['trigger_delay']._get_byte()) @@ -437,7 +438,7 @@ def __init__(self, name=None, label=None, unit=None, instrument=None, value=None vals = validators.Anything() else: # TODO (S) test this validator - vals = validators.Enum(byte_to_value_dict.values()) + vals = validators.Enum(*byte_to_value_dict.values()) super().__init__(name=name, label=label, unit=unit, vals=vals) self.instrument = instrument From 71640bfab6150f506f30cfea3ee528a0baac9e30 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Tue, 29 Mar 2016 12:08:27 +0200 Subject: [PATCH 12/56] added all remaining parameters --- .../instrument_drivers/AlazarTech/ATS9870.py | 194 +++++++++++++++--- 1 file changed, 160 insertions(+), 34 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index a552647d31a9..4c3d8f79d059 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -6,6 +6,7 @@ def __init__(self, name): super().__init__(name) # add parameters + # ----- Parameters for the configuration of the board ----- self.add_parameter(name='clock_source', parameter_class=AlazarParameter, label='Clock Source', unit=None, value='INTERNAL_CLOCK', byte_to_value_dict={1: 'INTERNAL_CLOCK', @@ -31,43 +32,168 @@ def __init__(self, name): self.add_parameter(name='decimation', parameter_class=AlazarParameter, label='Decimation', unit=None, value=0, vals=validators.Ints(0, 100000)) + self.add_parameter(name='coupling1', parameter_class=AlazarParameter, label='Coupling channel 1', unit=None, + value='AC_COUPLING', + byte_to_value_dict={1: 'AC_COUPLING', 2: 'DC_COUPLING'}) + self.add_parameter(name='coupling2', parameter_class=AlazarParameter, label='Coupling channel 2', unit=None, + value='AC_COUPLING', + byte_to_value_dict={1: 'AC_COUPLING', 2: 'DC_COUPLING'}) + + self.add_parameter(name='range1', parameter_class=AlazarParameter, label='Range channel 1', unit='V', + value=4, + byte_to_value_dict={2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4.}) + self.add_parameter(name='range2', parameter_class=AlazarParameter, label='Range channel 2', unit='V', + value=4, + byte_to_value_dict={2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4.}) + + self.add_parameter(name='impedance1', parameter_class=AlazarParameter, label='Impedance channel 1', unit='Ohm', + value=50, + byte_to_value_dict={1: 1000000, 2: 50}) + self.add_parameter(name='impedance2', parameter_class=AlazarParameter, label='Impedance channel 2', unit='Ohm', + value=50, + byte_to_value_dict={1: 1000000, 2: 50}) + + self.add_parameter(name='bwlimit1', parameter_class=AlazarParameter, label='Bandwidth limit channel 1', unit=None, + value='DISABLED', + byte_to_value_dict={0: 'DISABLED', 1: 'ENABLED'}) + self.add_parameter(name='bwlimit2', parameter_class=AlazarParameter, label='Bandwidth limit channel 2', unit=None, + value='DISABLED', + byte_to_value_dict={0: 'DISABLED', 1: 'ENABLED'}) + + self.add_parameter(name='trigger_operation', parameter_class=AlazarParameter, label='Trigger Operation', unit=None, + value='TRIG_ENGINE_OP_J', + byte_to_value_dict={0: 'TRIG_ENGINE_OP_J', + 1: 'TRIG_ENGINE_OP_K', + 2: 'TRIG_ENGINE_OP_J_OR_K', + 3: 'TRIG_ENGINE_OP_J_AND_K', + 4: 'TRIG_ENGINE_OP_J_XOR_K', + 5: 'TRIG_ENGINE_OP_J_AND_NOT_K', + 6: 'TRIG_ENGINE_OP_NOT_J_AND_K'}) + self.add_parameter(name='trigger_engine1', parameter_class=AlazarParameter, label='Trigger Engine 1', unit=None, + value='TRIG_ENGINE_J', + byte_to_value_dict={0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K'}) + self.add_parameter(name='trigger_engine2', parameter_class=AlazarParameter, label='Trigger Engine 2', unit=None, + value='TRIG_ENGINE_K', + byte_to_value_dict={0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K'}) + self.add_parameter(name='trigger_source1', parameter_class=AlazarParameter, label='Trigger Source 1', unit=None, + value='TRIG_EXTERNAL', + byte_to_value_dict={0: 'TRIG_CHAN_A', + 1: 'TRIG_CHAN_B', + 2: 'TRIG_EXTERNAL', + 3: 'TRIG_DISABLE'}) + self.add_parameter(name='trigger_source2', parameter_class=AlazarParameter, label='Trigger Source 2', unit=None, + value='TRIG_DISABLE', + byte_to_value_dict={0: 'TRIG_CHAN_A', + 1: 'TRIG_CHAN_B', + 2: 'TRIG_EXTERNAL', + 3: 'TRIG_DISABLE'}) + self.add_parameter(name='trigger_slope1', parameter_class=AlazarParameter, label='Trigger Slope 1', unit=None, + value='TRIG_SLOPE_POSITIVE', + byte_to_value_dict={1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE'}) + self.add_parameter(name='trigger_slope2', parameter_class=AlazarParameter, label='Trigger Slope 2', unit=None, + value='TRIG_SLOPE_POSITIVE', + byte_to_value_dict={1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE'}) + self.add_parameter(name='trigger_level1', parameter_class=AlazarParameter, label='Trigger Level 1', unit=None, + value=128, vals=validators.Ints(0, 255)) + self.add_parameter(name='trigger_level2', parameter_class=AlazarParameter, label='Trigger Level 2', unit=None, + value=128, vals=validators.Ints(0, 255)) + + self.add_parameter(name='external_trigger_coupling', parameter_class=AlazarParameter, + label='External Trigger Coupling', unit=None, + value='AC_COUPLING', + byte_to_value_dict={1: 'AC_COUPLING', 2: 'DC_COUPLING'}) + self.add_parameter(name='external_trigger_range', parameter_class=AlazarParameter, + label='External Trigger Range', unit=None, + value='ETR_5V', + byte_to_value_dict={0: 'ETR_5V', 1: 'ETR_1V'}) + self.add_parameter(name='trigger_delay', parameter_class=AlazarParameter, + label='Trigger Delay', unit='Sample clock cycles', + value=0, vals=validators.Ints(min_value=0)) + self.add_parameter(name='timeout_ticks', parameter_class=AlazarParameter, + label='Timeout Ticks', unit='10 us', + value=0, vals=validators.Ints(min_value=0)) + + # ----- Parameters for the acquire function ----- + self.add_parameter(name='mode', parameter_class=AlazarParameter, + label='Acquisiton mode', unit=None, + value='NPT', + byte_to_value_dict={0x200: 'NPT', 0x400: 'TS'}) + + # samples_per_record must be a multiple of 16! + self.add_parameter(name='samples_per_record', parameter_class=AlazarParameter, + label='Samples per Record', unit=None, + value=96000, vals=Multiples(divisor=16, min_value=0)) + # TODO (M) figure out if this also has to be a multiple of something, I could not find this in the documentation + # but somehow I have the feeling it still should be a multiple of something + self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, + label='Records per Buffer', unit=None, + value=1, vals=validators.Ints(min_value=0)) + self.add_parameter(name='buffers_per_acquisition', parameter_class=AlazarParameter, + label='Buffers per Acquisition', unit=None, + value=1, vals=validators.Ints(min_value=0)) + self.add_parameter(name='channel_selection', parameter_class=AlazarParameter, + label='Channel Selection', unit=None, + value='AB', + byte_to_value_dict={1: 'A', 2: 'B', 3: 'AB'}) + self.add_parameter(name='transfer_offset', parameter_class=AlazarParameter, + label='Transer Offset', unit='Samples', + value=0, vals=validators.Ints(min_value=0)) + self.add_parameter(name='external_startcapture', parameter_class=AlazarParameter, + label='External Startcapture', unit=None, + value='ENABLED', + byte_to_value_dict={0x0: 'DISABLED', 0x1: 'ENABLED'}) + self.add_parameter(name='enable_record_headers', parameter_class=AlazarParameter, + label='Enable Record Headers', unit=None, + value='DISABLED', + byte_to_value_dict={0x0: 'DISABLED', 0x8: 'ENABLED'}) + self.add_parameter(name='alloc_buffers', parameter_class=AlazarParameter, + label='Alloc Buffers', unit=None, + value='DISABLED', + byte_to_value_dict={0x0: 'DISABLED', 0x20: 'ENABLED'}) + self.add_parameter(name='fifo_only_streaming', parameter_class=AlazarParameter, + label='Fifo Only Streaming', unit=None, + value='DISABLED', + byte_to_value_dict={0x0: 'DISABLED', 0x800: 'ENABLED'}) + self.add_parameter(name='interleave_samples', parameter_class=AlazarParameter, + label='Interleave Samples', unit=None, + value='DISABLED', + byte_to_value_dict={0x0: 'DISABLED', 0x1000: 'ENABLED'}) + self.add_parameter(name='get_processed_data', parameter_class=AlazarParameter, + label='Get Processed Data', unit=None, + value='DISABLED', + byte_to_value_dict={0x0: 'DISABLED', 0x2000: 'ENABLED'}) + + self.add_parameter(name='allocated_buffers', parameter_class=AlazarParameter, + label='Allocated Buffers', unit=None, + value=1, vals=validators.Ints(min_value=0)) + self.add_parameter(name='buffer_timeout', parameter_class=AlazarParameter, + label='Buffer Timeout', unit='ms', + value=1000, vals=validators.Ints(min_value=0)) + # TODO (M) make parameter for board type # TODO (M) check board kind -# -----config----- -# sample_rate -# clock_edge -# decimation -# -# coupling{n} -# range{n} -# impedance{n} -# bwlimit{n} -# -# trigger_operation -# trigger_engine1 -# trigger_source1 -# trigger_slope1 -# trigger_level1 -# trigger_engine2 -# trigger_source2 -# trigger_slope2 -# trigger_level2 -# -# external_trigger_coupling -# trigger_range -# -# trigger_delay -# timeout_ticks -# -# ----acquire----- -# mode -# samples_per_record -# channel_selection -# -# more !? -# -# nbuffers +class Multiples(validators.Ints): + ''' + requires an integer + optional parameters min_value and max_value enforce + min_value <= value <= max_value + divisor enforces that value % divisor == 0 + ''' + + def __init__(self, divisor=1, **kwargs): + super().__init__(**kwargs) + if not isinstance(divisor, int): + raise TypeError('divisor must be an integer') + self._divisor = divisor + + def validate(self, value, context=''): + super().validate(value=value, context=context) + if not value % self._divisor == 0: + raise TypeError('{} is not a multiple of {}; {}'.format(repr(value), repr(self._divisor), context)) + + def __repr__(self): + super().__repr__() + ''.format(self._divisor) From 6b0aac7f86099e4ddff95cc3d8ab739722f4a9ec Mon Sep 17 00:00:00 2001 From: damazdejong Date: Tue, 29 Mar 2016 14:52:53 +0200 Subject: [PATCH 13/56] first working & lightly tested version --- qcodes/instrument_drivers/AlazarTech/ATS.py | 37 +++++++++---------- .../instrument_drivers/AlazarTech/ATS9870.py | 36 +++++++++--------- .../AlazarTech/ATS_acquisition_controllers.py | 2 +- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index a014f22e30d5..31a983145cc0 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -56,16 +56,16 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio if coupling is not None: for i, v in enumerate(coupling): - self.parameters['coupling'+str(i)]._set(v) + self.parameters['coupling'+str(i+1)]._set(v) if channel_range is not None: for i, v in enumerate(channel_range): - self.parameters['range'+str(i)]._set(v) + self.parameters['channel_range'+str(i+1)]._set(v) if impedance is not None: for i, v in enumerate(impedance): - self.parameters['impedance'+str(i)]._set(v) + self.parameters['impedance'+str(i+1)]._set(v) if bwlimit is not None: for i, v in enumerate(bwlimit): - self.parameters['bwlimit'+str(i)]._set(v) + self.parameters['bwlimit'+str(i+1)]._set(v) if trigger_operation is not None: self.parameters['trigger_operation']._set(trigger_operation) @@ -112,11 +112,11 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio return_code = self._ATS9870_dll.AlazarInputControl(self._handle, i, self.parameters['coupling'+str(i)]._get_byte(), - self.parameters['range'+str(i)]._get_byte(), + self.parameters['channel_range'+str(i)]._get_byte(), self.parameters['impedance'+str(i)]._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarInputControl " + str(i)) self.parameters['coupling'+str(i)]._set_updated() - self.parameters['range'+str(i)]._set_updated() + self.parameters['channel_range'+str(i)]._set_updated() self.parameters['impedance'+str(i)]._set_updated() return_code = self._ATS9870_dll.AlazarSetBWLimit(self._handle, @@ -200,7 +200,7 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b self.parameters['buffer_timeout']._set(buffer_timeout) # endregion - + self.parameters['mode']._set_updated() if not (self.parameters['mode'].get() == 'TS' or self.parameters['mode'].get() == 'NPT'): raise Exception("Only the 'TS' and 'NPT' modes are implemented at this point") @@ -277,8 +277,7 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b self.parameters['buffers_per_acquisition']._set_updated() self.parameters['channel_selection']._set_updated() self.parameters['transfer_offset']._set_updated() - self.parameters['mode']._set_updated() - self.parameters['external_starcapture']._set_updated() + self.parameters['external_startcapture']._set_updated() self.parameters['enable_record_headers']._set_updated() self.parameters['alloc_buffers']._set_updated() self.parameters['fifo_only_streaming']._set_updated() @@ -348,7 +347,7 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b self.clear_buffers() # check if all parameters are up to date - for p in self.parameters: + for p in self.parameters.values(): p.get() # return result @@ -413,20 +412,20 @@ def clear_buffers(self): def signal_to_volt(self, channel, signal): # TODO (S) check this # TODO (M) use byte value if range{channel} - return ((signal - 127.5) / 127.5) * (self.parameters["range" + str(channel)]) + return ((signal - 127.5) / 127.5) * (self.parameters["channel_range" + str(channel)].get()) def get_sample_speed(self): - if self.parameters['sample_rate'] == 'EXTERNAL_CLOCK': + if self.parameters['sample_rate'].get() == 'EXTERNAL_CLOCK': raise Exception('External clock is used, alazar driver could not determine sample speed.') rate = 0 - if self.parameters['sample_rate'] == '1GHz_REFERENCE_CLOCK': + if self.parameters['sample_rate'].get() == '1GHz_REFERENCE_CLOCK': rate = 1e9 else: - rate = self.parameters['sample_rate'] + rate = self.parameters['sample_rate'].get() - if self.parameters["decimation"] > 0: - return rate / self.parameters["decimation"] + if self.parameters["decimation"].get() > 0: + return rate / self.parameters["decimation"].get() else: return rate @@ -505,18 +504,18 @@ def __init__(self, bits_per_sample, samples_per_buffer, number_of_channels): mem_commit = 0x1000 page_readwrite = 0x4 - size_bytes = samples_per_buffer * number_of_channels + self.size_bytes = samples_per_buffer * number_of_channels # please see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx for documentation ctypes.windll.kernel32.VirtualAlloc.argtypes = [ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long] ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p - self.addr = ctypes.windll.kernel32.VirtualAlloc(0, ctypes.c_long(size_bytes), mem_commit, page_readwrite) + self.addr = ctypes.windll.kernel32.VirtualAlloc(0, ctypes.c_long(self.size_bytes), mem_commit, page_readwrite) if self.addr is None: self._allocated = False e = ctypes.windll.kernel32.GetLastError() raise Exception("Memory allocation error: " + str(e)) - ctypes_array = (ctypes.c_uint8 * size_bytes).from_address(self.addr) + ctypes_array = (ctypes.c_uint8 * self.size_bytes).from_address(self.addr) self.buffer = np.frombuffer(ctypes_array, dtype=np.uint8) pointer, read_only_flag = self.buffer.__array_interface__['data'] diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 4c3d8f79d059..459b881c16d1 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -33,16 +33,16 @@ def __init__(self, name): value=0, vals=validators.Ints(0, 100000)) self.add_parameter(name='coupling1', parameter_class=AlazarParameter, label='Coupling channel 1', unit=None, - value='AC_COUPLING', - byte_to_value_dict={1: 'AC_COUPLING', 2: 'DC_COUPLING'}) + value='AC', + byte_to_value_dict={1: 'AC', 2: 'DC'}) self.add_parameter(name='coupling2', parameter_class=AlazarParameter, label='Coupling channel 2', unit=None, - value='AC_COUPLING', - byte_to_value_dict={1: 'AC_COUPLING', 2: 'DC_COUPLING'}) + value='AC', + byte_to_value_dict={1: 'AC', 2: 'DC'}) - self.add_parameter(name='range1', parameter_class=AlazarParameter, label='Range channel 1', unit='V', + self.add_parameter(name='channel_range1', parameter_class=AlazarParameter, label='Range channel 1', unit='V', value=4, byte_to_value_dict={2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4.}) - self.add_parameter(name='range2', parameter_class=AlazarParameter, label='Range channel 2', unit='V', + self.add_parameter(name='channel_range2', parameter_class=AlazarParameter, label='Range channel 2', unit='V', value=4, byte_to_value_dict={2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4.}) @@ -76,17 +76,17 @@ def __init__(self, name): value='TRIG_ENGINE_K', byte_to_value_dict={0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K'}) self.add_parameter(name='trigger_source1', parameter_class=AlazarParameter, label='Trigger Source 1', unit=None, - value='TRIG_EXTERNAL', - byte_to_value_dict={0: 'TRIG_CHAN_A', - 1: 'TRIG_CHAN_B', - 2: 'TRIG_EXTERNAL', - 3: 'TRIG_DISABLE'}) + value='EXTERNAL', + byte_to_value_dict={0: 'CHANNEL_A', + 1: 'CHANNEL_B', + 2: 'EXTERNAL', + 3: 'DISABLE'}) self.add_parameter(name='trigger_source2', parameter_class=AlazarParameter, label='Trigger Source 2', unit=None, - value='TRIG_DISABLE', - byte_to_value_dict={0: 'TRIG_CHAN_A', - 1: 'TRIG_CHAN_B', - 2: 'TRIG_EXTERNAL', - 3: 'TRIG_DISABLE'}) + value='DISABLE', + byte_to_value_dict={0: 'CHANNEL_A', + 1: 'CHANNEL_B', + 2: 'EXTERNAL', + 3: 'DISABLE'}) self.add_parameter(name='trigger_slope1', parameter_class=AlazarParameter, label='Trigger Slope 1', unit=None, value='TRIG_SLOPE_POSITIVE', byte_to_value_dict={1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE'}) @@ -100,8 +100,8 @@ def __init__(self, name): self.add_parameter(name='external_trigger_coupling', parameter_class=AlazarParameter, label='External Trigger Coupling', unit=None, - value='AC_COUPLING', - byte_to_value_dict={1: 'AC_COUPLING', 2: 'DC_COUPLING'}) + value='AC', + byte_to_value_dict={1: 'AC', 2: 'DC'}) self.add_parameter(name='external_trigger_range', parameter_class=AlazarParameter, label='External Trigger Range', unit=None, value='ETR_5V', diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py index b04739c646c9..fa3b62b9ad11 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -50,7 +50,7 @@ def post_acquire(self, alazar): # fit channel A and channel B res1 = self.fit(recordA) res2 = self.fit(recordB) - return [alazar.signal_to_volt(0, res1[0] + 127.5), alazar.signal_to_volt(1, res2[0] + 127.5), res1[1], res2[1], + return [alazar.signal_to_volt(1, res1[0] + 127.5), alazar.signal_to_volt(2, res2[0] + 127.5), res1[1], res2[1], (res1[1] - res2[1]) % 360] else: raise Exception("Could not find CHANNEL_B during data extraction") From 7854340c94e4a3d0773e74bc7ef9d0dfbb1fcc47 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Tue, 29 Mar 2016 15:02:26 +0200 Subject: [PATCH 14/56] acquisition parameters are now automatically fetched from the driver --- .../AlazarTech/ATS_acquisition_controllers.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py index fa3b62b9ad11..89d1b4209669 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -5,11 +5,11 @@ # DFT AcquisitionController class DFT_AcquisitionController(AcquisitionController): - def __init__(self, demodulation_frequency, samples_per_record, records_per_buffer, buffers_per_acquisition): + def __init__(self, demodulation_frequency): self.demodulation_frequency = demodulation_frequency - self.samples_per_record = samples_per_record - self.records_per_buffer = records_per_buffer - self.buffers_per_acquisition = buffers_per_acquisition + self.samples_per_record = None + self.records_per_buffer = None + self.buffers_per_acquisition = None # TODO (S) this is not very general: self.number_of_channels = 2 self.cos_list = None @@ -17,6 +17,9 @@ def __init__(self, demodulation_frequency, samples_per_record, records_per_buffe self.buffer = None def pre_start_capture(self, alazar): + self.samples_per_record = alazar.parameters['samples_per_record'].get() + self.records_per_buffer = alazar.parameters['records_per_buffer'].get() + self.buffers_per_acquisition = alazar.parameters['buffers_per_acquisition'].get() sample_speed = alazar.get_sample_speed() integer_list = np.arange(self.samples_per_record) From 6e16aa541ebe5270da95e321cb370a702cac10e4 Mon Sep 17 00:00:00 2001 From: damazter Date: Sun, 17 Apr 2016 08:39:36 -0700 Subject: [PATCH 15/56] change default value of uptodateflag in Alazarparameter --- qcodes/instrument_drivers/AlazarTech/ATS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 31a983145cc0..e62a93b9451c 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -442,7 +442,7 @@ def __init__(self, name=None, label=None, unit=None, instrument=None, value=None super().__init__(name=name, label=label, unit=unit, vals=vals) self.instrument = instrument self._byte = None - self._uptodate_flag = True + self._uptodate_flag = False # TODO (M) check this block if byte_to_value_dict is None: From 3444592a9482a3ebdcf90982aa1a4f6e9fe02325 Mon Sep 17 00:00:00 2001 From: damazter Date: Sun, 17 Apr 2016 08:42:19 -0700 Subject: [PATCH 16/56] added empty docstrings for config and acquire --- qcodes/instrument_drivers/AlazarTech/ATS.py | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index e62a93b9451c..7de7c46e092e 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -42,7 +42,31 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio trigger_engine1=None, trigger_source1=None, trigger_slope1=None, trigger_level1=None, trigger_engine2=None, trigger_source2=None, trigger_slope2=None, trigger_level2=None, external_trigger_coupling=None, external_trigger_range=None, trigger_delay=None, timeout_ticks=None): + """ + :param clock_source: + :param sample_rate: + :param clock_edge: + :param decimation: + :param coupling: + :param channel_range: + :param impedance: + :param bwlimit: + :param trigger_operation: + :param trigger_engine1: + :param trigger_source1: + :param trigger_slope1: + :param trigger_level1: + :param trigger_engine2: + :param trigger_source2: + :param trigger_slope2: + :param trigger_level2: + :param external_trigger_coupling: + :param external_trigger_range: + :param trigger_delay: + :param timeout_ticks: + :return: + """ # region set parameters from args if clock_source is not None: @@ -169,6 +193,25 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b channel_selection=None, transfer_offset=None, external_startcapture=None, enable_record_headers=None, alloc_buffers=None, fifo_only_streaming=None, interleave_samples=None, get_processed_data=None, allocated_buffers=None, buffer_timeout=None, acquisition_controller=None): + """ + + :param mode: + :param samples_per_record: + :param records_per_buffer: + :param buffers_per_acquisition: + :param channel_selection: + :param transfer_offset: + :param external_startcapture: + :param enable_record_headers: + :param alloc_buffers: + :param fifo_only_streaming: + :param interleave_samples: + :param get_processed_data: + :param allocated_buffers: + :param buffer_timeout: + :param acquisition_controller: + :return: + """ # region set parameters from args if mode is not None: self.parameters['mode']._set(mode) From 48818b12cfaa34f6f43849c468a0698be08591ac Mon Sep 17 00:00:00 2001 From: damazter Date: Sun, 17 Apr 2016 08:56:15 -0700 Subject: [PATCH 17/56] rename dll variable to remove 9870 reference --- qcodes/instrument_drivers/AlazarTech/ATS.py | 108 ++++++++++---------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 7de7c46e092e..d538807b7215 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -24,10 +24,10 @@ class AlazarTech_ATS(Instrument): def __init__(self, name): super().__init__(name) # Make sure the dll is located at "C:\\WINDOWS\\System32\\ATSApi" - self._ATS9870_dll = ctypes.cdll.LoadLibrary('C:\\WINDOWS\\System32\\ATSApi') + self._ATS_dll = ctypes.cdll.LoadLibrary('C:\\WINDOWS\\System32\\ATSApi') # TODO (W) make the board id more general such that more than one card per system configurations are supported - self._handle = self._ATS9870_dll.AlazarGetBoardBySystemID(1, 1) + self._handle = self._ATS_dll.AlazarGetBoardBySystemID(1, 1) if not self._handle: raise Exception("AlazarTech_ATS not found") @@ -121,11 +121,11 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio self.parameters['timeout_ticks']._set(timeout_ticks) # endregion - return_code = self._ATS9870_dll.AlazarSetCaptureClock(self._handle, - self.parameters['clock_source']._get_byte(), - self.parameters['sample_rate']._get_byte(), - self.parameters['clock_edge']._get_byte(), - self.parameters['decimation']._get_byte()) + return_code = self._ATS_dll.AlazarSetCaptureClock(self._handle, + self.parameters['clock_source']._get_byte(), + self.parameters['sample_rate']._get_byte(), + self.parameters['clock_edge']._get_byte(), + self.parameters['decimation']._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarSetCaptureClock") self.parameters['clock_source']._set_updated() self.parameters['sample_rate']._set_updated() @@ -133,32 +133,32 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio self.parameters['decimation']._set_updated() for i in [1, 2]: - return_code = self._ATS9870_dll.AlazarInputControl(self._handle, - i, - self.parameters['coupling'+str(i)]._get_byte(), - self.parameters['channel_range'+str(i)]._get_byte(), - self.parameters['impedance'+str(i)]._get_byte()) + return_code = self._ATS_dll.AlazarInputControl(self._handle, + i, + self.parameters['coupling'+str(i)]._get_byte(), + self.parameters['channel_range'+str(i)]._get_byte(), + self.parameters['impedance'+str(i)]._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarInputControl " + str(i)) self.parameters['coupling'+str(i)]._set_updated() self.parameters['channel_range'+str(i)]._set_updated() self.parameters['impedance'+str(i)]._set_updated() - return_code = self._ATS9870_dll.AlazarSetBWLimit(self._handle, - i, - self.parameters['bwlimit'+str(i)]._get_byte()) + return_code = self._ATS_dll.AlazarSetBWLimit(self._handle, + i, + self.parameters['bwlimit'+str(i)]._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarSetBWLimit " + str(i)) self.parameters['bwlimit'+str(i)]._set_updated() - return_code = self._ATS9870_dll.AlazarSetTriggerOperation(self._handle, - self.parameters['trigger_operation']._get_byte(), - self.parameters['trigger_engine1']._get_byte(), - self.parameters['trigger_source1']._get_byte(), - self.parameters['trigger_slope1']._get_byte(), - self.parameters['trigger_level1']._get_byte(), - self.parameters['trigger_engine2']._get_byte(), - self.parameters['trigger_source2']._get_byte(), - self.parameters['trigger_slope2']._get_byte(), - self.parameters['trigger_level2']._get_byte()) + return_code = self._ATS_dll.AlazarSetTriggerOperation(self._handle, + self.parameters['trigger_operation']._get_byte(), + self.parameters['trigger_engine1']._get_byte(), + self.parameters['trigger_source1']._get_byte(), + self.parameters['trigger_slope1']._get_byte(), + self.parameters['trigger_level1']._get_byte(), + self.parameters['trigger_engine2']._get_byte(), + self.parameters['trigger_source2']._get_byte(), + self.parameters['trigger_slope2']._get_byte(), + self.parameters['trigger_level2']._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarSetTriggerOperation") self.parameters['trigger_operation']._set_updated() self.parameters['trigger_engine1']._set_updated() @@ -170,20 +170,20 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio self.parameters['trigger_slope2']._set_updated() self.parameters['trigger_level2']._set_updated() - return_code = self._ATS9870_dll.AlazarSetExternalTrigger(self._handle, - self.parameters['external_trigger_coupling']._get_byte(), - self.parameters['external_trigger_range']._get_byte()) + return_code = self._ATS_dll.AlazarSetExternalTrigger(self._handle, + self.parameters['external_trigger_coupling']._get_byte(), + self.parameters['external_trigger_range']._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarSetExternalTrigger") self.parameters['external_trigger_coupling']._set_updated() self.parameters['external_trigger_range']._set_updated() - return_code = self._ATS9870_dll.AlazarSetTriggerDelay(self._handle, - self.parameters['trigger_delay']._get_byte()) + return_code = self._ATS_dll.AlazarSetTriggerDelay(self._handle, + self.parameters['trigger_delay']._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarSetTriggerDelay") self.parameters['trigger_delay']._set_updated() - return_code = self._ATS9870_dll.AlazarSetTriggerTimeOut(self._handle, - self.parameters['timeout_ticks']._get_byte()) + return_code = self._ATS_dll.AlazarSetTriggerTimeOut(self._handle, + self.parameters['timeout_ticks']._get_byte()) self._result_handler(error_code=return_code, error_source="AlazarSetTriggerTimeOut") self.parameters['timeout_ticks']._set_updated() @@ -250,13 +250,13 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b # -----set final configurations----- # Abort any previous measurement - return_code = self._ATS9870_dll.AlazarAbortAsyncRead(self._handle) + return_code = self._ATS_dll.AlazarAbortAsyncRead(self._handle) self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") # get channel info bps = np.array([0], dtype=np.uint8) # bps bits per sample max_s = np.array([0], dtype=np.uint32) # max_s memory size in samples - return_code = self._ATS9870_dll.AlazarGetChannelInfo(self._handle, max_s.ctypes.data, bps.ctypes.data) + return_code = self._ATS_dll.AlazarGetChannelInfo(self._handle, max_s.ctypes.data, bps.ctypes.data) self._result_handler(error_code=return_code, error_source="AlazarGetChannelInfo") bps = bps[0] max_s = max_s[0] @@ -267,7 +267,7 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b if self.parameters['mode'].get() == 'NPT': pretriggersize = 0 # pretriggersize is 0 for NPT always post_trigger_size = self.parameters['samples_per_record']._get_byte() - return_code = self._ATS9870_dll.AlazarSetRecordSize(self._handle, pretriggersize, post_trigger_size) + return_code = self._ATS_dll.AlazarSetRecordSize(self._handle, pretriggersize, post_trigger_size) self._result_handler(error_code=return_code, error_source="AlazarSetRecordSize") @@ -289,13 +289,13 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b records_per_buffer = self.parameters['records_per_buffer']._get_byte() records_per_acquisition = records_per_buffer * self.parameters['buffers_per_acquisition']._get_byte() samples_per_buffer = samples_per_record * records_per_buffer - return_code = self._ATS9870_dll.AlazarBeforeAsyncRead(self._handle, - self.parameters['channel_selection']._get_byte(), - self.parameters['transfer_offset']._get_byte(), - samples_per_record, - records_per_buffer, - records_per_acquisition, - acquire_flags) + return_code = self._ATS_dll.AlazarBeforeAsyncRead(self._handle, + self.parameters['channel_selection']._get_byte(), + self.parameters['transfer_offset']._get_byte(), + samples_per_record, + records_per_buffer, + records_per_acquisition, + acquire_flags) self._result_handler(error_code=return_code, error_source="AlazarBeforeAsyncRead") elif self.parameters['mode'].get() == 'TS': if not self.parameters['samples_per_record']._get_byte() % self.parameters['buffers_per_acquisition'] == 0: @@ -307,13 +307,13 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b logging.warning('records_per_buffer should be 1 in TS mode, defauling to 1') self.parameters['records_per_buffer']._set(1) records_per_buffer = self.parameters['records_per_buffer']._get_byte() - return_code = self._ATS9870_dll.AlazarBeforeAsyncRead(self._handle, - self.parameters['channel_selection']._get_byte(), - self.parameters['transfer_offset']._get_byte(), - samples_per_buffer, - records_per_buffer, - buffers_per_acquisition, - acquire_flags) + return_code = self._ATS_dll.AlazarBeforeAsyncRead(self._handle, + self.parameters['channel_selection']._get_byte(), + self.parameters['transfer_offset']._get_byte(), + samples_per_buffer, + records_per_buffer, + buffers_per_acquisition, + acquire_flags) self._result_handler(error_code=return_code, error_source="AlazarBeforeAsyncRead") self.parameters['samples_per_record']._set_updated() self.parameters['records_per_buffer']._set_updated() @@ -338,14 +338,14 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b # post buffers to Alazar for buf in self.buffer_list: - return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) + return_code = self._ATS_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") self.parameters['allocated_buffers']._set_updated() # -----start capture here----- acquisition_controller.pre_start_capture(self) # call the startcapture method - return_code = self._ATS9870_dll.AlazarStartCapture(self._handle) + return_code = self._ATS_dll.AlazarStartCapture(self._handle) self._result_handler(error_code=return_code, error_source="AlazarStartCapture") acquisition_controller.pre_acquire(self) @@ -361,7 +361,7 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b while buffers_completed < self.parameters['buffers_per_acquisition']._get_byte(): buf = self.buffer_list[buffers_completed % self.parameters['allocated_buffers']._get_byte()] - return_code = self._ATS9870_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, buffer_timeout) + return_code = self._ATS_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, buffer_timeout) self._result_handler(error_code=return_code, error_source="AlazarWaitAsyncBufferComplete") # TODO (C) last series of buffers must be handled exceptionally (and I want to test the difference) @@ -372,12 +372,12 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b if buffer_recycling: acquisition_controller.handle_buffer(self, buf.buffer) - return_code = self._ATS9870_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) + return_code = self._ATS_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") buffers_completed += 1 # stop measurement here - return_code = self._ATS9870_dll.AlazarAbortAsyncRead(self._handle) + return_code = self._ATS_dll.AlazarAbortAsyncRead(self._handle) self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") # -----cleanup here----- From 05b6ee8bf205b515c9fa1ed4bd6b18ddb71719b2 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Wed, 27 Apr 2016 22:25:53 +0200 Subject: [PATCH 18/56] lint & refactor alazar base and 9870 --- qcodes/instrument_drivers/AlazarTech/ATS.py | 700 ++++++++++-------- .../instrument_drivers/AlazarTech/ATS9870.py | 338 +++++---- .../AlazarTech/ATS_acquisition_controllers.py | 44 +- 3 files changed, 609 insertions(+), 473 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index d538807b7215..dfa2e70f7d68 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -12,36 +12,134 @@ # these items are important for generalizing this code to multiple alazar cards # TODO (W) remove 8 bits per sample requirement # TODO (W) some alazar cards have a different number of channels :( -# this ddrive ronly works with 2-channel cards +# this driver only works with 2-channel cards # TODO (S) tests to do: -# acquisition that would overflow the board if measurement is not stopped quicmly enough -# can this be solved by not reposting the buffers? +# acquisition that would overflow the board if measurement is not stopped +# quickly enough. can this be solved by not reposting the buffers? class AlazarTech_ATS(Instrument): - - def __init__(self, name): + # TODO (S) is the success code always 512 (for any board)? + _success = 512 + + _error_codes = { + 513: 'ApiFailed', + 514: 'ApiAccessDenied', + 515: 'ApiDmaChannelUnavailable', + 516: 'ApiDmaChannelInvalid', + 517: 'ApiDmaChannelTypeError', + 518: 'ApiDmaInProgress', + 519: 'ApiDmaDone', + 520: 'ApiDmaPaused', + 521: 'ApiDmaNotPaused', + 522: 'ApiDmaCommandInvalid', + 523: 'ApiDmaManReady', + 524: 'ApiDmaManNotReady', + 525: 'ApiDmaInvalidChannelPriority', + 526: 'ApiDmaManCorrupted', + 527: 'ApiDmaInvalidElementIndex', + 528: 'ApiDmaNoMoreElements', + 529: 'ApiDmaSglInvalid', + 530: 'ApiDmaSglQueueFull', + 531: 'ApiNullParam', + 532: 'ApiInvalidBusIndex', + 533: 'ApiUnsupportedFunction', + 534: 'ApiInvalidPciSpace', + 535: 'ApiInvalidIopSpace', + 536: 'ApiInvalidSize', + 537: 'ApiInvalidAddress', + 538: 'ApiInvalidAccessType', + 539: 'ApiInvalidIndex', + 540: 'ApiMuNotReady', + 541: 'ApiMuFifoEmpty', + 542: 'ApiMuFifoFull', + 543: 'ApiInvalidRegister', + 544: 'ApiDoorbellClearFailed', + 545: 'ApiInvalidUserPin', + 546: 'ApiInvalidUserState', + 547: 'ApiEepromNotPresent', + 548: 'ApiEepromTypeNotSupported', + 549: 'ApiEepromBlank', + 550: 'ApiConfigAccessFailed', + 551: 'ApiInvalidDeviceInfo', + 552: 'ApiNoActiveDriver', + 553: 'ApiInsufficientResources', + 554: 'ApiObjectAlreadyAllocated', + 555: 'ApiAlreadyInitialized', + 556: 'ApiNotInitialized', + 557: 'ApiBadConfigRegEndianMode', + 558: 'ApiInvalidPowerState', + 559: 'ApiPowerDown', + 560: 'ApiFlybyNotSupported', + 561: 'ApiNotSupportThisChannel', + 562: 'ApiNoAction', + 563: 'ApiHSNotSupported', + 564: 'ApiVPDNotSupported', + 565: 'ApiVpdNotEnabled', + 566: 'ApiNoMoreCap', + 567: 'ApiInvalidOffset', + 568: 'ApiBadPinDirection', + 569: 'ApiPciTimeout', + 570: 'ApiDmaChannelClosed', + 571: 'ApiDmaChannelError', + 572: 'ApiInvalidHandle', + 573: 'ApiBufferNotReady', + 574: 'ApiInvalidData', + 575: 'ApiDoNothing', + 576: 'ApiDmaSglBuildFailed', + 577: 'ApiPMNotSupported', + 578: 'ApiInvalidDriverVersion', + 579: ('ApiWaitTimeout: operation did not finish during ' + 'timeout interval. Check your trigger.'), + 580: 'ApiWaitCanceled', + 581: 'ApiBufferTooSmall', + 582: ('ApiBufferOverflow:rate of acquiring data > rate of ' + 'transferring data to local memory. Try reducing sample rate, ' + 'reducing number of enabled channels, increasing size of each ' + 'DMA buffer or increase number of DMA buffers.'), + 583: 'ApiInvalidBuffer', + 584: 'ApiInvalidRecordsPerBuffer', + 585: ('ApiDmaPending:Async I/O operation was successfully started, ' + 'it will be completed when sufficient trigger events are ' + 'supplied to fill the buffer.'), + 586: ('ApiLockAndProbePagesFailed:Driver or operating system was ' + 'unable to prepare the specified buffer for DMA transfer. ' + 'Try reducing buffer size or total number of buffers.'), + 587: 'ApiWaitAbandoned', + 588: 'ApiWaitFailed', + 589: ('ApiTransferComplete:This buffer is last in the current ' + 'acquisition.'), + 590: 'ApiPllNotLocked:hardware error, contact AlazarTech', + 591: ('ApiNotSupportedInDualChannelMode:Requested number of samples ' + 'per channel is too large to fit in on-board memory. Try ' + 'reducing number of samples per channel, or switch to ' + 'single channel mode.') + } + + def __init__(self, name, dll_path='C:\\WINDOWS\\System32\\ATSApi'): super().__init__(name) - # Make sure the dll is located at "C:\\WINDOWS\\System32\\ATSApi" - self._ATS_dll = ctypes.cdll.LoadLibrary('C:\\WINDOWS\\System32\\ATSApi') + self._ATS_dll = ctypes.cdll.LoadLibrary(dll_path) - # TODO (W) make the board id more general such that more than one card per system configurations are supported + # TODO (W) make the board id more general such that more than one card + # per system configurations are supported self._handle = self._ATS_dll.AlazarGetBoardBySystemID(1, 1) if not self._handle: raise Exception("AlazarTech_ATS not found") # TODO (M) do something with board kind here - # TODO (S) is the succes code always 512 (for any board)? - self._succes = 512 self.buffer_list = [] - def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimation=None, coupling=None, - channel_range=None, impedance=None, bwlimit=None, trigger_operation=None, - trigger_engine1=None, trigger_source1=None, trigger_slope1=None, trigger_level1=None, - trigger_engine2=None, trigger_source2=None, trigger_slope2=None, trigger_level2=None, - external_trigger_coupling=None, external_trigger_range=None, trigger_delay=None, timeout_ticks=None): + def config(self, clock_source=None, sample_rate=None, clock_edge=None, + decimation=None, coupling=None, channel_range=None, + impedance=None, bwlimit=None, trigger_operation=None, + trigger_engine1=None, trigger_source1=None, + trigger_slope1=None, trigger_level1=None, + trigger_engine2=None, trigger_source2=None, + trigger_slope2=None, trigger_level2=None, + external_trigger_coupling=None, external_trigger_range=None, + trigger_delay=None, timeout_ticks=None): """ :param clock_source: @@ -69,130 +167,70 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimatio """ # region set parameters from args - if clock_source is not None: - self.parameters['clock_source']._set(clock_source) - if sample_rate is not None: - self.parameters['sample_rate']._set(sample_rate) - if clock_edge is not None: - self.parameters['clock_edge']._set(clock_edge) - if decimation is not None: - self.parameters['decimation']._set(decimation) - - if coupling is not None: - for i, v in enumerate(coupling): - self.parameters['coupling'+str(i+1)]._set(v) - if channel_range is not None: - for i, v in enumerate(channel_range): - self.parameters['channel_range'+str(i+1)]._set(v) - if impedance is not None: - for i, v in enumerate(impedance): - self.parameters['impedance'+str(i+1)]._set(v) - if bwlimit is not None: - for i, v in enumerate(bwlimit): - self.parameters['bwlimit'+str(i+1)]._set(v) - - if trigger_operation is not None: - self.parameters['trigger_operation']._set(trigger_operation) - if trigger_engine1 is not None: - self.parameters['trigger_engine1']._set(trigger_engine1) - if trigger_source1 is not None: - self.parameters['trigger_source1']._set(trigger_source1) - if trigger_slope1 is not None: - self.parameters['trigger_slope1']._set(trigger_slope1) - if trigger_level1 is not None: - self.parameters['trigger_level1']._set(trigger_level1) - - if trigger_engine2 is not None: - self.parameters['trigger_engine2']._set(trigger_engine2) - if trigger_source2 is not None: - self.parameters['trigger_source2']._set(trigger_source2) - if trigger_slope2 is not None: - self.parameters['trigger_slope2']._set(trigger_slope2) - if trigger_level2 is not None: - self.parameters['trigger_level2']._set(trigger_level2) - - if external_trigger_coupling is not None: - self.parameters['external_trigger_coupling']._set(external_trigger_coupling) - if external_trigger_range is not None: - self.parameters['external_trigger_range']._set(external_trigger_range) - if trigger_delay is not None: - self.parameters['trigger_delay']._set(trigger_delay) - if timeout_ticks is not None: - self.parameters['timeout_ticks']._set(timeout_ticks) + self._set_if_present('clock_source', clock_source) + self._set_if_present('sample_rate', sample_rate) + self._set_if_present('clock_edge', clock_edge) + self._set_if_present('decimation', decimation) + + self._set_list_if_present('coupling', coupling) + self._set_list_if_present('channel_range', channel_range) + self._set_list_if_present('impedance', impedance) + self._set_list_if_present('bwlimit', bwlimit) + + self._set_if_present('trigger_operation', trigger_operation) + self._set_if_present('trigger_engine1', trigger_engine1) + self._set_if_present('trigger_source1', trigger_source1) + self._set_if_present('trigger_slope1', trigger_slope1) + self._set_if_present('trigger_level1', trigger_level1) + + self._set_if_present('trigger_engine2', trigger_engine2) + self._set_if_present('trigger_source2', trigger_source2) + self._set_if_present('trigger_slope2', trigger_slope2) + self._set_if_present('trigger_level2', trigger_level2) + + self._set_if_present('external_trigger_coupling', + external_trigger_coupling) + self._set_if_present('external_trigger_range', + external_trigger_range) + self._set_if_present('trigger_delay', trigger_delay) + self._set_if_present('timeout_ticks', timeout_ticks) # endregion - return_code = self._ATS_dll.AlazarSetCaptureClock(self._handle, - self.parameters['clock_source']._get_byte(), - self.parameters['sample_rate']._get_byte(), - self.parameters['clock_edge']._get_byte(), - self.parameters['decimation']._get_byte()) - self._result_handler(error_code=return_code, error_source="AlazarSetCaptureClock") - self.parameters['clock_source']._set_updated() - self.parameters['sample_rate']._set_updated() - self.parameters['clock_edge']._set_updated() - self.parameters['decimation']._set_updated() + self._call_dll('AlazarSetCaptureClock', + args=['clock_source', 'sample_rate', + 'clock_edge', 'decimation']) for i in [1, 2]: - return_code = self._ATS_dll.AlazarInputControl(self._handle, - i, - self.parameters['coupling'+str(i)]._get_byte(), - self.parameters['channel_range'+str(i)]._get_byte(), - self.parameters['impedance'+str(i)]._get_byte()) - self._result_handler(error_code=return_code, error_source="AlazarInputControl " + str(i)) - self.parameters['coupling'+str(i)]._set_updated() - self.parameters['channel_range'+str(i)]._set_updated() - self.parameters['impedance'+str(i)]._set_updated() - - return_code = self._ATS_dll.AlazarSetBWLimit(self._handle, - i, - self.parameters['bwlimit'+str(i)]._get_byte()) - self._result_handler(error_code=return_code, error_source="AlazarSetBWLimit " + str(i)) - self.parameters['bwlimit'+str(i)]._set_updated() - - return_code = self._ATS_dll.AlazarSetTriggerOperation(self._handle, - self.parameters['trigger_operation']._get_byte(), - self.parameters['trigger_engine1']._get_byte(), - self.parameters['trigger_source1']._get_byte(), - self.parameters['trigger_slope1']._get_byte(), - self.parameters['trigger_level1']._get_byte(), - self.parameters['trigger_engine2']._get_byte(), - self.parameters['trigger_source2']._get_byte(), - self.parameters['trigger_slope2']._get_byte(), - self.parameters['trigger_level2']._get_byte()) - self._result_handler(error_code=return_code, error_source="AlazarSetTriggerOperation") - self.parameters['trigger_operation']._set_updated() - self.parameters['trigger_engine1']._set_updated() - self.parameters['trigger_source1']._set_updated() - self.parameters['trigger_slope1']._set_updated() - self.parameters['trigger_level1']._set_updated() - self.parameters['trigger_engine2']._set_updated() - self.parameters['trigger_source2']._set_updated() - self.parameters['trigger_slope2']._set_updated() - self.parameters['trigger_level2']._set_updated() - - return_code = self._ATS_dll.AlazarSetExternalTrigger(self._handle, - self.parameters['external_trigger_coupling']._get_byte(), - self.parameters['external_trigger_range']._get_byte()) - self._result_handler(error_code=return_code, error_source="AlazarSetExternalTrigger") - self.parameters['external_trigger_coupling']._set_updated() - self.parameters['external_trigger_range']._set_updated() - - return_code = self._ATS_dll.AlazarSetTriggerDelay(self._handle, - self.parameters['trigger_delay']._get_byte()) - self._result_handler(error_code=return_code, error_source="AlazarSetTriggerDelay") - self.parameters['trigger_delay']._set_updated() - - return_code = self._ATS_dll.AlazarSetTriggerTimeOut(self._handle, - self.parameters['timeout_ticks']._get_byte()) - self._result_handler(error_code=return_code, error_source="AlazarSetTriggerTimeOut") - self.parameters['timeout_ticks']._set_updated() + self._call_dll('AlazarInputControl', i=i, + args=['coupling{}', 'channel_range{}', + 'impedance{}']) + self._call_dll('AlazarSetBWLimit', i=i, args=['bwlimit{}']) + + self._call_dll('AlazarSetTriggerOperation', + args=['trigger_operation', + 'trigger_engine1', 'trigger_source1', + 'trigger_slope1', 'trigger_level1', + 'trigger_engine2', 'trigger_source2', + 'trigger_slope2', 'trigger_level2']) + + self._call_dll('AlazarSetExternalTrigger', + args=['external_trigger_coupling', + 'external_trigger_range']) + + self._call_dll('AlazarSetTriggerDelay', args=['trigger_delay']) + + self._call_dll('AlazarSetTriggerTimeOut', args=['timeout_ticks']) # TODO (W) config AUXIO - def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, buffers_per_acquisition=None, - channel_selection=None, transfer_offset=None, external_startcapture=None, enable_record_headers=None, - alloc_buffers=None, fifo_only_streaming=None, interleave_samples=None, get_processed_data=None, - allocated_buffers=None, buffer_timeout=None, acquisition_controller=None): + def acquire(self, mode=None, samples_per_record=None, + records_per_buffer=None, buffers_per_acquisition=None, + channel_selection=None, transfer_offset=None, + external_startcapture=None, enable_record_headers=None, + alloc_buffers=None, fifo_only_streaming=None, + interleave_samples=None, get_processed_data=None, + allocated_buffers=None, buffer_timeout=None, + acquisition_controller=None): """ :param mode: @@ -213,172 +251,160 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b :return: """ # region set parameters from args - if mode is not None: - self.parameters['mode']._set(mode) - if samples_per_record is not None: - self.parameters['samples_per_record']._set(samples_per_record) - if records_per_buffer is not None: - self.parameters['records_per_buffer']._set(records_per_buffer) - if buffers_per_acquisition is not None: - self.parameters['buffers_per_acquisition']._set(buffers_per_acquisition) - if channel_selection is not None: - self.parameters['channel_selection']._set(channel_selection) - if transfer_offset is not None: - self.parameters['transfer_offset']._set(transfer_offset) - if external_startcapture is not None: - self.parameters['external_starcapture']._set(external_startcapture) - if enable_record_headers is not None: - self.parameters['enable_record_headers']._set(enable_record_headers) - if alloc_buffers is not None: - self.parameters['alloc_buffers']._set(alloc_buffers) - if fifo_only_streaming is not None: - self.parameters['fifo_only_streaming']._set(fifo_only_streaming) - if interleave_samples is not None: - self.parameters['interleave_samples']._set(interleave_samples) - if get_processed_data is not None: - self.parameters['get_processed_data']._set(get_processed_data) - if allocated_buffers is not None: - self.parameters['allocated_buffers']._set(allocated_buffers) - if buffer_timeout is not None: - self.parameters['buffer_timeout']._set(buffer_timeout) + self._set_if_present('mode', mode) + self._set_if_present('samples_per_record', samples_per_record) + self._set_if_present('records_per_buffer', records_per_buffer) + self._set_if_present('buffers_per_acquisition', + buffers_per_acquisition) + self._set_if_present('channel_selection', channel_selection) + self._set_if_present('transfer_offset', transfer_offset) + self._set_if_present('external_starcapture', external_startcapture) + self._set_if_present('enable_record_headers', enable_record_headers) + self._set_if_present('alloc_buffers', alloc_buffers) + self._set_if_present('fifo_only_streaming', fifo_only_streaming) + self._set_if_present('interleave_samples', interleave_samples) + self._set_if_present('get_processed_data', get_processed_data) + self._set_if_present('allocated_buffers', allocated_buffers) + self._set_if_present('buffer_timeout', buffer_timeout) # endregion - self.parameters['mode']._set_updated() - if not (self.parameters['mode'].get() == 'TS' or self.parameters['mode'].get() == 'NPT'): - raise Exception("Only the 'TS' and 'NPT' modes are implemented at this point") + self.mode._set_updated() + if self.mode.get() not in ('TS', 'NPT'): + raise Exception("Only the 'TS' and 'NPT' modes are implemented " + "at this point") # -----set final configurations----- # Abort any previous measurement - return_code = self._ATS_dll.AlazarAbortAsyncRead(self._handle) - self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") + self._call_dll('AlazarAbortAsyncRead') # get channel info bps = np.array([0], dtype=np.uint8) # bps bits per sample max_s = np.array([0], dtype=np.uint32) # max_s memory size in samples - return_code = self._ATS_dll.AlazarGetChannelInfo(self._handle, max_s.ctypes.data, bps.ctypes.data) - self._result_handler(error_code=return_code, error_source="AlazarGetChannelInfo") + self._call_dll('AlazarGetChannelInfo', + args=[max_s.ctypes.data, bps.ctypes.data]) bps = bps[0] max_s = max_s[0] - if not bps == 8: + if bps != 8: raise Exception("Only 8 bits per sample supported at this moment") # Set record size for NPT mode - if self.parameters['mode'].get() == 'NPT': + if self.mode.get() == 'NPT': pretriggersize = 0 # pretriggersize is 0 for NPT always - post_trigger_size = self.parameters['samples_per_record']._get_byte() - return_code = self._ATS_dll.AlazarSetRecordSize(self._handle, pretriggersize, post_trigger_size) - self._result_handler(error_code=return_code, error_source="AlazarSetRecordSize") - + post_trigger_size = self.samples_per_record._get_byte() + self._call_dll('AlazarSetRecordSize', + args=[pretriggersize, post_trigger_size]) # set acquisition parameters here for NPT, TS mode - if self.parameters['channel_selection']._get_byte() == 3: + if self.channel_selection._get_byte() == 3: number_of_channels = 2 else: number_of_channels = 1 samples_per_buffer = 0 - acquire_flags = self.parameters['mode']._get_byte() | \ - self.parameters['external_startcapture']._get_byte() | \ - self.parameters['enable_record_headers']._get_byte() | \ - self.parameters['alloc_buffers']._get_byte() | \ - self.parameters['fifo_only_streaming']._get_byte() | \ - self.parameters['interleave_samples']._get_byte() | \ - self.parameters['get_processed_data']._get_byte() + buffers_per_acquisition = self.buffers_per_acquisition._get_byte() + samples_per_record = self.samples_per_record._get_byte() + acquire_flags = (self.mode._get_byte() | + self.external_startcapture._get_byte() | + self.enable_record_headers._get_byte() | + self.alloc_buffers._get_byte() | + self.fifo_only_streaming._get_byte() | + self.interleave_samples._get_byte() | + self.get_processed_data._get_byte()) + if self.parameters['mode'].get() == 'NPT': - samples_per_record = self.parameters['samples_per_record']._get_byte() - records_per_buffer = self.parameters['records_per_buffer']._get_byte() - records_per_acquisition = records_per_buffer * self.parameters['buffers_per_acquisition']._get_byte() + records_per_buffer = self.records_per_buffer._get_byte() + records_per_acquisition = ( + records_per_buffer * buffers_per_acquisition) samples_per_buffer = samples_per_record * records_per_buffer - return_code = self._ATS_dll.AlazarBeforeAsyncRead(self._handle, - self.parameters['channel_selection']._get_byte(), - self.parameters['transfer_offset']._get_byte(), - samples_per_record, - records_per_buffer, - records_per_acquisition, - acquire_flags) - self._result_handler(error_code=return_code, error_source="AlazarBeforeAsyncRead") + + self._call_dll('AlazarBeforeAsyncRead', + args=['channel_selection', 'transfer_offset', + samples_per_record, records_per_buffer, + records_per_acquisition, acquire_flags]) + elif self.parameters['mode'].get() == 'TS': - if not self.parameters['samples_per_record']._get_byte() % self.parameters['buffers_per_acquisition'] == 0: - logging.warning("buffers_per_acquisition is not a divisor of samples per record which it should be in" - " TS mode, rounding down in samples per buffer calculation") - samples_per_buffer = int(self.parameters['samples_per_record']._get_byte() / self.parameters['buffers_per_acquisition']) - buffers_per_acquisition = self.parameters['buffers_per_acquisition']._get_byte() - if not self.parameters['records_per_buffer']._get_byte() == 1: - logging.warning('records_per_buffer should be 1 in TS mode, defauling to 1') - self.parameters['records_per_buffer']._set(1) - records_per_buffer = self.parameters['records_per_buffer']._get_byte() - return_code = self._ATS_dll.AlazarBeforeAsyncRead(self._handle, - self.parameters['channel_selection']._get_byte(), - self.parameters['transfer_offset']._get_byte(), - samples_per_buffer, - records_per_buffer, - buffers_per_acquisition, - acquire_flags) - self._result_handler(error_code=return_code, error_source="AlazarBeforeAsyncRead") - self.parameters['samples_per_record']._set_updated() - self.parameters['records_per_buffer']._set_updated() - self.parameters['buffers_per_acquisition']._set_updated() - self.parameters['channel_selection']._set_updated() - self.parameters['transfer_offset']._set_updated() - self.parameters['external_startcapture']._set_updated() - self.parameters['enable_record_headers']._set_updated() - self.parameters['alloc_buffers']._set_updated() - self.parameters['fifo_only_streaming']._set_updated() - self.parameters['interleave_samples']._set_updated() + if (samples_per_record % buffers_per_acquisition != 0): + logging.warning('buffers_per_acquisition is not a divisor of ' + 'samples per record which it should be in ' + 'TS mode, rounding down in samples per buffer ' + 'calculation') + samples_per_buffer = int(samples_per_record / + buffers_per_acquisition) + if self.records_per_buffer._get_byte() != 1: + logging.warning('records_per_buffer should be 1 in TS mode, ' + 'defauling to 1') + self.records_per_buffer._set(1) + records_per_buffer = self.records_per_buffer._get_byte() + + self._call_dll('AlazarBeforeAsyncRead', + args=['channel_selection', 'transfer_offset', + samples_per_buffer, 'records_per_buffer', + buffers_per_acquisition, acquire_flags]) + + self.samples_per_record._set_updated() + self.records_per_buffer._set_updated() + self.buffers_per_acquisition._set_updated() + self.channel_selection._set_updated() + self.transfer_offset._set_updated() + self.external_startcapture._set_updated() + self.enable_record_headers._set_updated() + self.alloc_buffers._set_updated() + self.fifo_only_streaming._set_updated() + self.interleave_samples._set_updated() self.parameters['get_processed_data']._set_updated() # create buffers for acquisition self.clear_buffers() - for k in range(self.parameters['allocated_buffers']._get_byte()): + allocated_buffers = self.allocated_buffers._get_byte() + for k in range(allocated_buffers): try: - self.buffer_list.append(Buffer(bps, samples_per_buffer, number_of_channels)) + self.buffer_list.append(Buffer(bps, samples_per_buffer, + number_of_channels)) except: self.clear_buffers() raise # post buffers to Alazar for buf in self.buffer_list: - return_code = self._ATS_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) - self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") - self.parameters['allocated_buffers']._set_updated() + self._call_dll('AlazarPostAsyncBuffer', + args=[buf.addr, buf.size_bytes]) + self.allocated_buffers._set_updated() # -----start capture here----- acquisition_controller.pre_start_capture(self) # call the startcapture method - return_code = self._ATS_dll.AlazarStartCapture(self._handle) - self._result_handler(error_code=return_code, error_source="AlazarStartCapture") + self._call_dll('AlazarStartCapture') acquisition_controller.pre_acquire(self) # buffer handling from acquisition buffers_completed = 0 - buffer_timeout = self.parameters['buffer_timeout']._get_byte() - self.parameters['buffer_timeout']._set_updated() + buffer_timeout = self.buffer_timeout._get_byte() + self.buffer_timeout._set_updated() - buffer_recycling = False - if self.parameters['buffers_per_acquisition']._get_byte() > self.parameters['allocated_buffers']._get_byte(): - buffer_recycling = True + buffer_recycling = (self.buffers_per_acquisition._get_byte() > + self.allocated_buffers._get_byte()) - while buffers_completed < self.parameters['buffers_per_acquisition']._get_byte(): - buf = self.buffer_list[buffers_completed % self.parameters['allocated_buffers']._get_byte()] + while buffers_completed < self.buffers_per_acquisition._get_byte(): + buf = self.buffer_list[buffers_completed % allocated_buffers] - return_code = self._ATS_dll.AlazarWaitAsyncBufferComplete(self._handle, buf.addr, buffer_timeout) - self._result_handler(error_code=return_code, error_source="AlazarWaitAsyncBufferComplete") + self._call_dll('AlazarWaitAsyncBufferComplete', + args=[buf.addr, buffer_timeout]) - # TODO (C) last series of buffers must be handled exceptionally (and I want to test the difference) - # TODO (C) by changing buffer recycling for the last series of buffers + # TODO (C) last series of buffers must be handled exceptionally + # (and I want to test the difference) by changing buffer + # recycling for the last series of buffers # if buffers must be recycled, extract data and repost them # otherwise continue to next buffer if buffer_recycling: acquisition_controller.handle_buffer(self, buf.buffer) - return_code = self._ATS_dll.AlazarPostAsyncBuffer(self._handle, buf.addr, buf.size_bytes) - self._result_handler(error_code=return_code, error_source="AlazarPostAsyncBuffer") + self._call_dll('AlazarPostAsyncBuffer', + args=[buf.addr, buf.size_bytes]) buffers_completed += 1 # stop measurement here - return_code = self._ATS_dll.AlazarAbortAsyncRead(self._handle) - self._result_handler(error_code=return_code, error_source="AlazarAbortAsyncRead") + self._call_dll('AlazarAbortAsyncRead') # -----cleanup here----- # extract data if not yet done @@ -396,56 +422,64 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, b # return result return acquisition_controller.post_acquire(self) - def _result_handler(self, error_code=0, error_source=""): - # region error codes - error_codes = {513: 'ApiFailed', 514: 'ApiAccessDenied', 515: 'ApiDmaChannelUnavailable', - 516: 'ApiDmaChannelInvalid', 517: 'ApiDmaChannelTypeError', 518: 'ApiDmaInProgress', - 519: 'ApiDmaDone', 520: 'ApiDmaPaused', 521: 'ApiDmaNotPaused', - 522: 'ApiDmaCommandInvalid', 523: 'ApiDmaManReady', 524: 'ApiDmaManNotReady', - 525: 'ApiDmaInvalidChannelPriority', 526: 'ApiDmaManCorrupted', - 527: 'ApiDmaInvalidElementIndex', 528: 'ApiDmaNoMoreElements', - 529: 'ApiDmaSglInvalid', - 530: 'ApiDmaSglQueueFull', 531: 'ApiNullParam', 532: 'ApiInvalidBusIndex', - 533: 'ApiUnsupportedFunction', 534: 'ApiInvalidPciSpace', 535: 'ApiInvalidIopSpace', - 536: 'ApiInvalidSize', 537: 'ApiInvalidAddress', 538: 'ApiInvalidAccessType', - 539: 'ApiInvalidIndex', 540: 'ApiMuNotReady', 541: 'ApiMuFifoEmpty', - 542: 'ApiMuFifoFull', - 543: 'ApiInvalidRegister', 544: 'ApiDoorbellClearFailed', 545: 'ApiInvalidUserPin', - 546: 'ApiInvalidUserState', 547: 'ApiEepromNotPresent', - 548: 'ApiEepromTypeNotSupported', - 549: 'ApiEepromBlank', 550: 'ApiConfigAccessFailed', 551: 'ApiInvalidDeviceInfo', - 552: 'ApiNoActiveDriver', 553: 'ApiInsufficientResources', - 554: 'ApiObjectAlreadyAllocated', - 555: 'ApiAlreadyInitialized', 556: 'ApiNotInitialized', - 557: 'ApiBadConfigRegEndianMode', 558: 'ApiInvalidPowerState', 559: 'ApiPowerDown', - 560: 'ApiFlybyNotSupported', - 561: 'ApiNotSupportThisChannel', 562: 'ApiNoAction', 563: 'ApiHSNotSupported', - 564: 'ApiVPDNotSupported', 565: 'ApiVpdNotEnabled', 566: 'ApiNoMoreCap', - 567: 'ApiInvalidOffset', - 568: 'ApiBadPinDirection', 569: 'ApiPciTimeout', 570: 'ApiDmaChannelClosed', - 571: 'ApiDmaChannelError', 572: 'ApiInvalidHandle', 573: 'ApiBufferNotReady', - 574: 'ApiInvalidData', - 575: 'ApiDoNothing', 576: 'ApiDmaSglBuildFailed', 577: 'ApiPMNotSupported', - 578: 'ApiInvalidDriverVersion', - 579: 'ApiWaitTimeout: operation did not finish during timeout interval. Check your trigger.', - 580: 'ApiWaitCanceled', 581: 'ApiBufferTooSmall', - 582: 'ApiBufferOverflow:rate of acquiring data > rate of transferring data to local memory. Try reducing sample rate, reducing number of enabled channels, increasing size of each DMA buffer or increase number of DMA buffers.', - 583: 'ApiInvalidBuffer', 584: 'ApiInvalidRecordsPerBuffer', - 585: 'ApiDmaPending:Async I/O operation was succesfully started, it will be completed when sufficient trigger events are supplied to fill the buffer.', - 586: 'ApiLockAndProbePagesFailed:Driver or operating system was unable to prepare the specified buffer for DMA transfer. Try reducing buffer size or total number of buffers.', - 587: 'ApiWaitAbandoned', 588: 'ApiWaitFailed', - 589: 'ApiTransferComplete:This buffer is last in the current acquisition.', - 590: 'ApiPllNotLocked:hardware error, contact AlazarTech', - 591: 'ApiNotSupportedInDualChannelMode:Requested number of samples per channel is too large to fit in on-board memory. Try reducing number of samples per channel, or switch to single channel mode.'} - # endregion - if error_code == self._succes: - return None - else: + def _set_if_present(self, param_name, value): + if value is not None: + self.parameters[param_name]._set(value) + + def _set_list_if_present(self, param_base, value): + if value is not None: + for i, v in enumerate(value): + self.parameters[param_base + str(i + 1)]._set(v) + + def _call_dll(self, func_name, args=[], i=None): + """ + execute a dll function `func_name`, passing it: + - self._handle + - an optional index `i` + - a sequence of parameter names and arguments from `args` + - if an arg is a string, it's assumed to be a parameter name + and the parameter value (._get_bytes()) is used. if `i` is + provided, it will be inserted in each parameter name + using .format(i) (eg if i=2, 'coupling{}' becomes 'coupling2') + After the call succeeds, these parameters will be marked as + updated + - if an arg is NOT a string, it is inserted directly + """ + # create the argument list + args_out = [] if i is None else [i] + params = [] + for arg in args: + if isinstance(arg, str): + param = self.parameters[arg.format(i)] + args_out.append(param._get_byte()) + params.append(param) + else: + args_out.append(arg) + + # run the function + func = getattr(self._ATS_dll, func_name) + return_code = func(self._handle, *args_out) + + # check for errors + if return_code != self._success: # TODO (C) log error - if error_code not in error_codes: - raise KeyError(error_source+" raised unknown error "+str(error_code)) - raise Exception(error_source+" raised "+str(error_code)+": "+error_codes[error_code]) + argrepr = repr(args_out) + if len(argrepr) > 100: + argrepr = argrepr[:96] + '...]' + + if return_code not in self._error_codes: + raise RuntimeError( + 'unknown error {} from function {} with args: {}'.format( + return_code, func_name, argrepr)) + raise RuntimeError( + 'error {}: {} from function {} with args: {}'.format( + return_code, self._error_codes[return_code], func_name, + argrepr)) + + # mark parameters updated + for param in params: + param._set_updated() def clear_buffers(self): for b in self.buffer_list: @@ -455,26 +489,28 @@ def clear_buffers(self): def signal_to_volt(self, channel, signal): # TODO (S) check this # TODO (M) use byte value if range{channel} - return ((signal - 127.5) / 127.5) * (self.parameters["channel_range" + str(channel)].get()) + return (((signal - 127.5) / 127.5) * + (self.parameters['channel_range' + str(channel)].get())) def get_sample_speed(self): - if self.parameters['sample_rate'].get() == 'EXTERNAL_CLOCK': - raise Exception('External clock is used, alazar driver could not determine sample speed.') + if self.sample_rate.get() == 'EXTERNAL_CLOCK': + raise Exception('External clock is used, alazar driver ' + 'could not determine sample speed.') - rate = 0 - if self.parameters['sample_rate'].get() == '1GHz_REFERENCE_CLOCK': + rate = self.sample_rate.get() + if rate == '1GHz_REFERENCE_CLOCK': rate = 1e9 - else: - rate = self.parameters['sample_rate'].get() - if self.parameters["decimation"].get() > 0: - return rate / self.parameters["decimation"].get() + decimation = self.decimation.get() + if decimation > 0: + return rate / decimation else: return rate class AlazarParameter(Parameter): - def __init__(self, name=None, label=None, unit=None, instrument=None, value=None, byte_to_value_dict=None, vals=None): + def __init__(self, name=None, label=None, unit=None, instrument=None, + value=None, byte_to_value_dict=None, vals=None): if vals is None: if byte_to_value_dict is None: vals = validators.Anything() @@ -493,7 +529,8 @@ def __init__(self, name=None, label=None, unit=None, instrument=None, value=None self._value_to_byte_dict = TrivialDictionary() else: self._byte_to_value_dict = byte_to_value_dict - self._value_to_byte_dict = {v: k for k, v in self._byte_to_value_dict.items()} + self._value_to_byte_dict = { + v: k for k, v in self._byte_to_value_dict.items()} self._set(value) @@ -504,10 +541,13 @@ def get(self): """ # TODO (S) test this exception if self._uptodate_flag is False: - raise Exception('The value of this parameter (' + str(self.name) + ') is not up to date with the actual ' - 'value in the instrument.' - '\n Most probable cause is illegal usage of ._set() method of this parameter.' - '\n Don\'t use private methods if you do not know what you are doing!') + raise Exception('The value of this parameter (' + self.name + + ') is not up to date with the actual value in ' + 'the instrument.\n' + 'Most probable cause is illegal usage of ._set() ' + 'method of this parameter.\n' + 'Don\'t use private methods if you do not know ' + 'what you are doing!') return self._byte_to_value_dict[self._byte] def _get_byte(self): @@ -520,7 +560,8 @@ def _get_byte(self): def _set(self, value): """ This method sets the value of this parameter - This method is private to ensure that all values in the instruments are up to date always + This method is private to ensure that all values in the instruments + are up to date always :param value: the new value (e.g. 'NPT', 0.5, ...) :return: None """ @@ -536,10 +577,11 @@ def _set_updated(self): class Buffer: - def __init__(self, bits_per_sample, samples_per_buffer, number_of_channels): - if not bits_per_sample == 8: + def __init__(self, bits_per_sample, samples_per_buffer, + number_of_channels): + if bits_per_sample != 8: raise Exception("Buffer: only 8 bit per sample supported") - if not os.name == 'nt': + if os.name != 'nt': raise Exception("Buffer: only Windows supported at this moment") self._allocated = True @@ -549,33 +591,41 @@ def __init__(self, bits_per_sample, samples_per_buffer, number_of_channels): self.size_bytes = samples_per_buffer * number_of_channels - # please see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx for documentation - ctypes.windll.kernel32.VirtualAlloc.argtypes = [ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long] + # for documentation please see: + # https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx + ctypes.windll.kernel32.VirtualAlloc.argtypes = [ + ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long] ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p - self.addr = ctypes.windll.kernel32.VirtualAlloc(0, ctypes.c_long(self.size_bytes), mem_commit, page_readwrite) + self.addr = ctypes.windll.kernel32.VirtualAlloc( + 0, ctypes.c_long(self.size_bytes), mem_commit, page_readwrite) if self.addr is None: self._allocated = False e = ctypes.windll.kernel32.GetLastError() raise Exception("Memory allocation error: " + str(e)) - ctypes_array = (ctypes.c_uint8 * self.size_bytes).from_address(self.addr) + ctypes_array = (ctypes.c_uint8 * + self.size_bytes).from_address(self.addr) self.buffer = np.frombuffer(ctypes_array, dtype=np.uint8) pointer, read_only_flag = self.buffer.__array_interface__['data'] def free_mem(self): mem_release = 0x8000 - # see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366892(v=vs.85).aspx - ctypes.windll.kernel32.VirtualFree.argtypes = [ctypes.c_void_p, ctypes.c_long, ctypes.c_long] + # for documentation please see: + # https://msdn.microsoft.com/en-us/library/windows/desktop/aa366892(v=vs.85).aspx + ctypes.windll.kernel32.VirtualFree.argtypes = [ + ctypes.c_void_p, ctypes.c_long, ctypes.c_long] ctypes.windll.kernel32.VirtualFree.restype = ctypes.c_int - ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(self.addr), 0, mem_release) + ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(self.addr), 0, + mem_release) self._allocated = False def __del__(self): if self._allocated: self.free_mem() - logging.warning("Buffer prevented memory leak; Memory released to Windows.\n" - "Memory should have been released before buffer was deleted.") + logging.warning( + 'Buffer prevented memory leak; Memory released to Windows.\n' + 'Memory should have been released before buffer was deleted.') class AcquisitionController: @@ -591,7 +641,8 @@ def pre_start_capture(self, alazar): :param alazar: :return: """ - raise NotImplementedError("This method should be implemented in the implementation") + raise NotImplementedError( + 'This method should be implemented in a subclass') def pre_acquire(self, alazar): """ @@ -599,7 +650,8 @@ def pre_acquire(self, alazar): :param alazar: a reference to the alazar driver :return: nothing """ - raise NotImplementedError("This method should be implemented in the implementation") + raise NotImplementedError( + 'This method should be implemented in a subclass') def handle_buffer(self, alazar, buffer): """ @@ -607,14 +659,16 @@ def handle_buffer(self, alazar, buffer): :return: something, it is ignored in any case """ raise NotImplementedError( - "This method should be implemented in the implementation of the AcquisitionController class") + 'This method should be implemented in a subclass') def post_acquire(self, alazar): """ :param alazar: a reference to the alazar driver - :return: this function should return all relevant data that you want to get form the acquisition + :return: this function should return all relevant data that you want + to get form the acquisition """ - raise NotImplementedError("This method should be implemented somewhere") + raise NotImplementedError( + 'This method should be implemented in a subclass') class TrivialDictionary: @@ -626,4 +680,4 @@ def __getitem__(self, item): def __contains__(self, item): # this makes sure that this dictionary contains everything - return True \ No newline at end of file + return True diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 459b881c16d1..0596d1bb3a40 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -1,174 +1,246 @@ from .ATS import AlazarTech_ATS, AlazarParameter from qcodes.utils import validators + class AlazarTech_ATS9870(AlazarTech_ATS): def __init__(self, name): super().__init__(name) # add parameters # ----- Parameters for the configuration of the board ----- - self.add_parameter(name='clock_source', parameter_class=AlazarParameter, label='Clock Source', unit=None, + self.add_parameter(name='clock_source', + parameter_class=AlazarParameter, + label='Clock Source', + unit=None, value='INTERNAL_CLOCK', byte_to_value_dict={1: 'INTERNAL_CLOCK', 4: 'SLOW_EXTERNAL_CLOCK', 5: 'EXTERNAL_CLOCK_AC', 7: 'EXTERNAL_CLOCK_10_MHz_REF'}) - self.add_parameter(name='sample_rate', parameter_class=AlazarParameter, label='Sample Rate', unit='S/s', + self.add_parameter(name='sample_rate', + parameter_class=AlazarParameter, + label='Sample Rate', + unit='S/s', value=1000000000, - byte_to_value_dict={0x1: 1000, 0x2: 2000, 0x4: 5000, - 0x8: 10000, 0xA: 20000, 0xC: 50000, - 0xE: 100000, 0x10: 200000, 0x12: 500000, - 0x14: 1000000, 0x18: 2000000, 0x1A: 5000000, - 0x1C: 10000000, 0x1E: 20000000, 0x22: 50000000, - 0x24: 100000000, 0x2B: 250000000, 0x30: 500000000, - 0x35: 1000000000, - 0x40: 'EXTERNAL_CLOCK', - 1000000000: '1GHz_REFERENCE_CLOCK'}) - self.add_parameter(name='clock_edge', parameter_class=AlazarParameter, label='Clock Edge', unit=None, + byte_to_value_dict={ + 0x1: 1000, 0x2: 2000, 0x4: 5000, 0x8: 10000, + 0xA: 20000, 0xC: 50000, 0xE: 100000, + 0x10: 200000, 0x12: 500000, 0x14: 1000000, + 0x18: 2000000, 0x1A: 5000000, 0x1C: 10000000, + 0x1E: 20000000, 0x22: 50000000, 0x24: 100000000, + 0x2B: 250000000, 0x30: 500000000, + 0x35: 1000000000, 0x40: 'EXTERNAL_CLOCK', + 1000000000: '1GHz_REFERENCE_CLOCK'}) + self.add_parameter(name='clock_edge', + parameter_class=AlazarParameter, + label='Clock Edge', + unit=None, value='CLOCK_EDGE_RISING', byte_to_value_dict={0: 'CLOCK_EDGE_RISING', 1: 'CLOCK_EDGE_FALLING'}) - self.add_parameter(name='decimation', parameter_class=AlazarParameter, label='Decimation', unit=None, - value=0, vals=validators.Ints(0, 100000)) - - self.add_parameter(name='coupling1', parameter_class=AlazarParameter, label='Coupling channel 1', unit=None, - value='AC', - byte_to_value_dict={1: 'AC', 2: 'DC'}) - self.add_parameter(name='coupling2', parameter_class=AlazarParameter, label='Coupling channel 2', unit=None, - value='AC', - byte_to_value_dict={1: 'AC', 2: 'DC'}) + self.add_parameter(name='decimation', + parameter_class=AlazarParameter, + label='Decimation', + unit=None, + value=0, + vals=validators.Ints(0, 100000)) - self.add_parameter(name='channel_range1', parameter_class=AlazarParameter, label='Range channel 1', unit='V', - value=4, - byte_to_value_dict={2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4.}) - self.add_parameter(name='channel_range2', parameter_class=AlazarParameter, label='Range channel 2', unit='V', - value=4, - byte_to_value_dict={2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4.}) - - self.add_parameter(name='impedance1', parameter_class=AlazarParameter, label='Impedance channel 1', unit='Ohm', - value=50, - byte_to_value_dict={1: 1000000, 2: 50}) - self.add_parameter(name='impedance2', parameter_class=AlazarParameter, label='Impedance channel 2', unit='Ohm', - value=50, - byte_to_value_dict={1: 1000000, 2: 50}) - - self.add_parameter(name='bwlimit1', parameter_class=AlazarParameter, label='Bandwidth limit channel 1', unit=None, - value='DISABLED', - byte_to_value_dict={0: 'DISABLED', 1: 'ENABLED'}) - self.add_parameter(name='bwlimit2', parameter_class=AlazarParameter, label='Bandwidth limit channel 2', unit=None, - value='DISABLED', - byte_to_value_dict={0: 'DISABLED', 1: 'ENABLED'}) + for i in ['1', '2']: + self.add_parameter(name='coupling' + i, + parameter_class=AlazarParameter, + label='Coupling channel ' + i, + unit=None, + value='AC', + byte_to_value_dict={1: 'AC', 2: 'DC'}) + self.add_parameter(name='channel_range' + i, + parameter_class=AlazarParameter, + label='Range channel ' + i, + unit='V', + value=4, + byte_to_value_dict={ + 2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, + 10: 1., 11: 2., 12: 4.}) + self.add_parameter(name='impedance' + i, + parameter_class=AlazarParameter, + label='Impedance channel ' + i, + unit='Ohm', + value=50, + byte_to_value_dict={1: 1000000, 2: 50}) + self.add_parameter(name='bwlimit' + i, + parameter_class=AlazarParameter, + label='Bandwidth limit channel ' + i, + unit=None, + value='DISABLED', + byte_to_value_dict={0: 'DISABLED', + 1: 'ENABLED'}) - self.add_parameter(name='trigger_operation', parameter_class=AlazarParameter, label='Trigger Operation', unit=None, + self.add_parameter(name='trigger_operation', + parameter_class=AlazarParameter, + label='Trigger Operation', + unit=None, value='TRIG_ENGINE_OP_J', - byte_to_value_dict={0: 'TRIG_ENGINE_OP_J', - 1: 'TRIG_ENGINE_OP_K', - 2: 'TRIG_ENGINE_OP_J_OR_K', - 3: 'TRIG_ENGINE_OP_J_AND_K', - 4: 'TRIG_ENGINE_OP_J_XOR_K', - 5: 'TRIG_ENGINE_OP_J_AND_NOT_K', - 6: 'TRIG_ENGINE_OP_NOT_J_AND_K'}) - self.add_parameter(name='trigger_engine1', parameter_class=AlazarParameter, label='Trigger Engine 1', unit=None, - value='TRIG_ENGINE_J', - byte_to_value_dict={0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K'}) - self.add_parameter(name='trigger_engine2', parameter_class=AlazarParameter, label='Trigger Engine 2', unit=None, - value='TRIG_ENGINE_K', - byte_to_value_dict={0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K'}) - self.add_parameter(name='trigger_source1', parameter_class=AlazarParameter, label='Trigger Source 1', unit=None, - value='EXTERNAL', - byte_to_value_dict={0: 'CHANNEL_A', - 1: 'CHANNEL_B', - 2: 'EXTERNAL', - 3: 'DISABLE'}) - self.add_parameter(name='trigger_source2', parameter_class=AlazarParameter, label='Trigger Source 2', unit=None, - value='DISABLE', - byte_to_value_dict={0: 'CHANNEL_A', - 1: 'CHANNEL_B', - 2: 'EXTERNAL', - 3: 'DISABLE'}) - self.add_parameter(name='trigger_slope1', parameter_class=AlazarParameter, label='Trigger Slope 1', unit=None, - value='TRIG_SLOPE_POSITIVE', - byte_to_value_dict={1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE'}) - self.add_parameter(name='trigger_slope2', parameter_class=AlazarParameter, label='Trigger Slope 2', unit=None, - value='TRIG_SLOPE_POSITIVE', - byte_to_value_dict={1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE'}) - self.add_parameter(name='trigger_level1', parameter_class=AlazarParameter, label='Trigger Level 1', unit=None, - value=128, vals=validators.Ints(0, 255)) - self.add_parameter(name='trigger_level2', parameter_class=AlazarParameter, label='Trigger Level 2', unit=None, - value=128, vals=validators.Ints(0, 255)) - - self.add_parameter(name='external_trigger_coupling', parameter_class=AlazarParameter, - label='External Trigger Coupling', unit=None, + byte_to_value_dict={ + 0: 'TRIG_ENGINE_OP_J', + 1: 'TRIG_ENGINE_OP_K', + 2: 'TRIG_ENGINE_OP_J_OR_K', + 3: 'TRIG_ENGINE_OP_J_AND_K', + 4: 'TRIG_ENGINE_OP_J_XOR_K', + 5: 'TRIG_ENGINE_OP_J_AND_NOT_K', + 6: 'TRIG_ENGINE_OP_NOT_J_AND_K'}) + for i in ['1', '2']: + self.add_parameter(name='trigger_engine' + i, + parameter_class=AlazarParameter, + label='Trigger Engine ' + i, + unit=None, + value='TRIG_ENGINE_J', + byte_to_value_dict={0: 'TRIG_ENGINE_J', + 1: 'TRIG_ENGINE_K'}) + self.add_parameter(name='trigger_source' + i, + parameter_class=AlazarParameter, + label='Trigger Source ' + i, + unit=None, + value='DISABLE', + byte_to_value_dict={0: 'CHANNEL_A', + 1: 'CHANNEL_B', + 2: 'EXTERNAL', + 3: 'DISABLE'}) + self.add_parameter(name='trigger_slope' + i, + parameter_class=AlazarParameter, + label='Trigger Slope ' + i, + unit=None, + value='TRIG_SLOPE_POSITIVE', + byte_to_value_dict={1: 'TRIG_SLOPE_POSITIVE', + 2: 'TRIG_SLOPE_NEGATIVE'}) + self.add_parameter(name='trigger_level' + i, + parameter_class=AlazarParameter, + label='Trigger Level ' + i, + unit=None, + value=128, + vals=validators.Ints(0, 255)) + + self.add_parameter(name='external_trigger_coupling', + parameter_class=AlazarParameter, + label='External Trigger Coupling', + unit=None, value='AC', byte_to_value_dict={1: 'AC', 2: 'DC'}) - self.add_parameter(name='external_trigger_range', parameter_class=AlazarParameter, - label='External Trigger Range', unit=None, + self.add_parameter(name='external_trigger_range', + parameter_class=AlazarParameter, + label='External Trigger Range', + unit=None, value='ETR_5V', byte_to_value_dict={0: 'ETR_5V', 1: 'ETR_1V'}) - self.add_parameter(name='trigger_delay', parameter_class=AlazarParameter, - label='Trigger Delay', unit='Sample clock cycles', - value=0, vals=validators.Ints(min_value=0)) - self.add_parameter(name='timeout_ticks', parameter_class=AlazarParameter, - label='Timeout Ticks', unit='10 us', - value=0, vals=validators.Ints(min_value=0)) + self.add_parameter(name='trigger_delay', + parameter_class=AlazarParameter, + label='Trigger Delay', + unit='Sample clock cycles', + value=0, + vals=validators.Ints(min_value=0)) + self.add_parameter(name='timeout_ticks', + parameter_class=AlazarParameter, + label='Timeout Ticks', + unit='10 us', + value=0, + vals=validators.Ints(min_value=0)) # ----- Parameters for the acquire function ----- - self.add_parameter(name='mode', parameter_class=AlazarParameter, - label='Acquisiton mode', unit=None, + self.add_parameter(name='mode', + parameter_class=AlazarParameter, + label='Acquisiton mode', + unit=None, value='NPT', byte_to_value_dict={0x200: 'NPT', 0x400: 'TS'}) # samples_per_record must be a multiple of 16! - self.add_parameter(name='samples_per_record', parameter_class=AlazarParameter, - label='Samples per Record', unit=None, - value=96000, vals=Multiples(divisor=16, min_value=0)) - # TODO (M) figure out if this also has to be a multiple of something, I could not find this in the documentation - # but somehow I have the feeling it still should be a multiple of something - self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, - label='Records per Buffer', unit=None, - value=1, vals=validators.Ints(min_value=0)) - self.add_parameter(name='buffers_per_acquisition', parameter_class=AlazarParameter, - label='Buffers per Acquisition', unit=None, - value=1, vals=validators.Ints(min_value=0)) - self.add_parameter(name='channel_selection', parameter_class=AlazarParameter, - label='Channel Selection', unit=None, + self.add_parameter(name='samples_per_record', + parameter_class=AlazarParameter, + label='Samples per Record', + unit=None, + value=96000, + vals=Multiples(divisor=16, min_value=0)) + # TODO (M) figure out if this also has to be a multiple of something, + # I could not find this in the documentation but somehow I have the + # feeling it still should be a multiple of something + self.add_parameter(name='records_per_buffer', + parameter_class=AlazarParameter, + label='Records per Buffer', + unit=None, + value=1, + vals=validators.Ints(min_value=0)) + self.add_parameter(name='buffers_per_acquisition', + parameter_class=AlazarParameter, + label='Buffers per Acquisition', + unit=None, + value=1, + vals=validators.Ints(min_value=0)) + self.add_parameter(name='channel_selection', + parameter_class=AlazarParameter, + label='Channel Selection', + unit=None, value='AB', byte_to_value_dict={1: 'A', 2: 'B', 3: 'AB'}) - self.add_parameter(name='transfer_offset', parameter_class=AlazarParameter, - label='Transer Offset', unit='Samples', - value=0, vals=validators.Ints(min_value=0)) - self.add_parameter(name='external_startcapture', parameter_class=AlazarParameter, - label='External Startcapture', unit=None, + self.add_parameter(name='transfer_offset', + parameter_class=AlazarParameter, + label='Transer Offset', + unit='Samples', + value=0, + vals=validators.Ints(min_value=0)) + self.add_parameter(name='external_startcapture', + parameter_class=AlazarParameter, + label='External Startcapture', + unit=None, value='ENABLED', - byte_to_value_dict={0x0: 'DISABLED', 0x1: 'ENABLED'}) - self.add_parameter(name='enable_record_headers', parameter_class=AlazarParameter, - label='Enable Record Headers', unit=None, + byte_to_value_dict={0x0: 'DISABLED', + 0x1: 'ENABLED'}) + self.add_parameter(name='enable_record_headers', + parameter_class=AlazarParameter, + label='Enable Record Headers', + unit=None, value='DISABLED', - byte_to_value_dict={0x0: 'DISABLED', 0x8: 'ENABLED'}) - self.add_parameter(name='alloc_buffers', parameter_class=AlazarParameter, - label='Alloc Buffers', unit=None, + byte_to_value_dict={0x0: 'DISABLED', + 0x8: 'ENABLED'}) + self.add_parameter(name='alloc_buffers', + parameter_class=AlazarParameter, + label='Alloc Buffers', + unit=None, value='DISABLED', - byte_to_value_dict={0x0: 'DISABLED', 0x20: 'ENABLED'}) - self.add_parameter(name='fifo_only_streaming', parameter_class=AlazarParameter, - label='Fifo Only Streaming', unit=None, + byte_to_value_dict={0x0: 'DISABLED', + 0x20: 'ENABLED'}) + self.add_parameter(name='fifo_only_streaming', + parameter_class=AlazarParameter, + label='Fifo Only Streaming', + unit=None, value='DISABLED', - byte_to_value_dict={0x0: 'DISABLED', 0x800: 'ENABLED'}) - self.add_parameter(name='interleave_samples', parameter_class=AlazarParameter, - label='Interleave Samples', unit=None, + byte_to_value_dict={0x0: 'DISABLED', + 0x800: 'ENABLED'}) + self.add_parameter(name='interleave_samples', + parameter_class=AlazarParameter, + label='Interleave Samples', + unit=None, value='DISABLED', - byte_to_value_dict={0x0: 'DISABLED', 0x1000: 'ENABLED'}) - self.add_parameter(name='get_processed_data', parameter_class=AlazarParameter, - label='Get Processed Data', unit=None, + byte_to_value_dict={0x0: 'DISABLED', + 0x1000: 'ENABLED'}) + self.add_parameter(name='get_processed_data', + parameter_class=AlazarParameter, + label='Get Processed Data', + unit=None, value='DISABLED', - byte_to_value_dict={0x0: 'DISABLED', 0x2000: 'ENABLED'}) + byte_to_value_dict={0x0: 'DISABLED', + 0x2000: 'ENABLED'}) - self.add_parameter(name='allocated_buffers', parameter_class=AlazarParameter, - label='Allocated Buffers', unit=None, - value=1, vals=validators.Ints(min_value=0)) - self.add_parameter(name='buffer_timeout', parameter_class=AlazarParameter, - label='Buffer Timeout', unit='ms', - value=1000, vals=validators.Ints(min_value=0)) + self.add_parameter(name='allocated_buffers', + parameter_class=AlazarParameter, + label='Allocated Buffers', + unit=None, + value=1, + vals=validators.Ints(min_value=0)) + self.add_parameter(name='buffer_timeout', + parameter_class=AlazarParameter, + label='Buffer Timeout', + unit='ms', + value=1000, + vals=validators.Ints(min_value=0)) # TODO (M) make parameter for board type @@ -192,8 +264,8 @@ def __init__(self, divisor=1, **kwargs): def validate(self, value, context=''): super().validate(value=value, context=context) if not value % self._divisor == 0: - raise TypeError('{} is not a multiple of {}; {}'.format(repr(value), repr(self._divisor), context)) + raise TypeError('{} is not a multiple of {}; {}'.format( + repr(value), repr(self._divisor), context)) def __repr__(self): - super().__repr__() + ''.format(self._divisor) - + super().__repr__()[:-1] + ', Multiples of {}>'.format(self._divisor) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py index 89d1b4209669..4122d9da583d 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -17,20 +17,24 @@ def __init__(self, demodulation_frequency): self.buffer = None def pre_start_capture(self, alazar): - self.samples_per_record = alazar.parameters['samples_per_record'].get() - self.records_per_buffer = alazar.parameters['records_per_buffer'].get() - self.buffers_per_acquisition = alazar.parameters['buffers_per_acquisition'].get() + self.samples_per_record = alazar.samples_per_record.get() + self.records_per_buffer = alazar.records_per_buffer.get() + self.buffers_per_acquisition = alazar.buffers_per_acquisition.get() sample_speed = alazar.get_sample_speed() integer_list = np.arange(self.samples_per_record) + angle_list = (2 * np.pi * self.demodulation_frequency / sample_speed * + integer_list) - self.cos_list = np.cos(2 * np.pi * self.demodulation_frequency / sample_speed * integer_list) - self.sin_list = np.sin(2 * np.pi * self.demodulation_frequency / sample_speed * integer_list) - self.buffer = np.zeros(self.samples_per_record * self.records_per_buffer * self.number_of_channels) + self.cos_list = np.cos(angle_list) + self.sin_list = np.sin(angle_list) + self.buffer = np.zeros(self.samples_per_record * + self.records_per_buffer * + self.number_of_channels) def pre_acquire(self, alazar): # this could be used to start an Arbitrary Waveform Generator, etc... - # using this method ensures that the contents are executed AFTER the Alazar card starts listening for a - # trigger pulse + # using this method ensures that the contents are executed AFTER the + # Alazar card starts listening for a trigger pulse pass def handle_buffer(self, alazar, data): @@ -38,22 +42,27 @@ def handle_buffer(self, alazar, data): def post_acquire(self, alazar): # average all records in a buffer + records_per_acquisition = (1. * self.buffers_per_acquisition * + self.records_per_buffer) recordA = np.zeros(self.samples_per_record) for i in range(self.records_per_buffer): - recordA += self.buffer[i * self.samples_per_record: (i + 1) * self.samples_per_record] / ( - 1. * self.buffers_per_acquisition * self.records_per_buffer) + i0 = i * self.samples_per_record + i1 = i0 + self.samples_per_record + recordA += self.buffer[i0:i1] / records_per_acquisition recordB = np.zeros(self.samples_per_record) for i in range(self.records_per_buffer): - recordB += self.buffer[ - i * self.samples_per_record + len(self.buffer) / 2: (i + 1) * self.samples_per_record + len( - self.buffer) / 2] / (1. * self.buffers_per_acquisition * self.records_per_buffer) + i0 = i * self.samples_per_record + len(self.buffer) / 2 + i1 = i0 + self.samples_per_record + recordB += self.buffer[i0:i1] / records_per_acquisition if self.number_of_channels == 2: # fit channel A and channel B res1 = self.fit(recordA) res2 = self.fit(recordB) - return [alazar.signal_to_volt(1, res1[0] + 127.5), alazar.signal_to_volt(2, res2[0] + 127.5), res1[1], res2[1], + return [alazar.signal_to_volt(1, res1[0] + 127.5), + alazar.signal_to_volt(2, res2[0] + 127.5), + res1[1], res2[1], (res1[1] - res2[1]) % 360] else: raise Exception("Could not find CHANNEL_B during data extraction") @@ -61,10 +70,11 @@ def post_acquire(self, alazar): def fit(self, buf): # Discrete Fourier Transform - RePart = np.dot(buf - 127.5, self.cos_list) / float(self.samples_per_record) - ImPart = np.dot(buf - 127.5, self.sin_list) / float(self.samples_per_record) + RePart = np.dot(buf - 127.5, self.cos_list) / self.samples_per_record + ImPart = np.dot(buf - 127.5, self.sin_list) / self.samples_per_record - # the factor of 2 in the amplitude is due to the fact that there is a negative frequency as well + # the factor of 2 in the amplitude is due to the fact that there is + # a negative frequency as well ampl = 2 * np.sqrt(RePart ** 2 + ImPart ** 2) # see manual page 52!!! (using unsigned data) From 480df834596f0444fc36bca2cdc57133db618742 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Thu, 28 Apr 2016 12:03:23 +0200 Subject: [PATCH 19/56] refactor ATS _call_dll --- qcodes/instrument_drivers/AlazarTech/ATS.py | 105 ++++++++++---------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index dfa2e70f7d68..d67682d3918f 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -197,29 +197,35 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, # endregion self._call_dll('AlazarSetCaptureClock', - args=['clock_source', 'sample_rate', - 'clock_edge', 'decimation']) + self._handle, self.clock_source, self.sample_rate, + self.clock_edge, self.decimation) for i in [1, 2]: - self._call_dll('AlazarInputControl', i=i, - args=['coupling{}', 'channel_range{}', - 'impedance{}']) - self._call_dll('AlazarSetBWLimit', i=i, args=['bwlimit{}']) + self._call_dll('AlazarInputControl', + self._handle, i, + self.parameters['coupling' + str(i)], + self.parameters['channel_range' + str(i)], + self.parameters['impedance' + str(i)]) + self._call_dll('AlazarSetBWLimit', + self._handle, i, + self.parameters['bwlimit' + str(i)]) self._call_dll('AlazarSetTriggerOperation', - args=['trigger_operation', - 'trigger_engine1', 'trigger_source1', - 'trigger_slope1', 'trigger_level1', - 'trigger_engine2', 'trigger_source2', - 'trigger_slope2', 'trigger_level2']) + self._handle, self.trigger_operation, + self.trigger_engine1, self.trigger_source1, + self.trigger_slope1, self.trigger_level1, + self.trigger_engine2, self.trigger_source2, + self.trigger_slope2, self.trigger_level2) self._call_dll('AlazarSetExternalTrigger', - args=['external_trigger_coupling', - 'external_trigger_range']) + self._handle, self.external_trigger_coupling, + self.external_trigger_range) - self._call_dll('AlazarSetTriggerDelay', args=['trigger_delay']) + self._call_dll('AlazarSetTriggerDelay', + self._handle, self.trigger_delay) - self._call_dll('AlazarSetTriggerTimeOut', args=['timeout_ticks']) + self._call_dll('AlazarSetTriggerTimeOut', + self._handle, self.timeout_ticks) # TODO (W) config AUXIO @@ -276,13 +282,13 @@ def acquire(self, mode=None, samples_per_record=None, # -----set final configurations----- # Abort any previous measurement - self._call_dll('AlazarAbortAsyncRead') + self._call_dll('AlazarAbortAsyncRead', self._handle) # get channel info bps = np.array([0], dtype=np.uint8) # bps bits per sample max_s = np.array([0], dtype=np.uint32) # max_s memory size in samples self._call_dll('AlazarGetChannelInfo', - args=[max_s.ctypes.data, bps.ctypes.data]) + self._handle, max_s.ctypes.data, bps.ctypes.data) bps = bps[0] max_s = max_s[0] if bps != 8: @@ -293,7 +299,7 @@ def acquire(self, mode=None, samples_per_record=None, pretriggersize = 0 # pretriggersize is 0 for NPT always post_trigger_size = self.samples_per_record._get_byte() self._call_dll('AlazarSetRecordSize', - args=[pretriggersize, post_trigger_size]) + self._handle, pretriggersize, post_trigger_size) # set acquisition parameters here for NPT, TS mode if self.channel_selection._get_byte() == 3: @@ -318,9 +324,10 @@ def acquire(self, mode=None, samples_per_record=None, samples_per_buffer = samples_per_record * records_per_buffer self._call_dll('AlazarBeforeAsyncRead', - args=['channel_selection', 'transfer_offset', - samples_per_record, records_per_buffer, - records_per_acquisition, acquire_flags]) + self._handle, self.channel_selection, + self.transfer_offset, samples_per_record, + records_per_buffer, records_per_acquisition, + acquire_flags) elif self.parameters['mode'].get() == 'TS': if (samples_per_record % buffers_per_acquisition != 0): @@ -337,9 +344,10 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer = self.records_per_buffer._get_byte() self._call_dll('AlazarBeforeAsyncRead', - args=['channel_selection', 'transfer_offset', - samples_per_buffer, 'records_per_buffer', - buffers_per_acquisition, acquire_flags]) + self._handle, self.channel_selection, + self.transfer_offset, samples_per_buffer, + self.records_per_buffer, buffers_per_acquisition, + acquire_flags) self.samples_per_record._set_updated() self.records_per_buffer._set_updated() @@ -367,13 +375,13 @@ def acquire(self, mode=None, samples_per_record=None, # post buffers to Alazar for buf in self.buffer_list: self._call_dll('AlazarPostAsyncBuffer', - args=[buf.addr, buf.size_bytes]) + self._handle, buf.addr, buf.size_bytes) self.allocated_buffers._set_updated() # -----start capture here----- acquisition_controller.pre_start_capture(self) # call the startcapture method - self._call_dll('AlazarStartCapture') + self._call_dll('AlazarStartCapture', self._handle) acquisition_controller.pre_acquire(self) # buffer handling from acquisition @@ -388,7 +396,7 @@ def acquire(self, mode=None, samples_per_record=None, buf = self.buffer_list[buffers_completed % allocated_buffers] self._call_dll('AlazarWaitAsyncBufferComplete', - args=[buf.addr, buffer_timeout]) + self._handle, buf.addr, buffer_timeout) # TODO (C) last series of buffers must be handled exceptionally # (and I want to test the difference) by changing buffer @@ -400,11 +408,11 @@ def acquire(self, mode=None, samples_per_record=None, if buffer_recycling: acquisition_controller.handle_buffer(self, buf.buffer) self._call_dll('AlazarPostAsyncBuffer', - args=[buf.addr, buf.size_bytes]) + self._handle, buf.addr, buf.size_bytes) buffers_completed += 1 # stop measurement here - self._call_dll('AlazarAbortAsyncRead') + self._call_dll('AlazarAbortAsyncRead', self._handle) # -----cleanup here----- # extract data if not yet done @@ -431,34 +439,31 @@ def _set_list_if_present(self, param_base, value): for i, v in enumerate(value): self.parameters[param_base + str(i + 1)]._set(v) - def _call_dll(self, func_name, args=[], i=None): + def _call_dll(self, func_name, *args): """ - execute a dll function `func_name`, passing it: - - self._handle - - an optional index `i` - - a sequence of parameter names and arguments from `args` - - if an arg is a string, it's assumed to be a parameter name - and the parameter value (._get_bytes()) is used. if `i` is - provided, it will be inserted in each parameter name - using .format(i) (eg if i=2, 'coupling{}' becomes 'coupling2') - After the call succeeds, these parameters will be marked as - updated - - if an arg is NOT a string, it is inserted directly + Execute a dll function `func_name`, passing it the given arguments + + For each argument in the list + - If an arg is a parameter of this instrument, the parameter + value from `._get_bytes()` is used. If the call succeeds, these + parameters will be marked as updated using their `._set_updated()` + method + - Otherwise the arg is used directly """ # create the argument list - args_out = [] if i is None else [i] - params = [] + args_out = [] + all_params = self.parameters.values() + update_params = [] for arg in args: - if isinstance(arg, str): - param = self.parameters[arg.format(i)] - args_out.append(param._get_byte()) - params.append(param) + if arg in all_params: + args_out.append(arg._get_byte()) + update_params.append(arg) else: args_out.append(arg) # run the function func = getattr(self._ATS_dll, func_name) - return_code = func(self._handle, *args_out) + return_code = func(*args_out) # check for errors if return_code != self._success: @@ -477,8 +482,8 @@ def _call_dll(self, func_name, args=[], i=None): return_code, self._error_codes[return_code], func_name, argrepr)) - # mark parameters updated - for param in params: + # mark parameters updated (only after we've checked for errors) + for param in update_params: param._set_updated() def clear_buffers(self): From 762a4fa0d15e33db617d37d878348b797da3c582 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Thu, 28 Apr 2016 12:12:45 +0200 Subject: [PATCH 20/56] a little more cleanup in ATS --- qcodes/instrument_drivers/AlazarTech/ATS.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index d67682d3918f..a81f13296332 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -275,7 +275,8 @@ def acquire(self, mode=None, samples_per_record=None, # endregion self.mode._set_updated() - if self.mode.get() not in ('TS', 'NPT'): + mode = self.mode.get() + if mode not in ('TS', 'NPT'): raise Exception("Only the 'TS' and 'NPT' modes are implemented " "at this point") @@ -295,11 +296,11 @@ def acquire(self, mode=None, samples_per_record=None, raise Exception("Only 8 bits per sample supported at this moment") # Set record size for NPT mode - if self.mode.get() == 'NPT': + if mode == 'NPT': pretriggersize = 0 # pretriggersize is 0 for NPT always - post_trigger_size = self.samples_per_record._get_byte() self._call_dll('AlazarSetRecordSize', - self._handle, pretriggersize, post_trigger_size) + self._handle, pretriggersize, + self.samples_per_record) # set acquisition parameters here for NPT, TS mode if self.channel_selection._get_byte() == 3: @@ -317,7 +318,7 @@ def acquire(self, mode=None, samples_per_record=None, self.interleave_samples._get_byte() | self.get_processed_data._get_byte()) - if self.parameters['mode'].get() == 'NPT': + if mode == 'NPT': records_per_buffer = self.records_per_buffer._get_byte() records_per_acquisition = ( records_per_buffer * buffers_per_acquisition) @@ -329,7 +330,7 @@ def acquire(self, mode=None, samples_per_record=None, records_per_buffer, records_per_acquisition, acquire_flags) - elif self.parameters['mode'].get() == 'TS': + elif mode == 'TS': if (samples_per_record % buffers_per_acquisition != 0): logging.warning('buffers_per_acquisition is not a divisor of ' 'samples per record which it should be in ' @@ -359,7 +360,7 @@ def acquire(self, mode=None, samples_per_record=None, self.alloc_buffers._set_updated() self.fifo_only_streaming._set_updated() self.interleave_samples._set_updated() - self.parameters['get_processed_data']._set_updated() + self.get_processed_data._set_updated() # create buffers for acquisition self.clear_buffers() From 6e59e0629bfb406fbebac25c347c3e6de60c20e5 Mon Sep 17 00:00:00 2001 From: alexcjohnson Date: Thu, 28 Apr 2016 20:58:14 +0200 Subject: [PATCH 21/56] ATS board finding --- qcodes/instrument_drivers/AlazarTech/ATS.py | 101 +++++++++++++++++--- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index a81f13296332..dd34926e49b2 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -20,7 +20,13 @@ class AlazarTech_ATS(Instrument): - # TODO (S) is the success code always 512 (for any board)? + # override dll_path in your init script or in the board constructor + # if you have it somewhere else + dll_path = 'C:\\WINDOWS\\System32\\ATSApi' + + # override channels in a subclass if needed + channels = 2 + _success = 512 _error_codes = { @@ -117,15 +123,80 @@ class AlazarTech_ATS(Instrument): 'single channel mode.') } - def __init__(self, name, dll_path='C:\\WINDOWS\\System32\\ATSApi'): - super().__init__(name) - self._ATS_dll = ctypes.cdll.LoadLibrary(dll_path) + _board_names = { + 1: 'ATS850', + 2: 'ATS310', + 3: 'ATS330', + 4: 'ATS855', + 5: 'ATS315', + 6: 'ATS335', + 7: 'ATS460', + 8: 'ATS860', + 9: 'ATS660', + 10: 'ATS665', + 11: 'ATS9462', + 12: 'ATS9434', + 13: 'ATS9870', + 14: 'ATS9350', + 15: 'ATS9325', + 16: 'ATS9440', + 17: 'ATS9410', + 18: 'ATS9351', + 19: 'ATS9310', + 20: 'ATS9461', + 21: 'ATS9850', + 22: 'ATS9625', + 23: 'ATG6500', + 24: 'ATS9626', + 25: 'ATS9360', + 26: 'AXI9870', + 27: 'ATS9370', + 28: 'ATU7825', + 29: 'ATS9373', + 30: 'ATS9416' + } + + @classmethod + def find_boards(cls, dll_path=None): + dll = ctypes.cdll.LoadLibrary(dll_path or cls.dll_path) + + system_count = dll.AlazarNumOfSystems() + boards = [] + for system_id in range(1, system_count + 1): + board_count = dll.AlazarBoardsInSystemBySystemID(system_id) + for board_id in range(1, board_count + 1): + boards.append(cls.get_board_info(dll, system_id, board_id)) + return boards + + @classmethod + def get_board_info(cls, dll, system_id, board_id): + # make a temporary instrument for this board, to make it easier + # to get its info + board = cls('temp', system_id=system_id, board_id=board_id, + server_name=None) + handle = board._handle + board_kind = cls._board_names[dll.AlazarGetBoardKind(handle)] + + max_s, bps = board._get_channel_info(handle) + return { + 'system_id': system_id, + 'board_id': board_id, + 'board_kind': board_kind, + 'max_samples': max_s, + 'bits_per_sample': bps + } + + def __init__(self, name, system_id=1, board_id=1, dll_path=None, **kwargs): + super().__init__(name, **kwargs) + self._ATS_dll = ctypes.cdll.LoadLibrary(dll_path or self.dll_path) # TODO (W) make the board id more general such that more than one card # per system configurations are supported - self._handle = self._ATS_dll.AlazarGetBoardBySystemID(1, 1) + self._handle = self._ATS_dll.AlazarGetBoardBySystemID(system_id, + board_id) if not self._handle: - raise Exception("AlazarTech_ATS not found") + raise Exception('AlazarTech_ATS not found at ' + 'system {}, board {}'.format(system_id, board_id)) # TODO (M) do something with board kind here @@ -200,7 +271,7 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, self._handle, self.clock_source, self.sample_rate, self.clock_edge, self.decimation) - for i in [1, 2]: + for i in range(1, self.channels + 1): self._call_dll('AlazarInputControl', self._handle, i, self.parameters['coupling' + str(i)], @@ -229,6 +300,13 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, # TODO (W) config AUXIO + def _get_channel_info(self, handle): + bps = np.array([0], dtype=np.uint8) # bps bits per sample + max_s = np.array([0], dtype=np.uint32) # max_s memory size in samples + self._call_dll('AlazarGetChannelInfo', + handle, max_s.ctypes.data, bps.ctypes.data) + return max_s[0], bps[0] + def acquire(self, mode=None, samples_per_record=None, records_per_buffer=None, buffers_per_acquisition=None, channel_selection=None, transfer_offset=None, @@ -286,14 +364,9 @@ def acquire(self, mode=None, samples_per_record=None, self._call_dll('AlazarAbortAsyncRead', self._handle) # get channel info - bps = np.array([0], dtype=np.uint8) # bps bits per sample - max_s = np.array([0], dtype=np.uint32) # max_s memory size in samples - self._call_dll('AlazarGetChannelInfo', - self._handle, max_s.ctypes.data, bps.ctypes.data) - bps = bps[0] - max_s = max_s[0] + max_s, bps = self._get_channel_info(self._handle) if bps != 8: - raise Exception("Only 8 bits per sample supported at this moment") + raise Exception('Only 8 bits per sample supported at this moment') # Set record size for NPT mode if mode == 'NPT': From c9ae0abdc25ddeb0b88821cc588f1d366ea88999 Mon Sep 17 00:00:00 2001 From: elrama- Date: Wed, 27 Jul 2016 12:12:32 +0200 Subject: [PATCH 22/56] Minor changes (mostly typos) for ATS instrument to be properly created --- qcodes/instrument_drivers/AlazarTech/ATS.py | 2 +- qcodes/instrument_drivers/AlazarTech/ATS9870.py | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index dd34926e49b2..b5afa8cdadad 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -597,7 +597,7 @@ def __init__(self, name=None, label=None, unit=None, instrument=None, # TODO (S) test this validator vals = validators.Enum(*byte_to_value_dict.values()) - super().__init__(name=name, label=label, unit=unit, vals=vals) + super().__init__(name=name, label=label, units=unit, vals=vals) self.instrument = instrument self._byte = None self._uptodate_flag = False diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 0596d1bb3a40..04f5a8d419ac 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -3,8 +3,9 @@ class AlazarTech_ATS9870(AlazarTech_ATS): - def __init__(self, name): - super().__init__(name) + def __init__(self, name, server_name=None): + dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' + super().__init__(name, dll_path=dll_path) # add parameters # ----- Parameters for the configuration of the board ----- @@ -162,6 +163,9 @@ def __init__(self, name): # TODO (M) figure out if this also has to be a multiple of something, # I could not find this in the documentation but somehow I have the # feeling it still should be a multiple of something + # NOTE by ramiro: At least in previous python implementations(PycQED delft), this is an artifact for compatibility with AWG sequencing, not particular to any ATS architecture. + # ==> this is a construction imposed by the memory strategy implemented on the python driver we are writing, not limited by any actual ATS feature. + self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, label='Records per Buffer', @@ -268,4 +272,4 @@ def validate(self, value, context=''): repr(value), repr(self._divisor), context)) def __repr__(self): - super().__repr__()[:-1] + ', Multiples of {}>'.format(self._divisor) + return super().__repr__()[:-1] + ', Multiples of {}>'.format(self._divisor) From 78b6ef2536e8b5c99e2f7eadf65bd58abc457d3d Mon Sep 17 00:00:00 2001 From: elrama- Date: Wed, 27 Jul 2016 17:14:07 +0200 Subject: [PATCH 23/56] Fix on config method for ATS --- qcodes/instrument_drivers/AlazarTech/ATS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index b5afa8cdadad..f357bf8afe77 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -529,7 +529,7 @@ def _call_dll(self, func_name, *args): all_params = self.parameters.values() update_params = [] for arg in args: - if arg in all_params: + if isinstance(arg,AlazarParameter): args_out.append(arg._get_byte()) update_params.append(arg) else: From 48cf48f4a54bca6ad2c038c334f03a06c31d39f5 Mon Sep 17 00:00:00 2001 From: elrama- Date: Thu, 28 Jul 2016 12:33:56 +0200 Subject: [PATCH 24/56] Quick correction and first draft of an example Changes: * Typo in line 345 of ATS.py * Avoiding error handling for 518 (see explanation on github post) * Example notebook for ATS, still at a draft stage --- docs/examples/Qcodes example ATS_ONWORK.ipynb | 518 ++++++++++++++++++ qcodes/instrument_drivers/AlazarTech/ATS.py | 4 +- 2 files changed, 520 insertions(+), 2 deletions(-) create mode 100644 docs/examples/Qcodes example ATS_ONWORK.ipynb diff --git a/docs/examples/Qcodes example ATS_ONWORK.ipynb b/docs/examples/Qcodes example ATS_ONWORK.ipynb new file mode 100644 index 000000000000..dd3004c89bb7 --- /dev/null +++ b/docs/examples/Qcodes example ATS_ONWORK.ipynb @@ -0,0 +1,518 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "/*\r\n", + " * Qcodes Jupyter/IPython widgets\r\n", + " */\r\n", + "require([\r\n", + " 'nbextensions/widgets/widgets/js/widget',\r\n", + " 'nbextensions/widgets/widgets/js/manager'\r\n", + "], function (widget, manager) {\r\n", + "\r\n", + " var UpdateView = widget.DOMWidgetView.extend({\r\n", + " render: function() {\r\n", + " window.MYWIDGET = this;\r\n", + " this._interval = 0;\r\n", + " this.update();\r\n", + " },\r\n", + " update: function() {\r\n", + " this.display(this.model.get('_message'));\r\n", + " this.setInterval();\r\n", + " },\r\n", + " display: function(message) {\r\n", + " /*\r\n", + " * display method: override this for custom display logic\r\n", + " */\r\n", + " this.el.innerHTML = message;\r\n", + " },\r\n", + " remove: function() {\r\n", + " clearInterval(this._updater);\r\n", + " },\r\n", + " setInterval: function(newInterval) {\r\n", + " var me = this;\r\n", + " if(newInterval===undefined) newInterval = me.model.get('interval');\r\n", + " if(newInterval===me._interval) return;\r\n", + "\r\n", + " me._interval = newInterval;\r\n", + "\r\n", + " if(me._updater) clearInterval(me._updater);\r\n", + "\r\n", + " if(me._interval) {\r\n", + " me._updater = setInterval(function() {\r\n", + " me.send({myupdate: true});\r\n", + " if(!me.model.comm_live) {\r\n", + " console.log('missing comm, canceling widget updates', me);\r\n", + " clearInterval(me._updater);\r\n", + " }\r\n", + " }, me._interval * 1000);\r\n", + " }\r\n", + " }\r\n", + " });\r\n", + " manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n", + "\r\n", + " var HiddenUpdateView = UpdateView.extend({\r\n", + " display: function(message) {\r\n", + " this.$el.hide();\r\n", + " }\r\n", + " });\r\n", + " manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n", + "\r\n", + " var SubprocessView = UpdateView.extend({\r\n", + " render: function() {\r\n", + " var me = this;\r\n", + " me._interval = 0;\r\n", + " me._minimize = '';\r\n", + " me._restore = '';\r\n", + "\r\n", + " // max lines of output to show\r\n", + " me.maxOutputLength = 500;\r\n", + "\r\n", + " // in case there is already an outputView present,\r\n", + " // like from before restarting the kernel\r\n", + " $('.qcodes-output-view').not(me.$el).remove();\r\n", + "\r\n", + " me.$el\r\n", + " .addClass('qcodes-output-view')\r\n", + " .attr('qcodes-state', 'docked')\r\n", + " .html(\r\n", + " '
' +\r\n", + " '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('.qcodes-process-list');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "            me.processLinesButton = me.$el.find('.qcodes-processlines')\r\n",
+       "\r\n",
+       "            me.outputLines = [];\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.processLinesButton.click(function() {\r\n",
+       "                // toggle multiline process list display\r\n",
+       "                me.subprocessesMultiline = !me.subprocessesMultiline;\r\n",
+       "                me.showSubprocesses();\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "                me.model.set('_state', state);\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window)\r\n",
+       "                .off('resize.qcodes')\r\n",
+       "                .on('resize.qcodes', function() {me.clipBounds();});\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        updateState: function() {\r\n",
+       "            var me = this,\r\n",
+       "                oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                state = me.model.get('_state');\r\n",
+       "\r\n",
+       "            if(state === oldState) return;\r\n",
+       "\r\n",
+       "            setTimeout(function() {\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    console.log('here');\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el\r\n",
+       "                        .draggable({stop: function() { me.clipBounds(); }})\r\n",
+       "                        .css({\r\n",
+       "                            left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                            top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                        });\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                // any previous highlighting is now moot\r\n",
+       "                me.$el.removeClass('qcodes-highlight');\r\n",
+       "            }, 0);\r\n",
+       "\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        clipBounds: function() {\r\n",
+       "            var me = this;\r\n",
+       "            if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                var bounds = me.$el[0].getBoundingClientRect(),\r\n",
+       "                    minVis = 40,\r\n",
+       "                    maxLeft = window.innerWidth - minVis,\r\n",
+       "                    minLeft = minVis - bounds.width,\r\n",
+       "                    maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                if(bounds.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                else if(bounds.left < minLeft) me.$el.css('left', minLeft);\r\n",
+       "\r\n",
+       "                if(bounds.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                else if(bounds.top < 0) me.$el.css('top', 0);\r\n",
+       "            }\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            var me = this;\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = me.outputArea.scrollTop();\r\n",
+       "                me.outputArea.scrollTop(me.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = me.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    // if we add text and the box is minimized, highlight the\r\n",
+       "                    // title bar to alert the user that there are new messages.\r\n",
+       "                    // remove then add the class, so we get the animation again\r\n",
+       "                    // if it's already highlighted\r\n",
+       "                    me.$el.removeClass('qcodes-highlight');\r\n",
+       "                    setTimeout(function(){\r\n",
+       "                        me.$el.addClass('qcodes-highlight');\r\n",
+       "                    }, 0);\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                var newLines = message.split('\\n'),\r\n",
+       "                    out = me.outputLines,\r\n",
+       "                    outLen = out.length;\r\n",
+       "                if(outLen) out[outLen - 1] += newLines[0];\r\n",
+       "                else out.push(newLines[0]);\r\n",
+       "\r\n",
+       "                for(var i = 1; i < newLines.length; i++) {\r\n",
+       "                    out.push(newLines[i]);\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                if(out.length > me.maxOutputLength) {\r\n",
+       "                    out.splice(0, out.length - me.maxOutputLength + 1,\r\n",
+       "                        '<<< Output clipped >>>');\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.outputArea.text(out.join('\\n'));\r\n",
+       "                me.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                me.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    me.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            me.showSubprocesses();\r\n",
+       "            me.updateState();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        showSubprocesses: function() {\r\n",
+       "            var me = this,\r\n",
+       "                replacer = me.subprocessesMultiline ? '
' : ', ',\r\n", + " processes = (me.model.get('_processes') || '')\r\n", + " .replace(/\\n/g, '>' + replacer + '<');\r\n", + "\r\n", + " if(processes) processes = '<' + processes + '>';\r\n", + " else processes = 'No subprocesses';\r\n", + "\r\n", + " me.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n", + "\r\n", + " me.subprocessList.html(processes);\r\n", + " }\r\n", + " });\r\n", + " manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n", + "});\r\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "No loop running\n" + ] + } + ], + "source": [ + "%matplotlib nbagg\n", + "import matplotlib.pyplot as plt\n", + "import time\n", + "import numpy as np\n", + "\n", + "import qcodes as qc\n", + "\n", + "qc.halt_bg()\n", + "# qc.set_mp_method('spawn') # force Windows behavior on mac\n", + "\n", + "# this makes a widget in the corner of the window to show and control\n", + "# subprocesses and any output they would print to the terminal\n", + "qc.show_subprocess_widget()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import qcodes.instrument_drivers.AlazarTech.ATS9870 as ATSdriver\n", + "import qcodes.instrument_drivers.AlazarTech.ATS_acquisition_controllers as ats_contr" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "contr1 = ats_contr.DFT_AcquisitionController(demodulation_frequency=10e6)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ats_inst.config(clock_source='INTERNAL_CLOCK',\n", + " sample_rate=1000000,\n", + " clock_edge='CLOCK_EDGE_RISING',\n", + " decimation=0,\n", + " coupling=['AC','AC'],\n", + " channel_range=[2.,2.],\n", + " impedance=[50,50],\n", + " bwlimit=['DISABLED','DISABLED'],\n", + " trigger_operation='TRIG_ENGINE_OP_J',\n", + " trigger_engine1='TRIG_ENGINE_J',\n", + " trigger_source1='EXTERNAL',\n", + " trigger_slope1='TRIG_SLOPE_POSITIVE',\n", + " trigger_level1=0,\n", + " trigger_engine2='TRIG_ENGINE_K',\n", + " trigger_source2='CHANNEL_B',\n", + " trigger_slope2='TRIG_SLOPE_POSITIVE',\n", + " trigger_level2=0,\n", + " external_trigger_coupling='AC',\n", + " external_trigger_range='ETR_1V',\n", + " trigger_delay=0,\n", + " timeout_ticks=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "output = ats_inst.acquire(mode='NPT',\n", + " samples_per_record=1024,\n", + " records_per_buffer=70,\n", + " buffers_per_acquisition=128,\n", + " channel_selection='AB',\n", + " transfer_offset=0,\n", + " external_startcapture='DISABLED',\n", + " enable_record_headers='DISABLED',\n", + " alloc_buffers='ENABLED',\n", + " fifo_only_streaming='DISABLED',\n", + " interleave_samples='DISABLED',\n", + " get_processed_data='ENABLED',\n", + " allocated_buffers=None,\n", + " buffer_timeout=1000,\n", + " acquisition_controller=contr1)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1.2225695082720591,\n", + " 1.216472639837185,\n", + " -179.9999999998654,\n", + " -179.99999999986107,\n", + " 359.9999999999957]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [Root]", + "language": "python", + "name": "Python [Root]" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index f357bf8afe77..53dcb11d24c3 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -342,7 +342,7 @@ def acquire(self, mode=None, samples_per_record=None, buffers_per_acquisition) self._set_if_present('channel_selection', channel_selection) self._set_if_present('transfer_offset', transfer_offset) - self._set_if_present('external_starcapture', external_startcapture) + self._set_if_present('external_startcapture', external_startcapture) self._set_if_present('enable_record_headers', enable_record_headers) self._set_if_present('alloc_buffers', alloc_buffers) self._set_if_present('fifo_only_streaming', fifo_only_streaming) @@ -540,7 +540,7 @@ def _call_dll(self, func_name, *args): return_code = func(*args_out) # check for errors - if return_code != self._success: + if (return_code != self._success) and (return_code !=518): # TODO (C) log error argrepr = repr(args_out) From 25447582b2e4d558d75d518f93bac90faf720952 Mon Sep 17 00:00:00 2001 From: damazdejong Date: Mon, 8 Aug 2016 17:39:19 +0200 Subject: [PATCH 25/56] refactor: revert previous change Add a TODO item, remove obsolete variable and revert a change regarding post_trigger_size variable to improve code readability --- qcodes/instrument_drivers/AlazarTech/ATS.py | 4 ++-- qcodes/instrument_drivers/AlazarTech/ATS9870.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 53dcb11d24c3..0acaf7e72301 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -371,9 +371,10 @@ def acquire(self, mode=None, samples_per_record=None, # Set record size for NPT mode if mode == 'NPT': pretriggersize = 0 # pretriggersize is 0 for NPT always + post_trigger_size = self.samples_per_record._get_byte() self._call_dll('AlazarSetRecordSize', self._handle, pretriggersize, - self.samples_per_record) + post_trigger_size) # set acquisition parameters here for NPT, TS mode if self.channel_selection._get_byte() == 3: @@ -526,7 +527,6 @@ def _call_dll(self, func_name, *args): """ # create the argument list args_out = [] - all_params = self.parameters.values() update_params = [] for arg in args: if isinstance(arg,AlazarParameter): diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 04f5a8d419ac..34249b955650 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -4,6 +4,8 @@ class AlazarTech_ATS9870(AlazarTech_ATS): def __init__(self, name, server_name=None): + # TODO(damazter) allow arbitrary kwargs to be passed to the Instrument + # class, including server_name dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' super().__init__(name, dll_path=dll_path) # add parameters From b30a072754e9e8fc5c28af5b305af99297150a1e Mon Sep 17 00:00:00 2001 From: damazdejong Date: Mon, 8 Aug 2016 17:46:06 +0200 Subject: [PATCH 26/56] refactor: change TODO style update the TODO style to the new contributing guide --- qcodes/instrument_drivers/AlazarTech/ATS.py | 26 +++++++++---------- .../instrument_drivers/AlazarTech/ATS9870.py | 7 ++--- .../AlazarTech/ATS_acquisition_controllers.py | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 0acaf7e72301..f8653defcb5f 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -7,14 +7,14 @@ from qcodes.instrument.parameter import Parameter from qcodes.utils import validators -# TODO (C) logging +# TODO(damazter) (C) logging # these items are important for generalizing this code to multiple alazar cards -# TODO (W) remove 8 bits per sample requirement -# TODO (W) some alazar cards have a different number of channels :( +# TODO(damazter) (W) remove 8 bits per sample requirement +# TODO(damazter) (W) some alazar cards have a different number of channels :( # this driver only works with 2-channel cards -# TODO (S) tests to do: +# TODO(damazter) (S) tests to do: # acquisition that would overflow the board if measurement is not stopped # quickly enough. can this be solved by not reposting the buffers? @@ -298,7 +298,7 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None, self._call_dll('AlazarSetTriggerTimeOut', self._handle, self.timeout_ticks) - # TODO (W) config AUXIO + # TODO(damazter) (W) config AUXIO def _get_channel_info(self, handle): bps = np.array([0], dtype=np.uint8) # bps bits per sample @@ -473,7 +473,7 @@ def acquire(self, mode=None, samples_per_record=None, self._call_dll('AlazarWaitAsyncBufferComplete', self._handle, buf.addr, buffer_timeout) - # TODO (C) last series of buffers must be handled exceptionally + # TODO(damazter) (C) last series of buffers must be handled exceptionally # (and I want to test the difference) by changing buffer # recycling for the last series of buffers @@ -541,7 +541,7 @@ def _call_dll(self, func_name, *args): # check for errors if (return_code != self._success) and (return_code !=518): - # TODO (C) log error + # TODO(damazter) (C) log error argrepr = repr(args_out) if len(argrepr) > 100: @@ -566,8 +566,8 @@ def clear_buffers(self): self.buffer_list = [] def signal_to_volt(self, channel, signal): - # TODO (S) check this - # TODO (M) use byte value if range{channel} + # TODO(damazter) (S) check this + # TODO(damazter) (M) use byte value if range{channel} return (((signal - 127.5) / 127.5) * (self.parameters['channel_range' + str(channel)].get())) @@ -594,7 +594,7 @@ def __init__(self, name=None, label=None, unit=None, instrument=None, if byte_to_value_dict is None: vals = validators.Anything() else: - # TODO (S) test this validator + # TODO(damazter) (S) test this validator vals = validators.Enum(*byte_to_value_dict.values()) super().__init__(name=name, label=label, units=unit, vals=vals) @@ -602,7 +602,7 @@ def __init__(self, name=None, label=None, unit=None, instrument=None, self._byte = None self._uptodate_flag = False - # TODO (M) check this block + # TODO(damazter) (M) check this block if byte_to_value_dict is None: self._byte_to_value_dict = TrivialDictionary() self._value_to_byte_dict = TrivialDictionary() @@ -618,7 +618,7 @@ def get(self): This method returns the name of the value set for this parameter :return: value """ - # TODO (S) test this exception + # TODO(damazter) (S) test this exception if self._uptodate_flag is False: raise Exception('The value of this parameter (' + self.name + ') is not up to date with the actual value in ' @@ -645,7 +645,7 @@ def _set(self, value): :return: None """ - # TODO (S) test this validation + # TODO(damazter) (S) test this validation self.validate(value) self._byte = self._value_to_byte_dict[value] self._uptodate_flag = False diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 34249b955650..50cda06b0b9c 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -162,7 +162,8 @@ def __init__(self, name, server_name=None): unit=None, value=96000, vals=Multiples(divisor=16, min_value=0)) - # TODO (M) figure out if this also has to be a multiple of something, + # TODO(damazter) (M) figure out if this also has to be a multiple of + # something, # I could not find this in the documentation but somehow I have the # feeling it still should be a multiple of something # NOTE by ramiro: At least in previous python implementations(PycQED delft), this is an artifact for compatibility with AWG sequencing, not particular to any ATS architecture. @@ -248,9 +249,9 @@ def __init__(self, name, server_name=None): value=1000, vals=validators.Ints(min_value=0)) - # TODO (M) make parameter for board type + # TODO(damazter) (M) make parameter for board type - # TODO (M) check board kind + # TODO(damazter)(M) check board kind class Multiples(validators.Ints): diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py index 4122d9da583d..9f138f0eae3b 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -10,7 +10,7 @@ def __init__(self, demodulation_frequency): self.samples_per_record = None self.records_per_buffer = None self.buffers_per_acquisition = None - # TODO (S) this is not very general: + # TODO(damazter) (S) this is not very general: self.number_of_channels = 2 self.cos_list = None self.sin_list = None From 8655bcdd219a90b436faa4f03644a7aae4dace3f Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Tue, 9 Aug 2016 17:03:01 +0200 Subject: [PATCH 27/56] fix: server_name was not forwarded to base instrument class adds **kwarg handling to ATS9870 implementation of the alazar driver --- qcodes/instrument_drivers/AlazarTech/ATS9870.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 34249b955650..c8d785a93ce7 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -3,11 +3,9 @@ class AlazarTech_ATS9870(AlazarTech_ATS): - def __init__(self, name, server_name=None): - # TODO(damazter) allow arbitrary kwargs to be passed to the Instrument - # class, including server_name + def __init__(self, name, **kwargs): dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' - super().__init__(name, dll_path=dll_path) + super().__init__(name, dll_path=dll_path, **kwargs) # add parameters # ----- Parameters for the configuration of the board ----- From 032b9f37448133ea7efe1cc9bbad735c3ce3c88b Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Tue, 9 Aug 2016 17:13:37 +0200 Subject: [PATCH 28/56] fix: idn for alazar driver The alazar does not comply with the standard get_idn function of the Instrument base class. This commits overwrites the standard behavior to prevent errors from showing up --- qcodes/instrument_drivers/AlazarTech/ATS.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 0acaf7e72301..f8b7f181d283 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -202,6 +202,10 @@ def __init__(self, name, system_id=1, board_id=1, dll_path=None, **kwargs): self.buffer_list = [] + def get_idn(self): + board_kind = self._board_names[self._ATS_dll.AlazarGetBoardKind(self._handle)] + return {'firmware': None, 'model': board_kind, 'serial': None, 'vendor': 'AlazarTech'} + def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimation=None, coupling=None, channel_range=None, impedance=None, bwlimit=None, trigger_operation=None, From 50ff3c2c24d52138a649a1dcf4d45ff102ad981a Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Tue, 9 Aug 2016 17:23:00 +0200 Subject: [PATCH 29/56] refactor: change self.get_sample_speed into self.get_sample_rate The sampling rate is called rate and not speed. Remove this ambiguity. This is a breaking change from self.get_sample_speed into self.get_sample_rate --- qcodes/instrument_drivers/AlazarTech/ATS.py | 2 +- .../AlazarTech/ATS_acquisition_controllers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 266c43a4c588..b9060069bd19 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -575,7 +575,7 @@ def signal_to_volt(self, channel, signal): return (((signal - 127.5) / 127.5) * (self.parameters['channel_range' + str(channel)].get())) - def get_sample_speed(self): + def get_sample_rate(self): if self.sample_rate.get() == 'EXTERNAL_CLOCK': raise Exception('External clock is used, alazar driver ' 'could not determine sample speed.') diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py index 9f138f0eae3b..78016746afa1 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -20,7 +20,7 @@ def pre_start_capture(self, alazar): self.samples_per_record = alazar.samples_per_record.get() self.records_per_buffer = alazar.records_per_buffer.get() self.buffers_per_acquisition = alazar.buffers_per_acquisition.get() - sample_speed = alazar.get_sample_speed() + sample_speed = alazar.get_sample_rate() integer_list = np.arange(self.samples_per_record) angle_list = (2 * np.pi * self.demodulation_frequency / sample_speed * integer_list) From dcad78456d669a5d0e48e569702f421257c2630c Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Tue, 9 Aug 2016 17:44:40 +0200 Subject: [PATCH 30/56] feat: check if board kind matches the driver type Throw an error if a different Alazar card is detected. Refactor some lines which were too long. Remove outdated TODO's --- qcodes/instrument_drivers/AlazarTech/ATS.py | 15 ++++++++------- qcodes/instrument_drivers/AlazarTech/ATS9870.py | 16 +++++++++++----- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index b9060069bd19..5a273fb208cc 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -190,21 +190,21 @@ def __init__(self, name, system_id=1, board_id=1, dll_path=None, **kwargs): super().__init__(name, **kwargs) self._ATS_dll = ctypes.cdll.LoadLibrary(dll_path or self.dll_path) - # TODO (W) make the board id more general such that more than one card - # per system configurations are supported self._handle = self._ATS_dll.AlazarGetBoardBySystemID(system_id, board_id) if not self._handle: raise Exception('AlazarTech_ATS not found at ' 'system {}, board {}'.format(system_id, board_id)) - # TODO (M) do something with board kind here - self.buffer_list = [] def get_idn(self): - board_kind = self._board_names[self._ATS_dll.AlazarGetBoardKind(self._handle)] - return {'firmware': None, 'model': board_kind, 'serial': None, 'vendor': 'AlazarTech'} + board_kind = self._board_names[ + self._ATS_dll.AlazarGetBoardKind(self._handle)] + return {'firmware': None, + 'model': board_kind, + 'serial': None, + 'vendor': 'AlazarTech'} def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimation=None, coupling=None, channel_range=None, @@ -477,7 +477,8 @@ def acquire(self, mode=None, samples_per_record=None, self._call_dll('AlazarWaitAsyncBufferComplete', self._handle, buf.addr, buffer_timeout) - # TODO(damazter) (C) last series of buffers must be handled exceptionally + # TODO(damazter) (C) last series of buffers must be handled + # exceptionally # (and I want to test the difference) by changing buffer # recycling for the last series of buffers diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index d935c528ce02..6f18c66ec7f5 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -164,8 +164,13 @@ def __init__(self, name, **kwargs): # something, # I could not find this in the documentation but somehow I have the # feeling it still should be a multiple of something - # NOTE by ramiro: At least in previous python implementations(PycQED delft), this is an artifact for compatibility with AWG sequencing, not particular to any ATS architecture. - # ==> this is a construction imposed by the memory strategy implemented on the python driver we are writing, not limited by any actual ATS feature. + # NOTE by ramiro: At least in previous python implementations + # (PycQED delft), this is an artifact for compatibility with + # AWG sequencing, not particular to any ATS architecture. + # ==> this is a construction imposed by the memory + # strategy implemented on the python driver we + # are writing, not limited by any actual ATS + # feature. self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, @@ -247,9 +252,10 @@ def __init__(self, name, **kwargs): value=1000, vals=validators.Ints(min_value=0)) - # TODO(damazter) (M) make parameter for board type - - # TODO(damazter)(M) check board kind + model = self.get_idn()['model'] + if model != 'ATS9870': + raise Exception("The Alazar board kind is not 'ATS9870'," + " found '" + str(model) + "' instead.") class Multiples(validators.Ints): From 1ba4644117044547a19dc1bb601267bbf10392ab Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Wed, 10 Aug 2016 18:10:34 +0200 Subject: [PATCH 31/56] bug: change default trigger settings such that it will work by default This may seem like a small fix, but having the two trigger engines be J and K makes this work, having engine2=TRIG_ENGINE_J and DISABLED deactivates the triggering system if trigger_operation='TRIG_ENGINE_OP_J'. Hence the new default is engine2=TRIG_ENGINE_K --- qcodes/instrument_drivers/AlazarTech/ATS9870.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 6f18c66ec7f5..148c70e8dc95 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -94,7 +94,7 @@ def __init__(self, name, **kwargs): parameter_class=AlazarParameter, label='Trigger Engine ' + i, unit=None, - value='TRIG_ENGINE_J', + value='TRIG_ENGINE_' + ('J' if i == 0 else 'K'), byte_to_value_dict={0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K'}) self.add_parameter(name='trigger_source' + i, From 56b66bff09989eaaa3af67cf2383a63e9d404443 Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Thu, 11 Aug 2016 14:44:46 +0200 Subject: [PATCH 32/56] bug: making this work with loops, not complete this si the first steep to make acqisitioncontroller into an instrument. This is not working yet. this is an intermediate commit --- qcodes/instrument_drivers/AlazarTech/ATS.py | 44 ++++++++++++------- .../AlazarTech/ATS_acquisition_controllers.py | 25 ++++++++--- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 5a273fb208cc..81199d3d9200 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -458,11 +458,12 @@ def acquire(self, mode=None, samples_per_record=None, self.allocated_buffers._set_updated() # -----start capture here----- - acquisition_controller.pre_start_capture(self) + acquisition_controller.set_alazar(self) + acquisition_controller.pre_start_capture() # call the startcapture method self._call_dll('AlazarStartCapture', self._handle) - acquisition_controller.pre_acquire(self) + acquisition_controller.pre_acquire() # buffer handling from acquisition buffers_completed = 0 buffer_timeout = self.buffer_timeout._get_byte() @@ -486,7 +487,7 @@ def acquire(self, mode=None, samples_per_record=None, # otherwise continue to next buffer if buffer_recycling: - acquisition_controller.handle_buffer(self, buf.buffer) + acquisition_controller.handle_buffer(buf.buffer) self._call_dll('AlazarPostAsyncBuffer', self._handle, buf.addr, buf.size_bytes) buffers_completed += 1 @@ -498,7 +499,7 @@ def acquire(self, mode=None, samples_per_record=None, # extract data if not yet done if not buffer_recycling: for buf in self.buffer_list: - acquisition_controller.handle_buffer(self, buf.buffer) + acquisition_controller.handle_buffer(buf.buffer) # free up memory self.clear_buffers() @@ -508,7 +509,7 @@ def acquire(self, mode=None, samples_per_record=None, p.get() # return result - return acquisition_controller.post_acquire(self) + return acquisition_controller.post_acquire() def _set_if_present(self, param_name, value): if value is not None: @@ -712,32 +713,46 @@ def __del__(self): 'Memory should have been released before buffer was deleted.') -class AcquisitionController: - def __init__(self): +class AcquisitionController(Instrument): + def __init__(self, name, alazar, **kwargs): """ + :param alazar: a reference to the alazar driver :return: nothing """ - pass + super().__init__(name, **kwargs) + self.alazar = None + self.set_alazar(alazar) - def pre_start_capture(self, alazar): + def get_alazar(self): + return self.alazar + + def set_alazar(self, alazar): + self.alazar = alazar + + def get(self): """ + :return: + """ + raise NotImplementedError( + 'This method should be implemented in a subclass, by making an ' + 'appropriate call to alazar.acquire()') - :param alazar: + def pre_start_capture(self): + """ :return: """ raise NotImplementedError( 'This method should be implemented in a subclass') - def pre_acquire(self, alazar): + def pre_acquire(self): """ Use this method to prepare yourself for the data acquisition - :param alazar: a reference to the alazar driver :return: nothing """ raise NotImplementedError( 'This method should be implemented in a subclass') - def handle_buffer(self, alazar, buffer): + def handle_buffer(self, buffer): """ :param buffer: np.array with the data from the alazar card :return: something, it is ignored in any case @@ -745,9 +760,8 @@ def handle_buffer(self, alazar, buffer): raise NotImplementedError( 'This method should be implemented in a subclass') - def post_acquire(self, alazar): + def post_acquire(self): """ - :param alazar: a reference to the alazar driver :return: this function should return all relevant data that you want to get form the acquisition """ diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py index 78016746afa1..9b287394ecfb 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -5,8 +5,9 @@ # DFT AcquisitionController class DFT_AcquisitionController(AcquisitionController): - def __init__(self, demodulation_frequency): + def __init__(self, name, alazar, demodulation_frequency, **kwargs): self.demodulation_frequency = demodulation_frequency + self.acquisitionkwargs = {'acquisition_controller': self} self.samples_per_record = None self.records_per_buffer = None self.buffers_per_acquisition = None @@ -15,8 +16,21 @@ def __init__(self, demodulation_frequency): self.cos_list = None self.sin_list = None self.buffer = None + # make a call to the parent class and by extension, create the parameter + # structure of this class + super().__init__(name, alazar, **kwargs) + self.add_parameter("acquisition", get_cmd=self.do_acquisition) - def pre_start_capture(self, alazar): + def set_acquisitionkwargs(self, **kwargs): + self.acquisitionkwargs.update(**kwargs) + + def do_acquisition(self): + value = self.get_alazar().acquire(**self.acquisitionkwargs) + self._save_val(value) + return value + + def pre_start_capture(self): + alazar = self.get_alazar() self.samples_per_record = alazar.samples_per_record.get() self.records_per_buffer = alazar.records_per_buffer.get() self.buffers_per_acquisition = alazar.buffers_per_acquisition.get() @@ -31,16 +45,17 @@ def pre_start_capture(self, alazar): self.records_per_buffer * self.number_of_channels) - def pre_acquire(self, alazar): + def pre_acquire(self): # this could be used to start an Arbitrary Waveform Generator, etc... # using this method ensures that the contents are executed AFTER the # Alazar card starts listening for a trigger pulse pass - def handle_buffer(self, alazar, data): + def handle_buffer(self, data): self.buffer += data - def post_acquire(self, alazar): + def post_acquire(self): + alazar = self.get_alazar() # average all records in a buffer records_per_acquisition = (1. * self.buffers_per_acquisition * self.records_per_buffer) From a51dc490b9a1036e83533ee2e3c603ea3ab26d9e Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Thu, 11 Aug 2016 14:45:38 +0200 Subject: [PATCH 33/56] bug: simplifying example document, not complete remove all mess fro mthe example notebook, work in progress --- docs/examples/Qcodes example ATS_ONWORK.ipynb | 238 ++++++++++++++---- 1 file changed, 183 insertions(+), 55 deletions(-) diff --git a/docs/examples/Qcodes example ATS_ONWORK.ipynb b/docs/examples/Qcodes example ATS_ONWORK.ipynb index dd3004c89bb7..685f35be2ac7 100644 --- a/docs/examples/Qcodes example ATS_ONWORK.ipynb +++ b/docs/examples/Qcodes example ATS_ONWORK.ipynb @@ -347,6 +347,7 @@ "name": "stdout", "output_type": "stream", "text": [ + "pyqtgraph plotting not supported, try \"from qcodes.plots.pyqtgraph import QtPlot\" to see the full error\n", "No loop running\n" ] } @@ -358,6 +359,7 @@ "import numpy as np\n", "\n", "import qcodes as qc\n", + "import qcodes.instrument.parameter as parameter\n", "\n", "qc.halt_bg()\n", "# qc.set_mp_method('spawn') # force Windows behavior on mac\n", @@ -371,7 +373,7 @@ "cell_type": "code", "execution_count": 2, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -383,53 +385,60 @@ "cell_type": "code", "execution_count": 3, "metadata": { - "collapsed": true + "collapsed": false }, "outputs": [], "source": [ - "contr1 = ats_contr.DFT_AcquisitionController(demodulation_frequency=10e6)" + "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1', server_name=\"alazar_server\")\n", + "contr1 = ats_contr.DFT_AcquisitionController(name='contr1', demodulation_frequency=10e6, alazar=None, server_name=\"alazar_server\")\n", + "contr1.set_acquisitionkwargs(#mode='NPT',\n", + " samples_per_record=1024,\n", + " records_per_buffer=70,\n", + " buffers_per_acquisition=1,\n", + " #channel_selection='AB',\n", + " #transfer_offset=0,\n", + " #external_startcapture='ENABLED',\n", + " #enable_record_headers='DISABLED',\n", + " #alloc_buffers='DISABLED',\n", + " #fifo_only_streaming='DISABLED',\n", + " #interleave_samples='DISABLED',\n", + " #get_processed_data='DISABLED',\n", + " allocated_buffers=64,\n", + " #buffer_timeout=1000\n", + ")" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [], "source": [ - "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1')" + "server=qc.instrument.server.get_instrument_server_manager(\"alazar_server\")" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 17, "metadata": { "collapsed": false }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "ats_inst.config(clock_source='INTERNAL_CLOCK',\n", - " sample_rate=1000000,\n", - " clock_edge='CLOCK_EDGE_RISING',\n", - " decimation=0,\n", - " coupling=['AC','AC'],\n", - " channel_range=[2.,2.],\n", - " impedance=[50,50],\n", - " bwlimit=['DISABLED','DISABLED'],\n", - " trigger_operation='TRIG_ENGINE_OP_J',\n", - " trigger_engine1='TRIG_ENGINE_J',\n", - " trigger_source1='EXTERNAL',\n", - " trigger_slope1='TRIG_SLOPE_POSITIVE',\n", - " trigger_level1=0,\n", - " trigger_engine2='TRIG_ENGINE_K',\n", - " trigger_source2='CHANNEL_B',\n", - " trigger_slope2='TRIG_SLOPE_POSITIVE',\n", - " trigger_level2=0,\n", - " external_trigger_coupling='AC',\n", - " external_trigger_range='ETR_1V',\n", - " trigger_delay=0,\n", - " timeout_ticks=0)" + "server._server." ] }, { @@ -440,26 +449,12 @@ }, "outputs": [], "source": [ - "output = ats_inst.acquire(mode='NPT',\n", - " samples_per_record=1024,\n", - " records_per_buffer=70,\n", - " buffers_per_acquisition=128,\n", - " channel_selection='AB',\n", - " transfer_offset=0,\n", - " external_startcapture='DISABLED',\n", - " enable_record_headers='DISABLED',\n", - " alloc_buffers='ENABLED',\n", - " fifo_only_streaming='DISABLED',\n", - " interleave_samples='DISABLED',\n", - " get_processed_data='ENABLED',\n", - " allocated_buffers=None,\n", - " buffer_timeout=1000,\n", - " acquisition_controller=contr1)" + "alazar=server.instruments[0]" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "metadata": { "collapsed": false }, @@ -467,20 +462,16 @@ { "data": { "text/plain": [ - "[1.2225695082720591,\n", - " 1.216472639837185,\n", - " -179.9999999998654,\n", - " -179.99999999986107,\n", - " 359.9999999999957]" + "" ] }, - "execution_count": 9, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "output" + "alazar" ] }, { @@ -490,15 +481,152 @@ "collapsed": true }, "outputs": [], - "source": [] + "source": [ + "ats_inst.config(#clock_source='INTERNAL_CLOCK',\n", + " sample_rate=100000000,\n", + " #clock_edge='CLOCK_EDGE_RISING',\n", + " #decimation=0,\n", + " #coupling=['AC','AC'],\n", + " channel_range=[2.,2.],\n", + " #impedance=[50,50],\n", + " #bwlimit=['DISABLED','DISABLED'],\n", + " #trigger_operation='TRIG_ENGINE_OP_J',\n", + " #trigger_engine1='TRIG_ENGINE_J',\n", + " trigger_source1='EXTERNAL',\n", + " #trigger_slope1='TRIG_SLOPE_POSITIVE',\n", + " #trigger_level1=128,\n", + " #trigger_engine2='TRIG_ENGINE_K',\n", + " #trigger_source2='DISABLE',\n", + " #trigger_slope2='TRIG_SLOPE_POSITIVE',\n", + " #trigger_level2=128,\n", + " #external_trigger_coupling='AC',\n", + " #external_trigger_range='ETR_5V',\n", + " #trigger_delay=0,\n", + " #timeout_ticks=0\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "contr1.get_alazar()==ats_inst" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "contr1()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "contr1.snapshot()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "contr1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ats_inst.allocated_buffers.get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "ats_inst.clear_buffers()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "t = []\n", + "for n, p in ats_inst.parameters.items():\n", + " t.append([n,p.get()])\n", + " \n", + "t" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = parameter.ManualParameter(name=\"a\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "data = qc.Loop(a[0:10:0.1], delay=0.1).each(contr1).run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "data." + ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [Root]", + "display_name": "Python 3", "language": "python", - "name": "Python [Root]" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -510,7 +638,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2" + "version": "3.5.1" } }, "nbformat": 4, From c4839f07dcae1faf81a79ad54a3fdba8675877be Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Thu, 11 Aug 2016 16:16:22 +0200 Subject: [PATCH 34/56] feat: make the driver work with loops use the change proposed in #303 to make this driver work with loops --- qcodes/instrument_drivers/AlazarTech/ATS.py | 12 ++---------- .../AlazarTech/ATS_acquisition_controllers.py | 5 ++--- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 81199d3d9200..7566fe92a84f 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -714,14 +714,14 @@ def __del__(self): class AcquisitionController(Instrument): - def __init__(self, name, alazar, **kwargs): + def __init__(self, name, alazar_id, **kwargs): """ :param alazar: a reference to the alazar driver :return: nothing """ super().__init__(name, **kwargs) self.alazar = None - self.set_alazar(alazar) + self.set_alazar(kwargs['server'].instruments[alazar_id]) def get_alazar(self): return self.alazar @@ -729,14 +729,6 @@ def get_alazar(self): def set_alazar(self, alazar): self.alazar = alazar - def get(self): - """ - :return: - """ - raise NotImplementedError( - 'This method should be implemented in a subclass, by making an ' - 'appropriate call to alazar.acquire()') - def pre_start_capture(self): """ :return: diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py index 9b287394ecfb..853430c96c4c 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py @@ -5,7 +5,7 @@ # DFT AcquisitionController class DFT_AcquisitionController(AcquisitionController): - def __init__(self, name, alazar, demodulation_frequency, **kwargs): + def __init__(self, name, alazar_id, demodulation_frequency, **kwargs): self.demodulation_frequency = demodulation_frequency self.acquisitionkwargs = {'acquisition_controller': self} self.samples_per_record = None @@ -18,7 +18,7 @@ def __init__(self, name, alazar, demodulation_frequency, **kwargs): self.buffer = None # make a call to the parent class and by extension, create the parameter # structure of this class - super().__init__(name, alazar, **kwargs) + super().__init__(name, alazar_id, **kwargs) self.add_parameter("acquisition", get_cmd=self.do_acquisition) def set_acquisitionkwargs(self, **kwargs): @@ -26,7 +26,6 @@ def set_acquisitionkwargs(self, **kwargs): def do_acquisition(self): value = self.get_alazar().acquire(**self.acquisitionkwargs) - self._save_val(value) return value def pre_start_capture(self): From d991e65590e31d060c0d6428ae53d300fbe41a3d Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Thu, 11 Aug 2016 16:17:41 +0200 Subject: [PATCH 35/56] feat: update example notebook update to example notebook, work not finished yet. --- docs/examples/Qcodes example ATS_ONWORK.ipynb | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/docs/examples/Qcodes example ATS_ONWORK.ipynb b/docs/examples/Qcodes example ATS_ONWORK.ipynb index 685f35be2ac7..107c791e3c47 100644 --- a/docs/examples/Qcodes example ATS_ONWORK.ipynb +++ b/docs/examples/Qcodes example ATS_ONWORK.ipynb @@ -390,7 +390,7 @@ "outputs": [], "source": [ "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1', server_name=\"alazar_server\")\n", - "contr1 = ats_contr.DFT_AcquisitionController(name='contr1', demodulation_frequency=10e6, alazar=None, server_name=\"alazar_server\")\n", + "contr1 = ats_contr.DFT_AcquisitionController(name='contr1', demodulation_frequency=10e6, alazar_id=0, server_name=\"alazar_server\")\n", "contr1.set_acquisitionkwargs(#mode='NPT',\n", " samples_per_record=1024,\n", " records_per_buffer=70,\n", @@ -410,7 +410,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "collapsed": false }, @@ -421,29 +421,18 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": { "collapsed": false }, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "server._server." + "ats_inst._id" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "collapsed": false }, @@ -454,29 +443,18 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "collapsed": false }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "alazar" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "collapsed": true }, @@ -519,13 +497,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "collapsed": false }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[0.027273637138787041,\n", + " 0.02408165056435747,\n", + " 55.211359401767986,\n", + " 53.29892574674141,\n", + " 1.9124336550265753]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "contr1()" + "contr1.acquisition.get()" ] }, { From fc9809dc5757e86c5a3aba6d83be359c8ef4db76 Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Mon, 15 Aug 2016 16:35:08 +0200 Subject: [PATCH 36/56] fix: ATS9870 samples_per_record requirements were incorrect fixed them to comply with the ATS-SDK programmer's guide --- qcodes/instrument_drivers/AlazarTech/ATS9870.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py index 148c70e8dc95..32cd383de1e5 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py @@ -153,13 +153,16 @@ def __init__(self, name, **kwargs): value='NPT', byte_to_value_dict={0x200: 'NPT', 0x400: 'TS'}) - # samples_per_record must be a multiple of 16! + # samples_per_record must be a multiple of of some number (64 in the + # case of ATS9870) and and has some minimum (256 in the case of ATS9870) + # These values can be found in the ATS-SDK programmar's guide self.add_parameter(name='samples_per_record', parameter_class=AlazarParameter, label='Samples per Record', unit=None, value=96000, - vals=Multiples(divisor=16, min_value=0)) + vals=Multiples(divisor=64, min_value=256)) + # TODO(damazter) (M) figure out if this also has to be a multiple of # something, # I could not find this in the documentation but somehow I have the @@ -171,7 +174,6 @@ def __init__(self, name, **kwargs): # strategy implemented on the python driver we # are writing, not limited by any actual ATS # feature. - self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, label='Records per Buffer', From 2957f53d4119fea5e09bd318bc3e266cafb98e45 Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Mon, 15 Aug 2016 18:21:59 +0200 Subject: [PATCH 37/56] feat: improve the idn included many more numbers into the idn of the alazar cards --- qcodes/instrument_drivers/AlazarTech/ATS.py | 61 ++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index 7566fe92a84f..e34e30030b05 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -201,10 +201,67 @@ def __init__(self, name, system_id=1, board_id=1, dll_path=None, **kwargs): def get_idn(self): board_kind = self._board_names[ self._ATS_dll.AlazarGetBoardKind(self._handle)] + + major = np.array([0], dtype=np.uint8) + minor = np.array([0], dtype=np.uint8) + revision = np.array([0], dtype=np.uint8) + self._call_dll('AlazarGetCPLDVersion', + self._handle, + major.ctypes.data, + minor.ctypes.data) + cpld_ver = str(major[0])+"."+str(minor[0]) + + self._call_dll('AlazarGetDriverVersion', + major.ctypes.data, + minor.ctypes.data, + revision.ctypes.data) + driver_ver = str(major[0])+"."+str(minor[0])+"."+str(revision[0]) + + self._call_dll('AlazarGetSDKVersion', + major.ctypes.data, + minor.ctypes.data, + revision.ctypes.data) + sdk_ver = str(major[0])+"."+str(minor[0])+"."+str(revision[0]) + + value = np.array([0], dtype=np.uint32) + self._call_dll('AlazarQueryCapability', + self._handle, 0x10000024, 0, value.ctypes.data) + serial = str(value[0]) + self._call_dll('AlazarQueryCapability', + self._handle, 0x10000026, 0, value.ctypes.data) + latest_cal_date = (str(value[0])[0:2] + "-" + + str(value[0])[2:4] + "-" + + str(value[0])[4:6]) + + self._call_dll('AlazarQueryCapability', + self._handle, 0x1000002A, 0, value.ctypes.data) + memory_size = str(value[0]) + self._call_dll('AlazarQueryCapability', + self._handle, 0x1000002C, 0, value.ctypes.data) + asopc_type = str(value[0]) + + # see the ATS-SDK programmer's guide + # about the encoding of the link speed + self._call_dll('AlazarQueryCapability', + self._handle, 0x10000030, 0, value.ctypes.data) + pcie_link_speed = str(value[0]*2.5/10)+"GB/s" + self._call_dll('AlazarQueryCapability', + self._handle, 0x10000031, 0, value.ctypes.data) + pcie_link_width = str(value[0]) + + return {'firmware': None, 'model': board_kind, - 'serial': None, - 'vendor': 'AlazarTech'} + 'serial': serial, + 'vendor': 'AlazarTech', + 'CPLD_version': cpld_ver, + 'driver_version': driver_ver, + 'SDK_version': sdk_ver, + 'latest_cal_date': latest_cal_date, + 'memory_size': memory_size, + 'asopc_type': asopc_type, + 'pcie_link_speed': pcie_link_speed, + 'pcie_link_width': pcie_link_width} def config(self, clock_source=None, sample_rate=None, clock_edge=None, decimation=None, coupling=None, channel_range=None, From 97035dd4ca4443063bf7ca7baeace6358750a8b1 Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Mon, 15 Aug 2016 19:02:29 +0200 Subject: [PATCH 38/56] fix: snapshot of alazarparameters add [parameter]._save_val to the _set method of the alazarparameter to obtain proper snapshots of the alazarparameters (cherry picked from commit 3fa15ca) --- qcodes/instrument_drivers/AlazarTech/ATS.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py index e34e30030b05..e3e03cb77d21 100644 --- a/qcodes/instrument_drivers/AlazarTech/ATS.py +++ b/qcodes/instrument_drivers/AlazarTech/ATS.py @@ -712,6 +712,7 @@ def _set(self, value): self.validate(value) self._byte = self._value_to_byte_dict[value] self._uptodate_flag = False + self._save_val(value) return None def _set_updated(self): From 526c1d6c359bbd79917c6a772f95aa8ef5e3f33b Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Mon, 15 Aug 2016 19:03:58 +0200 Subject: [PATCH 39/56] fix: ATS example notebook now works The ats example notebook now works and is a bit more to the point. Comments will be added later (cherry picked from commit 6b01319) --- docs/examples/Qcodes example ATS_ONWORK.ipynb | 475 ++++++++++++------ 1 file changed, 325 insertions(+), 150 deletions(-) diff --git a/docs/examples/Qcodes example ATS_ONWORK.ipynb b/docs/examples/Qcodes example ATS_ONWORK.ipynb index 107c791e3c47..10976efa4f86 100644 --- a/docs/examples/Qcodes example ATS_ONWORK.ipynb +++ b/docs/examples/Qcodes example ATS_ONWORK.ipynb @@ -362,7 +362,7 @@ "import qcodes.instrument.parameter as parameter\n", "\n", "qc.halt_bg()\n", - "# qc.set_mp_method('spawn') # force Windows behavior on mac\n", + "qc.set_mp_method('spawn') # force Windows behavior on mac\n", "\n", "# this makes a widget in the corner of the window to show and control\n", "# subprocesses and any output they would print to the terminal\n", @@ -387,74 +387,75 @@ "metadata": { "collapsed": false }, - "outputs": [], - "source": [ - "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1', server_name=\"alazar_server\")\n", - "contr1 = ats_contr.DFT_AcquisitionController(name='contr1', demodulation_frequency=10e6, alazar_id=0, server_name=\"alazar_server\")\n", - "contr1.set_acquisitionkwargs(#mode='NPT',\n", - " samples_per_record=1024,\n", - " records_per_buffer=70,\n", - " buffers_per_acquisition=1,\n", - " #channel_selection='AB',\n", - " #transfer_offset=0,\n", - " #external_startcapture='ENABLED',\n", - " #enable_record_headers='DISABLED',\n", - " #alloc_buffers='DISABLED',\n", - " #fifo_only_streaming='DISABLED',\n", - " #interleave_samples='DISABLED',\n", - " #get_processed_data='DISABLED',\n", - " allocated_buffers=64,\n", - " #buffer_timeout=1000\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "server=qc.instrument.server.get_instrument_server_manager(\"alazar_server\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[{'bits_per_sample': 8,\n", + " 'board_id': 1,\n", + " 'board_kind': 'ATS9870',\n", + " 'max_samples': 4294966272,\n", + " 'system_id': 1}]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "ats_inst._id" + "ATSdriver.AlazarTech_ATS.find_boards()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "collapsed": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'pcie_link_width': '4', 'asopc_type': '2435577968', 'memory_size': '4294966272', 'SDK_version': '5.9.11', 'driver_version': '5.9.11', 'firmware': None, 'latest_cal_date': '29-05-13', 'pcie_link_speed': '0.25GB/s', 'model': 'ATS9870', 'vendor': 'AlazarTech', 'serial': '910323', 'CPLD_version': '13.8'}\n" + ] + } + ], "source": [ - "alazar=server.instruments[0]" + "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1', server_name=\"alazar_server\")\n", + "print(ats_inst.get_idn())" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [], "source": [ - "alazar" + "contr1 = ats_contr.DFT_AcquisitionController(name='contr1', demodulation_frequency=10e6, alazar_id=0, server_name=\"alazar_server\")\n", + "contr1.set_acquisitionkwargs(#mode='NPT',\n", + " samples_per_record=1024,\n", + " records_per_buffer=70,\n", + " buffers_per_acquisition=1,\n", + " #channel_selection='AB',\n", + " #transfer_offset=0,\n", + " #external_startcapture='ENABLED',\n", + " #enable_record_headers='DISABLED',\n", + " #alloc_buffers='DISABLED',\n", + " #fifo_only_streaming='DISABLED',\n", + " #interleave_samples='DISABLED',\n", + " #get_processed_data='DISABLED',\n", + " allocated_buffers=64,\n", + " #buffer_timeout=1000\n", + ")" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -486,18 +487,7 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "contr1.get_alazar()==ats_inst" - ] - }, - { - "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": { "collapsed": false }, @@ -505,112 +495,297 @@ { "data": { "text/plain": [ - "[0.027273637138787041,\n", - " 0.02408165056435747,\n", - " 55.211359401767986,\n", - " 53.29892574674141,\n", - " 1.9124336550265753]" + "[0.024195745849111321,\n", + " 0.024162687348084369,\n", + " 44.607126696026356,\n", + " 54.85652805220036,\n", + " 349.750598643826]" ] }, - "execution_count": 5, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "contr1.acquisition.get()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "contr1.snapshot()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "contr1." + "contr1.acquisition()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "collapsed": false }, - "outputs": [], - "source": [ - "ats_inst.allocated_buffers.get()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "ats_inst.clear_buffers()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "t = []\n", - "for n, p in ats_inst.parameters.items():\n", - " t.append([n,p.get()])\n", - " \n", - "t" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "a = parameter.ManualParameter(name=\"a\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "data = qc.Loop(a[0:10:0.1], delay=0.1).each(contr1).run()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS9870.AlazarTech_ATS9870',\n", + " 'functions': {},\n", + " 'name': 'Alazar1',\n", + " 'parameters': {'IDN': {'__class__': 'qcodes.instrument.parameter.StandardParameter',\n", + " 'instrument': 'qcodes.instrument_drivers.AlazarTech.ATS9870.AlazarTech_ATS9870',\n", + " 'instrument_name': 'Alazar1',\n", + " 'label': 'IDN',\n", + " 'name': 'IDN',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': '',\n", + " 'value': {'CPLD_version': '13.8',\n", + " 'SDK_version': '5.9.11',\n", + " 'asopc_type': '2435577968',\n", + " 'driver_version': '5.9.11',\n", + " 'firmware': None,\n", + " 'latest_cal_date': '29-05-13',\n", + " 'memory_size': '4294966272',\n", + " 'model': 'ATS9870',\n", + " 'pcie_link_speed': '0.25GB/s',\n", + " 'pcie_link_width': '4',\n", + " 'serial': '910323',\n", + " 'vendor': 'AlazarTech'}},\n", + " 'alloc_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Alloc Buffers',\n", + " 'name': 'alloc_buffers',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLED'},\n", + " 'allocated_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Allocated Buffers',\n", + " 'name': 'allocated_buffers',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': '',\n", + " 'value': 64},\n", + " 'buffer_timeout': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Buffer Timeout',\n", + " 'name': 'buffer_timeout',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': 'ms',\n", + " 'value': 1000},\n", + " 'buffers_per_acquisition': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Buffers per Acquisition',\n", + " 'name': 'buffers_per_acquisition',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': '',\n", + " 'value': 1},\n", + " 'bwlimit1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Bandwidth limit channel 1',\n", + " 'name': 'bwlimit1',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLED'},\n", + " 'bwlimit2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Bandwidth limit channel 2',\n", + " 'name': 'bwlimit2',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLED'},\n", + " 'channel_range1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Range channel 1',\n", + " 'name': 'channel_range1',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': 'V',\n", + " 'value': 2.0},\n", + " 'channel_range2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Range channel 2',\n", + " 'name': 'channel_range2',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': 'V',\n", + " 'value': 2.0},\n", + " 'channel_selection': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Channel Selection',\n", + " 'name': 'channel_selection',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'AB'},\n", + " 'clock_edge': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Clock Edge',\n", + " 'name': 'clock_edge',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'CLOCK_EDGE_RISING'},\n", + " 'clock_source': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Clock Source',\n", + " 'name': 'clock_source',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'INTERNAL_CLOCK'},\n", + " 'coupling1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Coupling channel 1',\n", + " 'name': 'coupling1',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'AC'},\n", + " 'coupling2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Coupling channel 2',\n", + " 'name': 'coupling2',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'AC'},\n", + " 'decimation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Decimation',\n", + " 'name': 'decimation',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 0},\n", + " 'enable_record_headers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Enable Record Headers',\n", + " 'name': 'enable_record_headers',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLED'},\n", + " 'external_startcapture': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'External Startcapture',\n", + " 'name': 'external_startcapture',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'ENABLED'},\n", + " 'external_trigger_coupling': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'External Trigger Coupling',\n", + " 'name': 'external_trigger_coupling',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'AC'},\n", + " 'external_trigger_range': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'External Trigger Range',\n", + " 'name': 'external_trigger_range',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'ETR_5V'},\n", + " 'fifo_only_streaming': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Fifo Only Streaming',\n", + " 'name': 'fifo_only_streaming',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLED'},\n", + " 'get_processed_data': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Get Processed Data',\n", + " 'name': 'get_processed_data',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLED'},\n", + " 'impedance1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Impedance channel 1',\n", + " 'name': 'impedance1',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': 'Ohm',\n", + " 'value': 50},\n", + " 'impedance2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Impedance channel 2',\n", + " 'name': 'impedance2',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': 'Ohm',\n", + " 'value': 50},\n", + " 'interleave_samples': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Interleave Samples',\n", + " 'name': 'interleave_samples',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLED'},\n", + " 'mode': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Acquisiton mode',\n", + " 'name': 'mode',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'NPT'},\n", + " 'records_per_buffer': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Records per Buffer',\n", + " 'name': 'records_per_buffer',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': '',\n", + " 'value': 70},\n", + " 'sample_rate': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Sample Rate',\n", + " 'name': 'sample_rate',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': 'S/s',\n", + " 'value': 100000000},\n", + " 'samples_per_record': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Samples per Record',\n", + " 'name': 'samples_per_record',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': '',\n", + " 'value': 1024},\n", + " 'timeout_ticks': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Timeout Ticks',\n", + " 'name': 'timeout_ticks',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '10 us',\n", + " 'value': 0},\n", + " 'transfer_offset': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Transer Offset',\n", + " 'name': 'transfer_offset',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': 'Samples',\n", + " 'value': 0},\n", + " 'trigger_delay': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Delay',\n", + " 'name': 'trigger_delay',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': 'Sample clock cycles',\n", + " 'value': 0},\n", + " 'trigger_engine1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Engine 1',\n", + " 'name': 'trigger_engine1',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'TRIG_ENGINE_K'},\n", + " 'trigger_engine2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Engine 2',\n", + " 'name': 'trigger_engine2',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'TRIG_ENGINE_K'},\n", + " 'trigger_level1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Level 1',\n", + " 'name': 'trigger_level1',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 128},\n", + " 'trigger_level2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Level 2',\n", + " 'name': 'trigger_level2',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 128},\n", + " 'trigger_operation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Operation',\n", + " 'name': 'trigger_operation',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'TRIG_ENGINE_OP_J'},\n", + " 'trigger_slope1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Slope 1',\n", + " 'name': 'trigger_slope1',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'TRIG_SLOPE_POSITIVE'},\n", + " 'trigger_slope2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Slope 2',\n", + " 'name': 'trigger_slope2',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'TRIG_SLOPE_POSITIVE'},\n", + " 'trigger_source1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Source 1',\n", + " 'name': 'trigger_source1',\n", + " 'ts': '2016-08-15 19:00:34',\n", + " 'units': '',\n", + " 'value': 'EXTERNAL'},\n", + " 'trigger_source2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", + " 'label': 'Trigger Source 2',\n", + " 'name': 'trigger_source2',\n", + " 'ts': '2016-08-15 19:00:33',\n", + " 'units': '',\n", + " 'value': 'DISABLE'}}}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "data." + "ats_inst.snapshot()" ] } ], From e63d505a4aa26c25e0e3006ade9a25454c7a12ab Mon Sep 17 00:00:00 2001 From: "Damaz@my_delft" Date: Tue, 16 Aug 2016 14:25:35 +0200 Subject: [PATCH 40/56] fix: ATS example notebook is now good fix comments and it now works with loops (cherry picked from commit e7e9de2) --- docs/examples/Qcodes example ATS_ONWORK.ipynb | 1019 +++++++++++++++-- 1 file changed, 932 insertions(+), 87 deletions(-) diff --git a/docs/examples/Qcodes example ATS_ONWORK.ipynb b/docs/examples/Qcodes example ATS_ONWORK.ipynb index 10976efa4f86..922d37e58163 100644 --- a/docs/examples/Qcodes example ATS_ONWORK.ipynb +++ b/docs/examples/Qcodes example ATS_ONWORK.ipynb @@ -353,13 +353,13 @@ } ], "source": [ + "# import all necessary things\n", "%matplotlib nbagg\n", - "import matplotlib.pyplot as plt\n", - "import time\n", - "import numpy as np\n", "\n", "import qcodes as qc\n", "import qcodes.instrument.parameter as parameter\n", + "import qcodes.instrument_drivers.AlazarTech.ATS9870 as ATSdriver\n", + "import qcodes.instrument_drivers.AlazarTech.ATS_acquisition_controllers as ats_contr\n", "\n", "qc.halt_bg()\n", "qc.set_mp_method('spawn') # force Windows behavior on mac\n", @@ -372,18 +372,6 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import qcodes.instrument_drivers.AlazarTech.ATS9870 as ATSdriver\n", - "import qcodes.instrument_drivers.AlazarTech.ATS_acquisition_controllers as ats_contr" - ] - }, - { - "cell_type": "code", - "execution_count": 3, "metadata": { "collapsed": false }, @@ -398,69 +386,77 @@ " 'system_id': 1}]" ] }, - "execution_count": 3, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# Command to list all alazar boards connected to the system\n", "ATSdriver.AlazarTech_ATS.find_boards()" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'pcie_link_width': '4', 'asopc_type': '2435577968', 'memory_size': '4294966272', 'SDK_version': '5.9.11', 'driver_version': '5.9.11', 'firmware': None, 'latest_cal_date': '29-05-13', 'pcie_link_speed': '0.25GB/s', 'model': 'ATS9870', 'vendor': 'AlazarTech', 'serial': '910323', 'CPLD_version': '13.8'}\n" - ] + "data": { + "text/plain": [ + "{'CPLD_version': '13.8',\n", + " 'SDK_version': '5.9.11',\n", + " 'asopc_type': '2435577968',\n", + " 'driver_version': '5.9.11',\n", + " 'firmware': None,\n", + " 'latest_cal_date': '29-05-13',\n", + " 'memory_size': '4294966272',\n", + " 'model': 'ATS9870',\n", + " 'pcie_link_speed': '0.25GB/s',\n", + " 'pcie_link_width': '4',\n", + " 'serial': '910323',\n", + " 'vendor': 'AlazarTech'}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ + "# Create the ATS9870 instrument on the new server \"alazar_server\"\n", "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1', server_name=\"alazar_server\")\n", - "print(ats_inst.get_idn())" + "# Print all information about this Alazar card\n", + "ats_inst.get_idn()" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ - "contr1 = ats_contr.DFT_AcquisitionController(name='contr1', demodulation_frequency=10e6, alazar_id=0, server_name=\"alazar_server\")\n", - "contr1.set_acquisitionkwargs(#mode='NPT',\n", - " samples_per_record=1024,\n", - " records_per_buffer=70,\n", - " buffers_per_acquisition=1,\n", - " #channel_selection='AB',\n", - " #transfer_offset=0,\n", - " #external_startcapture='ENABLED',\n", - " #enable_record_headers='DISABLED',\n", - " #alloc_buffers='DISABLED',\n", - " #fifo_only_streaming='DISABLED',\n", - " #interleave_samples='DISABLED',\n", - " #get_processed_data='DISABLED',\n", - " allocated_buffers=64,\n", - " #buffer_timeout=1000\n", - ")" + "# Instantiate an acquisition controller (In this case we are doing a simple DFT) on the same server (\"alazar_server\") and \n", + "# provide the name of the name of the alazar card that this controller should control\n", + "acquisition_controller = ats_contr.DFT_AcquisitionController(name='acquisition_controller', \n", + " demodulation_frequency=10e6, \n", + " alazar_name='Alazar1', \n", + " server_name=\"alazar_server\")" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ + "# Configure all settings in the Alazar card\n", "ats_inst.config(#clock_source='INTERNAL_CLOCK',\n", " sample_rate=100000000,\n", " #clock_edge='CLOCK_EDGE_RISING',\n", @@ -485,6 +481,33 @@ ")" ] }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# This command is specific to this acquisition controller. The kwargs provided here are being forwarded to ats_inst.acquire\n", + "# This way, it becomes easy to change acquisition specific settings from the ipython notebook\n", + "acquisition_controller.set_acquisitionkwargs(#mode='NPT',\n", + " samples_per_record=1024,\n", + " records_per_buffer=70,\n", + " buffers_per_acquisition=1,\n", + " #channel_selection='AB',\n", + " #transfer_offset=0,\n", + " #external_startcapture='ENABLED',\n", + " #enable_record_headers='DISABLED',\n", + " #alloc_buffers='DISABLED',\n", + " #fifo_only_streaming='DISABLED',\n", + " #interleave_samples='DISABLED',\n", + " #get_processed_data='DISABLED',\n", + " allocated_buffers=64,\n", + " #buffer_timeout=1000\n", + ")" + ] + }, { "cell_type": "code", "execution_count": 7, @@ -495,11 +518,7 @@ { "data": { "text/plain": [ - "[0.024195745849111321,\n", - " 0.024162687348084369,\n", - " 44.607126696026356,\n", - " 54.85652805220036,\n", - " 349.750598643826]" + "0.024900543063357889" ] }, "execution_count": 7, @@ -508,7 +527,9 @@ } ], "source": [ - "contr1.acquisition()" + "# Getting the value of the parameter 'acquisition' of the instrument 'acquisition_controller' performes the entire acquisition \n", + "# protocol. This again depends on the specific implementation of the acquisition controller\n", + "acquisition_controller.acquisition()" ] }, { @@ -529,7 +550,7 @@ " 'instrument_name': 'Alazar1',\n", " 'label': 'IDN',\n", " 'name': 'IDN',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': {'CPLD_version': '13.8',\n", " 'SDK_version': '5.9.11',\n", @@ -546,235 +567,235 @@ " 'alloc_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Alloc Buffers',\n", " 'name': 'alloc_buffers',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLED'},\n", " 'allocated_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Allocated Buffers',\n", " 'name': 'allocated_buffers',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 64},\n", " 'buffer_timeout': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Buffer Timeout',\n", " 'name': 'buffer_timeout',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'ms',\n", " 'value': 1000},\n", " 'buffers_per_acquisition': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Buffers per Acquisition',\n", " 'name': 'buffers_per_acquisition',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 1},\n", " 'bwlimit1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Bandwidth limit channel 1',\n", " 'name': 'bwlimit1',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLED'},\n", " 'bwlimit2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Bandwidth limit channel 2',\n", " 'name': 'bwlimit2',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLED'},\n", " 'channel_range1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Range channel 1',\n", " 'name': 'channel_range1',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'V',\n", " 'value': 2.0},\n", " 'channel_range2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Range channel 2',\n", " 'name': 'channel_range2',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'V',\n", " 'value': 2.0},\n", " 'channel_selection': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Channel Selection',\n", " 'name': 'channel_selection',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'AB'},\n", " 'clock_edge': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Clock Edge',\n", " 'name': 'clock_edge',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'CLOCK_EDGE_RISING'},\n", " 'clock_source': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Clock Source',\n", " 'name': 'clock_source',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'INTERNAL_CLOCK'},\n", " 'coupling1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Coupling channel 1',\n", " 'name': 'coupling1',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'AC'},\n", " 'coupling2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Coupling channel 2',\n", " 'name': 'coupling2',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'AC'},\n", " 'decimation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Decimation',\n", " 'name': 'decimation',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 0},\n", " 'enable_record_headers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Enable Record Headers',\n", " 'name': 'enable_record_headers',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLED'},\n", " 'external_startcapture': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'External Startcapture',\n", " 'name': 'external_startcapture',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'ENABLED'},\n", " 'external_trigger_coupling': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'External Trigger Coupling',\n", " 'name': 'external_trigger_coupling',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'AC'},\n", " 'external_trigger_range': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'External Trigger Range',\n", " 'name': 'external_trigger_range',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'ETR_5V'},\n", " 'fifo_only_streaming': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Fifo Only Streaming',\n", " 'name': 'fifo_only_streaming',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLED'},\n", " 'get_processed_data': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Get Processed Data',\n", " 'name': 'get_processed_data',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLED'},\n", " 'impedance1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Impedance channel 1',\n", " 'name': 'impedance1',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'Ohm',\n", " 'value': 50},\n", " 'impedance2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Impedance channel 2',\n", " 'name': 'impedance2',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'Ohm',\n", " 'value': 50},\n", " 'interleave_samples': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Interleave Samples',\n", " 'name': 'interleave_samples',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLED'},\n", " 'mode': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Acquisiton mode',\n", " 'name': 'mode',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'NPT'},\n", " 'records_per_buffer': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Records per Buffer',\n", " 'name': 'records_per_buffer',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 70},\n", " 'sample_rate': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Sample Rate',\n", " 'name': 'sample_rate',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'S/s',\n", " 'value': 100000000},\n", " 'samples_per_record': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Samples per Record',\n", " 'name': 'samples_per_record',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 1024},\n", " 'timeout_ticks': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Timeout Ticks',\n", " 'name': 'timeout_ticks',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '10 us',\n", " 'value': 0},\n", " 'transfer_offset': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Transer Offset',\n", " 'name': 'transfer_offset',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'Samples',\n", " 'value': 0},\n", " 'trigger_delay': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Delay',\n", " 'name': 'trigger_delay',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': 'Sample clock cycles',\n", " 'value': 0},\n", " 'trigger_engine1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Engine 1',\n", " 'name': 'trigger_engine1',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'TRIG_ENGINE_K'},\n", " 'trigger_engine2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Engine 2',\n", " 'name': 'trigger_engine2',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'TRIG_ENGINE_K'},\n", " 'trigger_level1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Level 1',\n", " 'name': 'trigger_level1',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 128},\n", " 'trigger_level2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Level 2',\n", " 'name': 'trigger_level2',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 128},\n", " 'trigger_operation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Operation',\n", " 'name': 'trigger_operation',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'TRIG_ENGINE_OP_J'},\n", " 'trigger_slope1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Slope 1',\n", " 'name': 'trigger_slope1',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'TRIG_SLOPE_POSITIVE'},\n", " 'trigger_slope2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Slope 2',\n", " 'name': 'trigger_slope2',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'TRIG_SLOPE_POSITIVE'},\n", " 'trigger_source1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Source 1',\n", " 'name': 'trigger_source1',\n", - " 'ts': '2016-08-15 19:00:34',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'EXTERNAL'},\n", " 'trigger_source2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n", " 'label': 'Trigger Source 2',\n", " 'name': 'trigger_source2',\n", - " 'ts': '2016-08-15 19:00:33',\n", + " 'ts': '2016-08-16 14:21:37',\n", " 'units': '',\n", " 'value': 'DISABLE'}}}" ] @@ -785,8 +806,832 @@ } ], "source": [ + "# make a snapshot of the 'ats_inst' instrument\n", "ats_inst.snapshot()" ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DataSet:\n", + " mode = DataMode.PULL_FROM_SERVER\n", + " location = '2016-08-16/14-21-37_AlazarTest'\n", + " | | | \n", + " Setpoint | dummy_set | dummy | (50,)\n", + " Measured | acquisition_controller_acquisition | acquisition | (50,)\n", + "started at 2016-08-16 14:21:39\n" + ] + }, + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('