This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Talk to SR850 lockin amplifier | |
# version 1, 2014-01-20 | |
# Amar | |
import visa | |
import numpy as np | |
from datetime import date | |
import time | |
class LIA(visa.SerialInstrument): | |
# Lock-in amplifier, SR850 | |
def __init__(self,portName): | |
visa.SerialInstrument.__init__(self,portName) | |
self.timeout = 3 | |
self.id = self.ask("*IDN?") | |
def characterize(self): | |
warnings = "" | |
print self.id | |
print "Sensitivity = ", self.ask("SENS?") | |
print "Reserve = ", self.ask("RSRV?") | |
if self.ask("RSRV?")!="0": warnings+= "** Warning! Dynamic reserve is not 0 dB ** \n" | |
print "Time constant = ", self.ask("OFLT?") | |
print "Traces = ", self.ask("TRCD?1"), self.ask("TRCD?2"), self.ask("TRCD?3"), self.ask("TRCD?4") | |
FMOD = self.ask("FMOD?") | |
if FMOD == "0": FMODString = "internal" | |
elif FMOD == "1": FMODString = "internal sweep" | |
elif FMOD == "2": FMODString = "external" | |
print "Ref. source = ", FMODString | |
print "Ref. frequency = ", self.ask("FREQ?") | |
print "Ref. phase = ", self.ask("PHAS?") | |
print "Ref. sine level = ", self.ask("SLVL?") | |
print warnings | |
def setf(self,fi): | |
self.write("FREQ " + `fi`) | |
def setphase(self,p): | |
self.write("PHAS " +`p`) | |
def getAverage(self,channel=1,N=400): | |
# channel #s: 1 = X, 2 = Y, 3 = R, 4 = Theta | |
S = [] | |
for i in range(N): S.append( float(self.ask("OUTP?" + `channel`)) ) | |
S_avg = np.average(S) | |
S_std = np.std(S) | |
return S_avg, S_std | |
def scanP(self,f,channel=1,N=100,std=False): | |
# channels: 1 = X, 2 = Y, 3 = R, 4 = Theta | |
output, err = [], [] | |
for fi in f: | |
self.setf(fi) | |
print self.ask("FREQ?"), | |
x = [] | |
for i in range(N): x.append( float(self.ask("OUTP?"+`channel`)) ) | |
x_avg = np.average(x) | |
output.append( x_avg ) | |
x_std = np.std(x) | |
err.append( x_std ) | |
if std: return output, err | |
else: return output | |
def scanR(self,f,trace=1,N=100,std=False): | |
# traces: 1,2,3,4 | |
output, err = [], [] | |
for fi in f: | |
self.setf(fi) | |
print self.ask("FREQ?"), | |
x = [] | |
for i in range(N): x.append( float(self.ask("OUTR?"+`trace`)) ) | |
x_avg = np.average(x) | |
output.append( x_avg ) | |
x_std = np.std(x) | |
err.append( x_std ) | |
if std: return output, err | |
else: return output |
Here is how to use these utility functions to measure a noise spectrum with the SR850. (Watch out for the dynamic reserve when making noise measurements!)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SR850 as a spectrum analyzer | |
# version 1, 2014-01-21 | |
# Amar | |
import os | |
os.chdir("c:/data/googledrive/code") | |
import SR850 | |
import numpy as np | |
import pylab as plt | |
lia= SR850.LIA("COM7") | |
lia.characterize() | |
lia.write("TRCD 1,5,0,0,0") # set trace 1 to Xn (rms noise in X quadrature, V/rt-Hz) | |
lia.write("TRCD 2,6,0,0,0") # set trace 2 to Yn (rms noise in Y quadrature, V/rt-Hz) | |
background = True | |
Navg = 1000 | |
f = 10**np.arange(0,4,0.2) | |
Xn, Xn_err = np.array( lia.scanR(f,trace=1,N=Navg,std=True) ) | |
if background: | |
foo = raw_input("Ready for background measurement?") | |
Xn_bg, Xn_bg_err = np.array( lia.scanR(f,trace=1,N=Navg,std=True) ) | |
lia.close() | |
plt.figure(1) | |
plt.title("Current noise spectrum with lock-in \n G = 1e9 V/A, 10 mV FS, 0 dB reserve") | |
plt.xlabel("Frequency, f [Hz]") | |
plt.ylabel("Current noise, \sqrt{W_I} [A/\sqrt{\mathrm{Hz}}]") | |
plt.xscale('log') | |
plt.yscale('log') | |
plt.errorbar(f,np.sqrt(2) * Xn/1e9,yerr = 20 * np.sqrt(2) * Xn_err/1e9,color='b',marker='o',lw=2,label="Beam on") | |
if background: | |
plt.errorbar(f,np.sqrt(2) * Xn_bg/1e9,yerr = 20 * np.sqrt(2) * Xn_bg_err/1e9,color='g',marker='^',lw=2,label="Background") | |
plt.plot(f,np.sqrt(2*1.6e-19*1.7e-9)*np.ones(len(f)),'b--',lw=4, alpha=0.5,label="Shot noise") | |
plt.legend(loc='upper right') | |
plt.show() |