Skip to content

Add Windfreak SynthHD and SynthHDPro devices #110

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/devices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ These devices cover various frequency sources that provide either hardware-timed

devices/novatechDDS9m
devices/phasematrixquicksyn
devices/windfreak


Miscellaneous
Expand Down
126 changes: 126 additions & 0 deletions docs/source/devices/windfreak.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
Windfreak Synth
===============

This labscript device controls the Windfreak SynthHD and SynthHD Pro signal generators.

At present only static frequencies and DDS gating is supported.
This driver also supports external referencing.

.. note::

There have been observed, infrequent instances where the device does not update to newly programmed values.
This does not appear to be an issue with this code, but rather the device or the `windfreak` package.
As with any new hardware; trust, but verify, the output.
If you can reliably reproduce the problem, please create an issue so it can be addressed.

Installation
~~~~~~~~~~~~

This driver requires the `windfreak` package available on pip.
If using a version of Windows older than 10,
you will need to install the usb driver available from windfreak.

Usage
~~~~~

Below is a basic script using the driver.

.. code-block:: python

from labscript import *

from labscript_devices.PrawnBlaster.labscript_devices import PrawnBlaster
from labscript_devices.Windfreak.labscript_devices import WindfreakSynthHDPro

PrawnBlaster(name='prawn', com_port='COM6', num_pseudoclocks=1)

WindfreakSynthHDPro(name='WF', com_port="COM7")

StaticDDS('WF_A', WF, 'channel 0')

if __name__ == '__main__':

WF.enable_output(0) # enables channel A (0)
WF_A.setfreq(10, units = 'GHz')
WF_A.setamp(-24) # in dBm
WF_A.setphase(45) # in deg

start(0)
stop(1)

This driver supports the DDS Gate feature which can provide dynamic TTL control of the outputs.
This is done by enabling the `rf_enable` triggering mode on the synth,
as well as setting the correct `digital_gate` on the output.
Note that both outputs will be toggled on/off when using `rf_enable` modulation.

It also supports external referencing of the device.
The below script uses external clocking and gating features.

.. code-block:: python

from labscript import *

from labscript_devices.PrawnBlaster.labscript_devices import PrawnBlaster
from labscript_devices.Windfreak.labscript_devices import WindfreakSynthHDPro
from labscript_devices.NI_DAQmx.Models.NI_USB_6343 import NI_USB_6343

PrawnBlaster(name='prawn', com_port='COM6', num_pseudoclocks=1)

NI_USB_6343(name='ni_6343', parent_device=prawn.clocklines[0],
clock_terminal='/ni_usb_6343/PFI0',
MAX_name='ni_usb_6343',
)

WindfreakSynthHDPro(name='WF', com_port="COM7",
trigger_mode='rf enable',
reference_mode='external',
reference_frequency=10e6)

StaticDDS('WF_A', WF, 'channel 0',
digital_gate={'device':ni_6343, 'connection':'port0/line0'})

if __name__ == '__main__':

WF.enable_output(0) # enables channel A (0)
WF_A.setfreq(10, units = 'GHz')
WF_A.setamp(-24) # in dBm
WF_A.setphase(45) # in deg

t = 0
start(t)

# enable rf via digital gate for 1 ms at 10 ms
t = 10e-3
WF_A.enable(t)
t += 1e-3
WF_A.disable(t)

stop(t+1e-3)


Detailed Documentation
~~~~~~~~~~~~~~~~~~~~~~

.. automodule:: labscript_devices.Windfreak
:members:
:undoc-members:
:show-inheritance:
:private-members:

.. automodule:: labscript_devices.Windfreak.labscript_devices
:members:
:undoc-members:
:show-inheritance:
:private-members:

.. automodule:: labscript_devices.Windfreak.blacs_tabs
:members:
:undoc-members:
:show-inheritance:
:private-members:

.. automodule:: labscript_devices.Windfreak.blacs_workers
:members:
:undoc-members:
:show-inheritance:
:private-members:
12 changes: 12 additions & 0 deletions labscript_devices/Windfreak/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#####################################################################
# #
# /labscript_devices/Windfreak/__init__.py #
# #
# Copyright 2022, Monash University and contributors #
# #
# This file is part of labscript_devices, in the labscript suite #
# (see http://labscriptsuite.org), and is licensed under the #
# Simplified BSD License. See the license.txt file in the root of #
# the project for the full license. #
# #
#####################################################################
81 changes: 81 additions & 0 deletions labscript_devices/Windfreak/blacs_tabs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#####################################################################
# #
# /labscript_devices/Windfreak/blacs_tabs.py #
# #
# Copyright 2022, Monash University and contributors #
# #
# This file is part of labscript_devices, in the labscript suite #
# (see http://labscriptsuite.org), and is licensed under the #
# Simplified BSD License. See the license.txt file in the root of #
# the project for the full license. #
# #
#####################################################################

from blacs.device_base_class import DeviceTab


class WindfreakSynthHDTab(DeviceTab):

def __init__(self, *args, **kwargs):
if not hasattr(self,'device_worker_class'):
self.device_worker_class = 'labscript_devices.Windfreak.blacs_workers.WindfreakSynthHDWorker'
DeviceTab.__init__(self, *args, **kwargs)

def initialise_GUI(self):

print(self.settings)
conn_obj = self.settings['connection_table'].find_by_name(self.device_name).properties

self.allowed_chans = conn_obj.get('allowed_chans',None)

# finish populating these from device properties
chan_prop = {'freq':{},'amp':{},'phase':{},'gate':{}}
freq_limits = conn_obj.get('freq_limits',None)
chan_prop['freq']['min'] = freq_limits[0]
chan_prop['freq']['max'] = freq_limits[1]
chan_prop['freq']['decimals'] = conn_obj.get('freq_res',None)
chan_prop['freq']['base_unit'] = 'Hz'
chan_prop['freq']['step'] = 100
amp_limits = conn_obj.get('amp_limits',None)
chan_prop['amp']['min'] = amp_limits[0]
chan_prop['amp']['max'] = amp_limits[1]
chan_prop['amp']['decimals'] = conn_obj.get('amp_res',None)
chan_prop['amp']['base_unit'] = 'dBm'
chan_prop['amp']['step'] = 1
phase_limits = conn_obj.get('phase_limits',None)
chan_prop['phase']['min'] = phase_limits[0]
chan_prop['phase']['max'] = phase_limits[1]
chan_prop['phase']['decimals'] = conn_obj.get('phase_res',None)
chan_prop['phase']['base_unit'] = 'deg'
chan_prop['phase']['step'] = 1

dds_prop = {}
for chan in self.allowed_chans:
dds_prop[f'channel {chan:d}'] = chan_prop

self.create_dds_outputs(dds_prop)
dds_widgets,ao_widgets,do_widgets = self.auto_create_widgets()
self.auto_place_widgets(('Synth Outputs',dds_widgets))

DeviceTab.initialise_GUI(self)

# set capabilities
self.supports_remote_value_check(True)
self.supports_smart_programming(True)
#self.statemachine_timeout_add(5000,self.status_monitor)

def initialise_workers(self):

conn_obj = self.settings['connection_table'].find_by_name(self.device_name).properties
self.com_port = conn_obj.get('com_port',None)
self.trigger_mode = conn_obj.get('trigger_mode','disabled')
self.reference_mode = conn_obj['reference_mode']
self.reference_frequency = conn_obj['reference_frequency']

self.create_worker('main_worker',self.device_worker_class,{'com_port':self.com_port,
'allowed_chans':self.allowed_chans,
'trigger_mode':self.trigger_mode,
'reference_mode':self.reference_mode,
'reference_frequency':self.reference_frequency})

self.primary_worker = 'main_worker'
Loading