Skip to content

Instantly share code, notes, and snippets.

@awade
Created May 17, 2019 01:28
Show Gist options
  • Save awade/e6a104958d34dec343cd1121f51d22d8 to your computer and use it in GitHub Desktop.
Save awade/e6a104958d34dec343cd1121f51d22d8 to your computer and use it in GitHub Desktop.
Minimum working example of how to access Zurich HF2LI instrument via python API
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"toc-hr-collapsed": false
},
"source": [
"# Minimum working example for python API access to Zurich box\n",
"\n",
"--------\n",
"| Author | Andrew Wade |\n",
"| :---- | ------|\n",
"| Date | 14 May 2019 | \n",
"| Contact | andrew.richard.wade (at) gmail.com|\n",
"| Elog entry | [QIL:xxxx](https://nodus.ligo.caltech.edu:8081/QIL/xxxx) |\n",
"\n",
"----\n",
"\n",
"This notebook is a basic minimum working example for accessing the zurich box using the python API.\n",
"\n",
"To use this API interface you must install the Zurich offical software on a seperate computer and connect the Zurich box using a USB cable. Instructions for installing the data server and web server can be found in the offical manual on the [Zurich HF2LI](https://www.zhinst.com/products/hf2li). \n",
"\n",
"--------"
]
},
{
"cell_type": "markdown",
"metadata": {
"toc-hr-collapsed": true
},
"source": [
"### Server install instructions for Debian\n",
"\n",
"The Zurich box (model [HF2LI](https://www.zhinst.com/products/hf2li)) has no interface. All controls are done from a USB interface to a host computer (running windows or Ubuntu/Debian). This computer then hosts a web-server that runs an interface in a browser (through http) or responds to requests from python/matlab/labview/C API over the network. \n",
"\n",
"Set up on a linux box is fast and easy from a fresh install. A thin low powered computer is ideal."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Installing data + webserver\n",
"Start with a fresh install of [Debian](https://www.debian.org/distrib/), use the latest stable release. Then download the latest stable release for the HF2LI, HF2IS, HF2PLL instruments from the [Zurich downloads page](https://www.zhinst.com/downloads/). You’ll probably want the 64bit linux. You can untar this file with\n",
"\n",
"```bash\n",
"> tar xzvf LabOneLinux<arch>-<release>-<revision>.tar.gz\n",
"```\n",
"(Insert your filename details above)\n",
"\n",
"Then cd into the directory it created and run\n",
"```bash\n",
"> sudo bash install.sh\n",
"```\n",
"It will ask a bunch of questions, just hit enter and y all the way through.\n",
"\n",
"It should immediately boot the HF2 data server. You can check the data server is running with\n",
"```bash\n",
">ziService status\n",
"```\n",
"\n",
"Now plug in your Zurich box using the USB cable. Note: there are ethernet ports on the box, but these are NOT for network ethernet. If the box is powered up the data server should find the box. \n",
"\n",
"In another terminal you’ll want to to start a Webserver so you can view the box status, settings and live data. Go to another terminal and run\n",
"```bash\n",
"> ziWebServer\n",
"```\n",
"Your Zurich device should now be exposed on port 8006 of that machine. You are read to go.\n",
"\n",
"Now on that computer you can got to the webpage interface http://localhost:8006, alternatively on any other computer on the network you can go to the host machine’s IP address and see your Zurich interface. I.e. if the computer IP is 192.168.1.121 then go to http://192.168.1.128:8006. \n",
"\n",
"To access the python interface (next step) you’ll want to go into the webpage interface, go to the Config tab, and set Connectivity to ‘From Everywhere’. The data server on port 8005 will now be accessable to python and other APIs from other machines accessing by the computer’s external IP address."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Installing python package\n",
"You need python 3.5 or higher. Maybe just use the latest.\n",
"\n",
"make a virtual environment:\n",
"```bash\n",
">python3 -m venv myzurichenv\n",
">source myzurichenv/bin/activate\n",
"```\n",
"\n",
"Now install the zurich python API directly using pip:\n",
"```bash\n",
">pip install zhinst\n",
"```\n",
"\n",
"That’s all that is needed. You would probably also want a bunch of standard packages:\n",
"```bash\n",
">pip install numpy scipy matplotlib ipython pandas\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Setting up service to keep host alive from when box is booted\n",
"You’ll want to set up a service on your Debian box with systemd. Make a unit\n",
"```bash\n",
"> cd /etc/systemd/system\n",
"> sudo vim ziServer.service\n",
"```\n",
"You must use sudo to be able to save changes to files here.\n",
"\n",
"Paste the following in, this assumes that your username and its group is called controls on your machine:\n",
"\n",
"```\n",
"[Unit] \n",
"Description=Zurich Instruments HF2LI data server \n",
"After=syslog.target network.target \n",
"\n",
" \n",
"[Service] \n",
"User=controls \n",
"Group=controls \n",
"WorkingDirectory=/home/controls/services/ \n",
"ExecStart=/bin/bash -c \"exec ziServer\" \n",
"Restart=no \n",
"RestartSec=30 \n",
"\n",
" \n",
"[Install] \n",
"WantedBy=multi-user.target\n",
"```\n",
"\n",
"\n",
"__Tip__: in vim you can type “:set paste” to get exact paste without auto indent etc.\n",
"\n",
"\n",
"Save the file and exit. Tell systemd to look for new things:\n",
"```bash\n",
"> systemctl daemon-reload\n",
"```\n",
"\n",
"Enable the service:\n",
"```bash\n",
"> systemctl enable ziServer.service\n",
"```\n",
"\n",
"Now manually start the service:\n",
"```bash\n",
"> systemctl start myservice.service\n",
"```\n",
"\n",
"It should be running, try:\n",
"```bash\n",
"> ps | grep ziServer\n",
"```\n",
"\n",
"It should run on reboot of the machine and restart every 30 seconds if it crashes for whatever reason. Try rebooting the host machine to check it is still running\n",
"\n",
"Configuring web-server service\n",
"Follow the above steps to also auto load the webserver with a unit file named /etc/systemd/system/ziWebServer.service with text:\n",
"\n",
"```\n",
"[Unit] \n",
"Description=Zurich Instruments HF2LI web server \n",
"After=syslog.target network.target \n",
"\n",
" \n",
"[Service] \n",
"User=controls \n",
"Group=controls \n",
"WorkingDirectory=/home/controls/services/ \n",
"ExecStart=/bin/bash -c \"exec ziWebServer\" \n",
"Restart=no \n",
"RestartSec=30 \n",
"\n",
" \n",
"[Install] \n",
"WantedBy=multi-user.target\n",
"```\n",
"Now you have a local network ready server for accessing the Zurich box through a web browser and a python/matlab API."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Import stuff for accessing HF2LI and other standard packages\n",
"import zhinst.utils\n",
"import zhinst.ziPython as ziPython\n",
"import time\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Some plotting and tools for getting PSDs for testing\n",
"from scipy import signal\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A minimum working example"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ipAddress='10.0.1.23'\n",
"ipAddress='localhost'\n",
"deviceID = 'dev334'\n",
"poll_return_flat_dict = True\n",
"poll_timeout=500\n",
"demodIndexList=[2,3]\n",
"poll_length = 1.0 # Seconds\n",
" \n",
"poll_flags = 0x0004 #Throw EOFError exception if sample loss is detected\n",
"\n",
"daq = ziPython.ziDAQServer(ipAddress, 8005, 1) # open connection with dataserver\n",
"\n",
"daq.flush() # Flushes the cache of previous subscribe data in poll buffer\n",
"for ii in demodIndexList:\n",
" daq.subscribe('/{deviceID:s}/demods/{n:d}/sample'.format(deviceID=deviceID, n=ii))\n",
"\n",
"data = daq.poll(poll_length, poll_timeout, poll_flags, poll_return_flat_dict) # Get data\n",
"\n",
"daq.unsubscribe('*') # unsubscribe from all paths\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# Compute the sample frequency\n",
"clockbase = float(daq.getInt('/{:s}/clockbase'.format(deviceID)))\n",
"fs = clockbase/(data['/dev334/demods/2/sample']['timestamp'][1] - data['/dev334/demods/2/sample']['timestamp'][0])\n",
"print(fs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Class for handling access to Zurich box Lock-in tab settings and data retrieval"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class ZurichAccess():\n",
" '''\n",
" This class establishes a connection with the Zurich HF2LI box and\n",
" provides a couple of methods for accessing data streams and \n",
" configuring settings'''\n",
" \n",
" def __init__(self, ipAddress='localhost', deviceID='dev123', updateWaitTime=0.0):\n",
" assert isinstance(ipAddress, str), 'ipAddress must be string. Will be IP address of host.'\n",
" assert isinstance(deviceID, str), 'deviceID must be string. Will be unique name for physical like dev334.'\n",
" self.ipAddress = ipAddress\n",
" self.deviceID = deviceID\n",
" self.updateWaitTime = updateWaitTime\n",
" \n",
" self.daq = ziPython.ziDAQServer(ipAddress, 8005, 1) # open connection with dataserver\n",
" \n",
"# self.daq = ziPython.ziDAQServer(ipAddress, 8005, 1) # open connection with dataserver\n",
" \n",
" \n",
" def getDemod(self, poll_length, demodIndexList=[], poll_return_flat_dict = True, poll_timeout=500):\n",
" '''\n",
" Method for grabbing output of demode channels specified in demodIndexList.\n",
" Output is formated into quadratures, time base and sample frequency organized into \n",
" a channel per column.\n",
" '''\n",
" deviceID = self.deviceID\n",
" poll_flags = 0x0004 #Throw EOFError exception if sample loss is detected\n",
" \n",
" assert demodIndexList, 'You must input list of demodulators as integer array (0-5), e.g. [2,3]'\n",
" for ii in demodIndexList:\n",
" assert isinstance(ii, int) and 0<=ii<=5, 'Demod channel index numbers but be of type interger between 0 and 5'\n",
"\n",
" self.daq.flush() # Flushes the cache of previous subscribe data in poll buffer\n",
" \n",
" chanSubscribeList = ['/{deviceID:s}/demods/{n:d}/sample'.format(deviceID=deviceID, n=ii) for ii in demodIndexList]\n",
" for chanSubscribe in chanSubscribeList:\n",
" self.daq.subscribe(chanSubscribe)\n",
"\n",
" time.sleep(self.updateWaitTime)\n",
" \n",
" self.daq.sync()\n",
" data = self.daq.poll(poll_length, poll_timeout, poll_flags, poll_return_flat_dict) # Get data\n",
" clockbase = float(self.daq.getInt('/{:s}/clockbase'.format(deviceID)))\n",
"\n",
" self.daq.unsubscribe('*') # unsubscribe from all paths\n",
"\n",
" assert data, 'poll() returned an empty data dictionary, did you subscribe to any paths using demodIndexList (must also be activated on Zurich box interface) and set deviceID correct for you Zurich box?'\n",
" for chanSubscribe in chanSubscribeList:\n",
" assert chanSubscribe in data.keys(), 'One or more channels did not return data on poll, check that demod channel is enabled.'\n",
" for keydata in data:\n",
" assert not (data[keydata]['time']['dataloss'] or\n",
" data[keydata]['time']['blockloss'] or\n",
" data[keydata]['time']['invalidtimestamp']), 'One of returned data packets contained an error.'\n",
" \n",
" \n",
" # now reformat the output so that we get numpy arrays of the quadratures along with sample frequency\n",
" # and time base.\n",
" \n",
" # The Zurich API returns synchronized channel data, but the length of different\n",
" # channels can differ. The number of points will be minimum to meet the requested poll time\n",
" # However, the time base at the start matches up. So it is necessary to truncate the \n",
" # data output at shortest of the output channels to guarantee vectors of \n",
" # the same length. \n",
" \n",
" lls = min(len(dataVals['x']) for dataVals in data.values()) # find shortest channel\n",
"\n",
" # Translate data into numpy arrays grouped by quadrature, channels are columns \n",
" X = np.zeros((len(data), lls))\n",
" Y = np.zeros((len(data), lls))\n",
" t = np.zeros((len(data), lls))\n",
" for ii, dataVals in enumerate(data.values()):\n",
" X[ii,:] = dataVals['x'][:(lls)].transpose()\n",
" Y[ii,:] = dataVals['y'][:(lls)].transpose()\n",
" t[ii,:] = dataVals['timestamp'][:(lls)].transpose()\n",
"\n",
" # Compute the sampling frequency\n",
" fs = clockbase/(data[chanSubscribeList[0]]['timestamp'][1] - data[chanSubscribeList[0]]['timestamp'][0])\n",
"\n",
" return X, Y, fs, t\n",
" \n",
" def getDemodRAW(self, poll_length, demodIndexList=[], poll_return_flat_dict = True, poll_timeout=500):\n",
" '''\n",
" Returns raw flat dict output from Zurich with all metadata and original \n",
" format put out by the zhinst API'''\n",
" deviceID = self.deviceID\n",
" poll_flags = 0x0004 #Throw EOFError exception if sample loss is detected\n",
" \n",
" assert demodIndexList, 'You must input list of demodulators as integer array (0-5), e.g. [2,3]'\n",
" for ii in demodIndexList:\n",
" assert isinstance(ii, int) and 0<=ii<=5, 'Demod channel index numbers but be of type interger between 0 and 5'\n",
"\n",
" self.daq.flush() # Flushes the cache of previous subscribe data in poll buffer\n",
" \n",
" chanSubscribeList = ['/{deviceID:s}/demods/{n:d}/sample'.format(deviceID=deviceID, n=ii) for ii in demodIndexList]\n",
" for chanSubscribe in chanSubscribeList:\n",
" self.daq.subscribe(chanSubscribe)\n",
"\n",
" time.sleep(self.updateWaitTime)\n",
" \n",
" self.daq.sync()\n",
" data = self.daq.poll(poll_length, poll_timeout, poll_flags, poll_return_flat_dict) # Get data\n",
" clockbase = float(self.daq.getInt('/{:s}/clockbase'.format(deviceID)))\n",
"\n",
" self.daq.unsubscribe('*') # unsubscribe from all paths\n",
"\n",
" assert data, 'poll() returned an empty data dictionary, did you subscribe to any paths using demodIndexList (must also be activated on Zurich box interface) and set deviceID correct for you Zurich box?'\n",
" for chanSubscribe in chanSubscribeList:\n",
" assert chanSubscribe in data.keys(), 'One or more channels did not return data on poll, check that demod channel is enabled.'\n",
" for keydata in data:\n",
" assert not (data[keydata]['time']['dataloss'] or\n",
" data[keydata]['time']['blockloss'] or\n",
" data[keydata]['time']['invalidtimestamp']), 'One of returned data packets contained an error.'\n",
" \n",
" return data\n",
" \n",
" def enableDemod(self, demodIndexList):\n",
" '''\n",
" Method for enabling a list of demod channels (also known as indexes). \n",
" Format is python array [1,2,...]\n",
" '''\n",
" deviceID = self.deviceID\n",
" assert demodIndexList, 'You must input array of which lockin demodulators to poll (0-5)'\n",
" for ii in demodIndexList:\n",
" assert isinstance(ii, int), 'Demod channel index numbers must be of type interger'\n",
" \n",
" for ii in demodIndexList:\n",
"# print('/{deviceID:s}/demods/{n:d}/enable'.format(deviceID=deviceID, n=ii)) \n",
" self.daq.setInt('/{deviceID:s}/demods/{n:d}/enable'.format(deviceID=deviceID, n=ii), 1)\n",
"\n",
" def disableDemod(self, demodIndexList):\n",
" '''\n",
" Method for disabling a list of demod channels (also known as indexes). \n",
" Format is python array [1,2,...]\n",
" '''\n",
" deviceID = self.deviceID\n",
" assert demodIndexList, 'You must input array of which lockin demodulators to poll (0-5)'\n",
" for ii in demodIndexList:\n",
" assert isinstance(ii, int), 'Demod channel index numbers must be of type interger'\n",
"\n",
" for ii in demodIndexList:\n",
" # print('/{deviceID:s}/demods/{n:d}/enable'.format(deviceID=deviceID, n=ii)) \n",
" self.daq.setInt('/{deviceID:s}/demods/{n:d}/enable'.format(deviceID=deviceID, n=ii), 0) \n",
" \n",
" def setOscillatorFreq(self, oscNumberID, freq):\n",
" '''\n",
" Method for setting frequency of Zurich box internal oscillator frequencys. \n",
" oscNumberId is 1 or 2 (type int) and frequency is in Hz (min=0Hz, max=100 MHz)\n",
" '''\n",
" deviceID = self.deviceID\n",
" assert oscNumberID in [0,1], 'Oscillator ID must be int of either 0 or 1'\n",
" assert 0<=freq<=100e6, 'Oscillator frequency must be in range 0, 100MHz, units are Hz'\n",
"# print('/{deviceID:s}/oscs/{OsID:d}'.format(deviceID=deviceID,OsID=oscNumberID))\n",
" self.daq.setDouble('/{deviceID:s}/oscs/{OsID:d}/freq'.format(deviceID=deviceID,OsID=oscNumberID), freq)\n",
"\n",
" def setDemodLOChannel(self, demodIndex=None, oscNumberID=None):\n",
" '''\n",
" Method of assigning internal oscillators to demod channels. \n",
" demodIndex is interger 0 - 5 for demod channel ID. \n",
" oscNumberID assigns either channel 0 or 1 oscillator to demod channel.\n",
" '''\n",
" deviceID = self.deviceID\n",
" assert isinstance(demodIndex, int) and demodIndex in range(6), 'You must input int (0-5) for which lockin demodulators to configure'\n",
" assert oscNumberID in [0, 1]\n",
"\n",
" self.daq.setInt('/{deviceID:s}/demods/{n:d}/oscselect'.format(deviceID=deviceID, n=demodIndex), oscNumberID) \n",
"# print('/{deviceID:s}/demods/{n:d}/oscselect'.format(deviceID=deviceID, n=demodIndex))\n",
"\n",
" def setDemodLPFilter(self, demodIndex=None, LP3dBBW=10e3, LPOrder=4):\n",
" '''\n",
" Method of configuing demod low pass filter options.\n",
" demodIndex is interger 0 - 5 for demod channel ID. \n",
" LPFreq assigns the filter 3dB frequency cutoff point and LPOrder is order of filter\n",
" '''\n",
" \n",
" deviceID = self.deviceID\n",
" assert isinstance(demodIndex, int) and demodIndex in range(6), 'You must input int (0-5) for which lockin demodulators to configure'\n",
" assert 118.8e-6<=LP3dBBW<=88.39e3, 'Frequency (Hz) must be in range 120 mHz to 88 kHz.'\n",
" assert LPOrder in [1, 2, 3, 4, 5, 6, 7, 8], 'LPOrder must be int in range 1 to 8.'\n",
" \n",
" self.daq.setInt('/{deviceID:s}/demods/{n:d}/order'.format(deviceID=deviceID, n=demodIndex), LPOrder)\n",
" timeconstant= zhinst.utils.bw2tc(LP3dBBW, LPOrder)\n",
" self.daq.setDouble('/{deviceID:s}/demods/{n:d}/timeconstant'.format(deviceID=deviceID, n=demodIndex), timeconstant)\n",
" \n",
" \n",
" def setDemodSampleRate(self, demodIndex=None, demodSampleRate=None):\n",
" '''\n",
" Method of configuing demod sample rate pass filter options.\n",
" demodIndex is interger 0 - 5 for demod channel ID. \n",
" demodSampleRate assigns the sample rate of the demod channel.\n",
" '''\n",
" \n",
" deviceID = self.deviceID\n",
" assert isinstance(demodIndex, int) and demodIndex in range(6), 'You must input int (0-5) for which lockin demodulators to configure'\n",
" assert 219.6e-3<=demodSampleRate<=1.842e6, 'Frequency (Hz) must be in range 200 mHz to 1.8 MHz.'\n",
" \n",
" self.daq.setDouble('/{deviceID:s}/demods/{n:d}/rate'.format(deviceID=deviceID, n=demodIndex), demodSampleRate)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ZA = ZurichAccess(ipAddress='10.0.1.23', deviceID='dev334', updateWaitTime=0.0)\n",
"# ZA = ZurichAccess(ipAddress='localhost', deviceID='dev334', updateWaitTime=10.0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Reset to some defaults\n",
"for ii in range(2):\n",
" ZA.setOscillatorFreq(ii, 1e6)\n",
"\n",
"for ii in range(6):\n",
" ZA.setDemodLOChannel(demodIndex=ii,oscNumberID=0)\n",
" ZA.setDemodLPFilter(demodIndex=ii, LP3dBBW=10.0e3)\n",
" ZA.setDemodSampleRate(demodIndex=ii, demodSampleRate=30.e3)\n",
" ZA.disableDemod([ii])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Test for retrieving 1.0 second of data from all channels using raw getDemod method\n",
"ZA.enableDemod(range(6)) # Enable all the channels\n",
" \n",
"tic = time.time() # Start a timer\n",
"for testn in range(6):\n",
" print('Index requested {}:'.format(testn))\n",
" try:\n",
" testOut = ZA.getDemodRAW(1.0, demodIndexList=[testn]) # These are taken in sequence rather than at the same time\n",
" print(testOut.keys()) # Print out the channal recovered\n",
" print('yes, data obtained for this channel.')\n",
" except:\n",
" print('nope, no data gotten for this channel.')\n",
"\n",
"print('')\n",
"print('Total time to collect channels separately {:.2f}s'.format(time.time()-tic)) # Total time for getting channels in sequence "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Testing collection of two channels of demod tab and make a PSD\n",
"\n",
"This example uses the getDemod method that formats data into nice equal length matrixes.\n",
"\n",
"Settings are enabled using looping to make both channels the same. Data collected for multiple channels in a single ZA.getDemod command is synchronous. Often the poll commands will collect a minimum of the requested time but total number of points after that lower bound can be variable. The time bases match up so the data in the ZA.getDemod method truncates to the shortest of the returned channels."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# A test of a single batch recovered for WOPO homodyne setup\n",
"# Modify settings and channels to your initial test requirments.\n",
"ZA.setOscillatorFreq(0, 500e3)\n",
"\n",
"for ii in [2,3]: # Set up channels 3 and 4 with same settings\n",
" ZA.setDemodLOChannel(demodIndex=ii, oscNumberID=0)\n",
" ZA.setDemodLPFilter(demodIndex=ii, LP3dBBW=10.e3, LPOrder=4)\n",
" ZA.setDemodSampleRate(demodIndex=ii, demodSampleRate=30.e3)\n",
"\n",
"ZA.enableDemod([2,3]) # Enable both channels as a last step of setup\n",
"\n",
"# Now recover data and plot\n",
"X, Y, fs, _ = ZA.getDemod(2.0, demodIndexList=[2,3])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fres = 12.08 # PSD resolution bandwidth [Hz]\n",
"\n",
"f, Pxx_den = signal.welch(X, fs=fs, nperseg=fs/fres) # compute PSDs of all channels\n",
"\n",
"fig1 = plt.figure(figsize=(8,6))\n",
"ax = fig1.add_subplot(111)\n",
"for ii in range(len(Pxx_den)):\n",
" ax.loglog(f, np.sqrt(Pxx_den[ii,:]))\n",
"ax.set_title('Compair ASD two demodulation of two inputs of Zurich at 500 MHz with 10 kHz LPF ')\n",
"ax.set_xlabel('Frequency [Hz]')\n",
"ax.set_ylabel('ASD [V/rtHz]')\n",
"ax.grid(True, which='both')\n",
"ax.margins(x=0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### More Official Examples"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('Examples files showing various Zurich box python API examples can '\n",
" 'be found in the examples folder of the installed zhinst package that can be '\n",
" 'found at {} on your local machine.'.format(zhinst.__file__))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# To get documentation do something like\n",
"help(ziPython.ziDAQServer.poll)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"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.6.7"
},
"toc-autonumbering": false,
"toc-showcode": false,
"toc-showmarkdowntxt": false,
"toc-showtags": false
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment