diff --git a/docs/changes/newsfragments/7865.improved_driver b/docs/changes/newsfragments/7865.improved_driver new file mode 100644 index 00000000000..973e39fe2c3 --- /dev/null +++ b/docs/changes/newsfragments/7865.improved_driver @@ -0,0 +1 @@ +Add convenience methods to Tektronix DPO7200xx (``single``, ``download_waveforms``, ``get_timebase``) and AWG70000A (``upload_seqx``) drivers for streamlined waveform acquisition and sequence upload workflows. diff --git a/docs/examples/basic_examples/Station.ipynb b/docs/examples/basic_examples/Station.ipynb index 52155731aaf..8497bf9a1c8 100644 --- a/docs/examples/basic_examples/Station.ipynb +++ b/docs/examples/basic_examples/Station.ipynb @@ -621,14 +621,14 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "import sys\n", "\n", - "from qcodes.utils.installation import register_station_schema_with_vscode\n", + "from qcodes.extensions import register_station_schema_with_vscode\n", "\n", "# if statement for CI only\n", "if sys.platform == \"win32\" and os.path.exists(\n", diff --git a/src/qcodes/instrument_drivers/tektronix/AWG70000A.py b/src/qcodes/instrument_drivers/tektronix/AWG70000A.py index 28bcff15c0d..ca6a97b8a01 100644 --- a/src/qcodes/instrument_drivers/tektronix/AWG70000A.py +++ b/src/qcodes/instrument_drivers/tektronix/AWG70000A.py @@ -708,6 +708,32 @@ def stop(self) -> None: """ self.write("AWGControl:STOP") + def upload_seqx(self, seqx_input, sequence_name="seq") -> None: + """ + A convenience function to upload a sequence to the instrument's memory and add it to the + sequence list. Enable outputs and put awg in play mode. + + Args: + seqx_input: The input needed to make a seqx file, preferably the + output of makeSEQXFileInput. + sequence_name: The name of the sequence (as it appears in the sequence list, not the file name). + If a sequence with the same name already exists, it will be overwritten. + + """ + + seqx = self.makeSEQXFile(*seqx_input) + self.sendSEQXFile(seqx, sequence_name + ".seqx") + # Load the sequence file from local AWG storage to playback memory + self.loadSEQXFile(sequence_name + ".seqx") + self.ch1.setSequenceTrack(sequence_name, 1) + self.ch2.setSequenceTrack(sequence_name, 2) + # Turn on outputs and play + self.ch1.state(1) # Enable channel 1 output + self.ch2.state(1) # Enable channel 2 output + # Make sure all output is on (in case it was turned off globally) + self.all_output_off(0) + self.play() + @property def sequenceList(self) -> list[str]: """ diff --git a/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py b/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py index fd4c162c3e8..86ee7775ae5 100644 --- a/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py +++ b/src/qcodes/instrument_drivers/tektronix/DPO7200xx.py @@ -158,6 +158,64 @@ def ask_raw(self, cmd: str) -> str: self.visa_log.debug(f"Response: {response}") return response + def single(self): + """ + Set scope into single acquisition mode and wait for triggered acquisition + """ + self.acquisition.stop_after("SEQUENCE") + self.acquisition.state("RUN") + timeout_val = self.timeout() + timeout = timeout_val if timeout_val is not None else 10.0 + start_time = time.time() + while True: + acq_state = self.acquisition.state().strip() + trigger_state = self.trigger.ready().strip() + # logger.info(f"Trigger: {trigger_state}, Acquisition: {acq_state}") + if (acq_state == "1") and (trigger_state == "1"): + break + + if time.time() - start_time > timeout: + break + time.sleep(0.1) + + def download_waveforms(self) -> tuple: + """ + Wait for acquisition of a triggered waveform to complete and then + download acquired waveforms from the enabled channels the Tektronix scope. + """ + timeout_val = self.timeout() + timeout = timeout_val if timeout_val is not None else 60.0 + start_time = time.time() + while True: + acq_state = self.acquisition.state().strip() + if acq_state == "0": + break + if time.time() - start_time > timeout: + break + time.sleep(0.1) + + # Only download waveforms from enabled channels + wfms = () + for ch in self.channel: + if self.ask(f"SELect:{ch._identifier}?").strip() == "1": + ch.set_trace_length(self.horizontal.record_length()) + wfms += ( + ch.waveform.trace(), + ) # This will trigger the actual download of the waveform + return wfms + + def get_timebase(self) -> tuple: + """ + Get the timebase of the scope in seconds per division + + Returns: + Tuple of time unit (str) and time axis values (np.ndarray) + + """ + time_unit = self.channel[0].waveform.trace_axis + time_axis = self.channel[0].waveform.trace_axis() + return time_unit.unit, time_axis + class TektronixDPOData(InstrumentChannel): """