forked from PythonLabInstControl/SR830_LockInAmplifier
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstanford_SR830_modified.py
1351 lines (1214 loc) · 55.1 KB
/
stanford_SR830_modified.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
"""
@author: Jörg Encke, Wilfried Hortschitz, Matthias Kahr, Veronika Schrenk
This class is able to connect to the Stanford Lock-In Amplifier SR830,
regardless what Gpib-Adress the Amplifier is set.
All major functionalities have been implemented in public methods.
Literature - References:
[1]
MODEL SR830 DSP Lock-In Amplifier - Manual
by Stanford Research Systems
Revision 2.5 (10/2011)
http://www.thinksrs.com/downloads/PDFs/Manuals/SR830m.pdf
"""
import time
import imp
import sys
import warnings
import subprocess
import numpy as np
DEBUG = False
DEVICE_NAME = "Stanford_Research_Systems,SR830"
class liaSR830():
def __lin_search_logic(self):
"""
This function is meant to be called from __init__ to automatically search
for the correct gpib-address in ubuntu
"""
try:
f, filename, descr = imp.find_module('Gpib')
Gpib_package = imp.load_module('Gpib', f, filename, descr)
f, filename, descr = imp.find_module('gpib')
gpib_package = imp.load_module('gpib', f, filename, descr)
gpib_available = True
except ImportError:
gpib_available = False
print('Gpib is not available')
if gpib_available:
print("searching for correct gpib-address...")
for x in range(1, 31):
try:
self.inst = Gpib_package.Gpib(0,x)
self.inst.clear();
self.inst.write('*idn?')
time.sleep(0.8)
print("Stanford_Research_System, SR830 on gpib-address " + str(x) + " detected!")
return True
break
except gpib_package.GpibError, e:
print(str(x) + " ...")
continue
return False
def __check_if_GPIB_USB_B_Adapter_linux(self):
"""
internal method
this method checks if the GPIB-USB-B-Adapter is used instead of the GPIB-USB-HS-Adapter.
if this condition is true the method loads all needed modules in Ubuntu
"""
a = []
a = subprocess.check_output('lsusb')
x = None
for i in a.split('\n'):
if 'GPIB-USB-B' in i:
x = i
break
if x is not None:
bus_number = x[4:7]
device_number = x[15:18]
subprocess.Popen('sudo fxload -D /dev/bus/usb/' + str(bus_number)+ '/' + str(device_number) +
' -I /lib/firmware/ni_usb_gpib/niusbb_firmware.hex -s /lib/firmware/ni_usb_gpib/niusbb_loader.hex',
shell=True, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
def __init__(self):
'''
Automatically search for pre-set gpib-address from connected instrument
Check if the connected Intrument is compatible to this driver by
using check_instr-function
'''
found = False
if sys.platform.startswith('lin'):
self.__check_if_GPIB_USB_B_Adapter_linux();
found = self.__lin_search_logic();
if not found:
#print("Run \'sudo gpib_config\'")
subprocess.Popen('sudo gpib_config', shell=True, stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
print("Gpib-address could not be detected!")
print("Press F5...")
elif sys.platform.startswith('win'):
try:
f, filename, descr = imp.find_module('visa')
visa_package = imp.load_module('visa', f, filename, descr)
visa_available = True
except ImportError:
visa_available = False
print('Visa is not available')
if visa_available:
rm = visa_package.ResourceManager()
print("searching for correct gpib-address...")
for x in range(1, 31):
with warnings.catch_warnings(record = True) as w:
self.visa_instr = rm.open_resource('GPIB0::' + str(x) + '::INSTR')
if len(w):
print(str(x) + " ...")
continue
else:
print(str(x) + " ...")
if(self.check_instr()):
print "Stanford_Research_System, SR830 on gpib-address " + str(x) + " detected!"
found = True
break
if not found:
print("Gpib-address could not be detected!")
def check_instr(self):
'''
Check if the connected Intrument is compatible to this driver by
comparing the *IDN? answer to the string "Stanford_Research_Systems,SR830"
'''
if sys.platform.startswith('lin'):
self.inst.clear();
self.inst.write('*idn?')
time.sleep(0.2)
ident = self.inst.read(100)
self.inst.clear();
elif sys.platform.startswith('win'):
self.visa_instr.clear();
try:
ident = self.visa_instr.query("*IDN?")
time.sleep(3)
except:
ident = ""
self.visa_instr.clear();
if DEVICE_NAME in ident:
return True
else:
if DEBUG: print "DEBUG: Instrument "+ ident + " seems not to be Stanford_Research_Systems, SR830"
return False
def correct_phaseshift(self, phase):
"""
I have no idea what this method is supposed to do (-> untested)
"""
th=100
sig = lambda x: x < 0.
prev_sig = sig(phase[0])
prev_element = phase[0]
jump = 0
return_array = []
for element in phase:
save_element = element
if (sig(element) is not prev_sig
and abs(prev_element) > th
and abs(element) > th):
if jump: jump = 0
else: jump = -1 if prev_sig else 1
if jump:
save_element=element+ jump * 360
prev_element=element
prev_sig = sig(element)
return_array.append(save_element)
return return_array
def __GetSomething(self, cmdString):
"""
Internal function. The cmdString will be send to the instrument
to get a response.
(cmdString can be for example SENS?, FREQ?,... most likely something with a question mark)
"""
if sys.platform.startswith('win'):
self.visa_instr.clear();
resp = self.visa_instr.query(cmdString)
elif sys.platform.startswith('lin'):
self.inst.clear();
self.inst.write(cmdString)
resp = self.inst.read(100)
self.inst.clear();
if DEBUG:
print("command: " + cmdString + "; resp: " + str(resp))
return resp
def __SetSomething(self, cmdString, setValue):
"""
Internal function. The cmdString will be send to the instrument.
Use setValue to set specific Values on the instrument
(setValue can for example be the value of PHAS or FREQ,
when the cmdString contains "PHAS" or "FREQ")
"""
if sys.platform.startswith('win'):
self.visa_instr.write(cmdString + ' ' + str(setValue))
elif sys.platform.startswith('lin'):
self.inst.clear();
self.inst.write(cmdString + ' ' + str(setValue))
time.sleep(0.2)
self.inst.clear();
if DEBUG:
print("command: " + cmdString + ' ' + str(setValue))
def ConvertiToTimeconstant(self, i):
"""
converts the i-param needed for the OFLT?-command to the actual timeconstant-value
"""
options = {0 : 10e-6,
1 : 30e-6,
2 : 100e-6,
3 : 300e-6,
4 : 1e-3,
5 : 3e-3,
6 : 10e-3,
7 : 30e-3,
8 : 100e-3,
9 : 300e-3,
10: 1,
11: 3,
12: 10,
13: 30,
14: 100,
15: 300,
16: 1000,
17: 3000,
18: 10000,
19: 30000
}
try:
return options[i]
except:
raise Exception("ConvertiToTimeconstant: parameter i contains an invalid value")
def ConvertTimeconstantToi(self, timeconstant):
"""
converts the actual timeconstant-value to the i-param, needed for the OFLT-command
"""
options = {10e-6 : 0,
30e-6 : 1,
100e-6 : 2,
300e-6 : 3,
1e-3 : 4,
3e-3 : 5,
10e-3 : 6,
30e-3 : 7,
100e-3 : 8,
300e-3 : 9,
1 : 10,
3 : 11,
10 : 12,
30 : 13,
100 : 14,
300 :15,
1000 : 16,
3000 : 17,
10000 : 18,
30000 : 19
}
try:
return options[timeconstant]
except:
raise Exception("ConvertTimeconstantToi: parameter timeconstant contains an invalid value")
# by HoWil#############
def __SensitivityToVolt(self, n_In):
"""
Internal method
This function is meant to be called from .SetSensitivityLIA() to calculate
the sensitivity value out of the sensitivity settings on the lockIn
"""
# Dim m_In As Integer
m_In = n_In + 1;
voltValue = round(10**((m_In%3) / 3)) * (10**-9 * 10**np.floor(m_In / 3));
return voltValue
# end % function SensitivityToVolt
def SetSensitivityLIA(self, timeconstant = None):
"""
Automatically sets the best Sensitivity.
When the timeconstant is None the timeconstant set on the device
is being used. Attention: If this pre-set timeconstant is large, this could take awhile!
When the timecontant is not None, the timeconstant on the device is set to this timeconstant,
before the SetSensitivityLIA-Logic starts
"""
#Configure property value(s).
#set(obj, 'sens', 22.0);
bKorrekterBereich = 0;
Frequenz = self.getF();
T = 1/Frequenz
while bKorrekterBereich == 0:
if timeconstant == None:
i = self.GetTimeConst();
timeconstant = self.ConvertiToTimeconstant(i)
time.sleep(3 * timeconstant + T);
else:
i = self.ConvertTimeconstantToi(timeconstant);
self.SetTimeConst(i)
time.sleep(3 * timeconstant + T);
# end
# Query property value(s).
iSensitivityLIA = self.getSens(); # get the set sensitivity
R = self.getR();
#print " R = %f" %R
#print " iSensitivityLIA = %i" %iSensitivityLIA
vValue = self.__SensitivityToVolt(iSensitivityLIA);#!!!
#print " voltValue = %f" %voltValue
if R > vValue:
iSensitivityLIA = iSensitivityLIA + 1;
if iSensitivityLIA > 26 :
iSensitivityLIA = 26;
# end;
# Configure property value(s).
self.SetSens(iSensitivityLIA);
bKorrekterBereich = 0;
time.sleep(3 * timeconstant + 0.2 * T)
else:
#R = self.getR();
#vValue = self.__SensitivityToVolt(iSensitivityLIA);#!!!
if DEBUG: print str(vValue)
if R < 0.3 * vValue:
iSensitivityLIA = iSensitivityLIA - 1;
if iSensitivityLIA < 0:
iSensitivityLIA = 0;
# end;
if DEBUG: print("iSensitivityLIA: " + str(iSensitivityLIA))
self.SetSens(iSensitivityLIA);
bKorrekterBereich = 0;
time.sleep(3 * timeconstant + 0.2 * T)
else:
bKorrekterBereich = 1;
if DEBUG: print str(vValue)
return vValue
# end
# end
# end
# end # function SetSensitivityLIA
def SendString(self, CmdString):
"""
sends CmdString as a command to the instrument
"""
if DEBUG:
print("send string: " + CmdString)
if sys.platform.startswith('win'):
self.visa_instr.write(CmdString)
elif sys.platform.startswith('lin'):
self.inst.write(CmdString)
return
def getR(self):
"""
Query the value of R (3). Returns ASCII floating point value[1].
[additional information: other options would be: X (1), Y (2), θ (4)]
"""
R = self.__GetSomething('OUTP?3')
if DEBUG:
print("R: " + R)
return float(R)
def getPhi(self):
"""
Query the value of θ (4). Returns ASCII floating point value[1].
[additional information: other options would be: X (1), Y (2), R (3)]
"""
phi = self.__GetSomething('OUTP?4')
if DEBUG:
print("Phi: " + phi)
return float(phi)
def getSens(self):
"""
duplicate to method GetSens
The SENS? command queries the sensitivity[1].
i=0(≙2 nV/fA), i=1(≙5 nV/fA), i=2(≙10 nV/fA), i=3(≙20 nV/fA), i=4(≙50 nV/fA), i=5(≙100 nV/fA), i=6(≙200 nV/fA),
i=7(≙500 nV/fA), i=8(≙1 μV/pA), i=9(≙2 μV/pA), i=10(≙5 μV/pA), i=11(≙10 μV/pA), i=12(≙20 μV/pA), i=13(≙50 μV/pA),
i=14(≙100 μV/pA), i=15(≙200 μV/pA), i=16(≙500 μV/pA), i=17(≙1 mV/nA), i=18(≙2 mV/nA), i=19(≙5 mV/nA), i=20(≙10 mV/nA),
i=21(≙20 mV/nA), i=22(≙50 mV/nA), i=23(≙100 mV/nA), i=24(≙200 mV/nA), i=25(≙500 mV/nA), i=26(≙1 V/μA)
"""
i = self.__GetSomething('SENS?')
if DEBUG:
print("Sens: " + i)
return float(i)
def getF(self):
"""
duplicate to method GetRefFreq
The FREQ? query command will return the reference frequency
(in internal or external mode)[1].
"""
fr = self.__GetSomething('FREQ?')
if DEBUG:
print("F: " + fr)
return float(fr)
####################
#Instrument status
def SerialPollDiagnostic(self):
"""
I have no idea what this method is supposed to do (-> untested)
"""
resp = self.__GetSomething('*STB?')
SPB = int(resp) # SPB ...serial poll byte
ok = SPB & 1 | SPB & 2 | (not (SPB & 64)) #.....no command in progress
if (not ok):
SPBbit0 = SPB & 0 #no data is beeing acquired
SPBbit1 = SPB & 2 #no command execution in progress
SPBbit2 = SPB & 4 #unmasked bit in error status byte set
SPBbit3 = SPB & 8 #unmasked bit in LIA status byte set
SPBbit4 = SPB & 16 #!!!! the interface output buffer is not empty
SPBbit5 = SPB & 32 #unmasked bit in standard status byte set
SPBbit6 = SPB & 64 # SRQ has oThe FREQ? query command will return the reference frequency
SPBbit7 = SPB & 128 #not in use
if SPBbit2:
print 'unmasked bit in error status byte set'
ERRSbyte = self.__GetSomething('ERRS?')# may be subroutine call required
print 'error-status byte: ', ERRSbyte
if SPBbit3:
print 'unmasked bit in LIA status byte set'
LIASbyte = self.__GetSomething('LIAS?') # may be subroutine call required
print 'LIA-status byte: ', LIASbyte
if SPBbit4:
self.SendString('REST') # not shure that this will help
if SPBbit5:
ESRbyte = self.__GetSomething('*ESR?') # may be subroutine call required
print 'standard event-status byte: ', ESRbyte
if SPBbit6:
SPEbyte = self.__GetSomething('*SRE?') # may be subroutine call required
print 'SRQ occurred SP enable register value ', SPEbyte
return SPB
#reference settings
def SetRefRms(self,rms):
"""
The SLVL x command sets the amplitude of the sine output.
The parameter x is a voltage (real number of Volts). The value of x will
be rounded to 0.002V. The value of x is limited to 0.004 ≤ x ≤ 5.000[1].
"""
#if rms < 0.004 or rms > 5.0:
# raise Exception("SetRefRms: parameter rms can only be set to values from 0.004 to 5.0")
resp = self.__SetSomething('SLVL', rms)
return resp
def GetRefRms(self):
"""
The SLVL? command queries the amplitude of the sine output.
"""
rms = self.__GetSomething('SLVL?')
return float(rms)
def SetRefFreq(self,f):
"""
The FREQ f command sets the frequency of the internal oscillator. This
command is allowed only if the reference source is internal. The parame-
ter f is a frequency (real number of Hz). The value of f will be rounded to
5 digits or 0.0001 Hz, whichever is greater. The value of f is limited to
0.001 ≤ f ≤ 102000. If the harmonic number is greater than 1, then the
frequency is limited to nxf ≤ 102 kHz where n is the harmonic number[1].
"""
#if f < 0.001 or f > 102000:
# raise Exception("SetRefFreq: parameter f can only be set to values from 0.001 to 102000.")
resp = self.__SetSomething('FREQ', str(f))
return resp
def GetRefFreq(self):
"""
duplicate to method getF
The FREQ? query command will return the reference frequency
(in internal or external mode)[1].
"""
f = self.__GetSomething('Freq?')
return float(f)
def SetRefPhas(self, phase):
"""
The PHAS x command will set the phase shift to x.
The parameter x is the phase (real number of degrees).
The value of x will be rounded to 0.01°.
The phase may be programmed from -360.00 ≤ x ≤ 729.99 and will be
wrapped around at ±180°. For example, the PHAS 541.0 command will
set the phase to -179.00° (541-360=181=-179)[1].
"""
#if phase < -360.0 or phase > 729.99:
# raise Exception("SetRefPhas: parameter phase can only be set to values from -360.0 to 729.99")
resp = self.__SetSomething('PHAS', str(phase))
return resp
def GetRefPhas(self):
"""
The PHAS? command queries the reference phase shift[1].
"""
phase = self.__GetSomething('PHAS?')
return float(phase)
def SetRefMode(self,refmod):
"""
The FMOD i command sets the reference source. The parameter
i selects internal (i=1) or external (i=0)[1].
"""
if refmod not in (0,1):
raise Exception("SetRefMode: parameter refmode can only be set to 0 (=external) or 1(=internal)")
resp = self.__SetSomething('FMOD', str(refmod))
return resp
def __checkFractionalDigits(self, i, exception_text):
"""
internal method checks if there are other numbers than 0 among the fractional digits
"""
import decimal
if "." in str(i):
d = decimal.Decimal(i).as_tuple()
preDecimalPlaces = len(d.digits) + d.exponent
try:
fractionalDigits = int(str(i)[(preDecimalPlaces + 1):])
except:
raise Exception(exception_text)
if fractionalDigits != 0:
raise Exception(exception_text)
def GetRefMode(self):
"""
The FMOD? command queries the reference source[1].
refmod=0(≙external) or refmode=1(≙internal)
"""
refmod = self.__GetSomething('FMOD?')
return int(refmod)
def SetRefHarm(self,harm):
"""
The HARM i command sets the detection harmonic. This
parameter is an integer from 1 to 19999. The HARM i command will set
the lock-in to detect at the i th harmonic of the reference frequency. The
value of i is limited by ixf ≤ 102 kHz. If the value of i requires a detection
frequency greater than 102 kHz, then the harmonic number will be set to
the largest value of i such that ixf ≤ 102 kHz[1].
"""
#if harm < 1 or harm > 19999:
# raise Exception("harm can only be set to values from 1 to 19999")
exception_text = "SetRefHarm: parameter harm has to be int or long from 1 to 19999"
self.__checkFractionalDigits(harm, exception_text);
try:
harm = int(harm)
except:
raise Exception(exception_text)
if not isinstance( harm, ( int, long ) ):
raise Exception(exception_text)
resp = self.__SetSomething('HARM', str(harm))
return resp
def GetRefHarm(self):
"""
The HARM? command queries the detection harmonic[1].
"""
harm = self.__GetSomething('HARM?')
return int(harm)
#input and filter
def SetInputConfig(self,iconf):
"""
The ISRC command sets the input configuration. The parameter
i selects A (i=0), A-B (i=1), I (1 MΩ) (i=2) or I (100 MΩ) (i=3).
Changing the current gain does not change the instrument sensitivity.
Sensitivities above 10 nA require a current gain of 1 MΩ. Sensitivities
between 20 nA and 1 μA automatically select the 1 MΩ current gain. At
sensitivities below 20 nA, changing the sensitivity does not change the
current gain[1].
"""
if iconf not in (0, 1, 2, 3):
raise Exception("SetInputConfig: parameter iconf can only be set to value from 0 to 3\nA (iconf=0), A-B (iconf=1), I (1 MΩ) (iconf=2) or I (100 MΩ) (iconf=3)")
resp = self.__SetSomething('ISRC', str(iconf))
return resp
def GetInputConfig(self):
"""
The ISRC? command queries the input configuration[1].
iconf=0 (≙A), iconf=1(≙A-B), iconf=2 (≙I(1 MΩ)) or iconf=3(≙I(100 MΩ))
"""
iconf = self.__GetSomething('ISRC?')
return int(iconf)
def SetGNDConfig(self, gndconf):
"""
The IGND command queries the input shield grounding[1]. The
parameter gndconf selects Float (gndconf=0) or Ground (gndconf=1).
"""
if gndconf not in (0,1):
raise Exception("SetGNDConfig: parameter gndconf can only be 0(≙Float) or 1(≙Ground)")
self.__SetSomething('IGND', gndconf)
def GetGNDConfig(self):
"""
The IGND? command queries the input shield grounding[1]. The
gndconf=0(≙Float) or gndconf=1(≙Ground)
"""
gndconf = self.__GetSomething('IGND?')
return int(gndconf)
def SetInputCoupling(self,icoup):
"""
The ICPL i command sets the input coupling.
The parameter i selects AC (i=0) or DC (i=1)[1].
"""
if icoup not in (0,1):
raise Exception("SetInputCoupling: parameter icoup can only be 0(≙AC) or 1(≙DC)")
resp = self.__SetSomething('ICPL', icoup)
return resp
def GetInputCoupling(self):
"""
The ICPL? command queries the input coupling[1].
icoup=0(≙AC) or icoup=1(≙DC)
"""
icoup = self.__GetSomething('ICPL?')
return int(icoup)
def SetLineNotch(self, linotch):
"""
The ILIN i command sets the input line notch filter status. The
parameter i selects Out or no filters (i=0), Line notch in (i=1), 2xLine
notch in (i=2) or Both notch filters in (i=3)[1].
"""
if linotch not in (0,1,2,3):
raise Exception("SetLineNotch: parameter linotch can only be set to 0(≙Out or no filters), 1(≙Line notch in), 2(≙2xLine notch in) or 3(≙Both notch filters in)")
self.__SetSomething('ILIN', str(linotch))
def GetLineNotch(self):
"""
The ILIN? command queries the input line notch filter status[1].
"""
linotch = self.__GetSomething('ILIN?')
return int(linotch)
def SetSens(self, i):
"""
The SENS command sets the sensitivity[1].
i=0(≙2 nV/fA), i=1(≙5 nV/fA), i=2(≙10 nV/fA), i=3(≙20 nV/fA), i=4(≙50 nV/fA), i=5(≙100 nV/fA), i=6(≙200 nV/fA),
i=7(≙500 nV/fA), i=8(≙1 μV/pA), i=9(≙2 μV/pA), i=10(≙5 μV/pA), i=11(≙10 μV/pA), i=12(≙20 μV/pA), i=13(≙50 μV/pA),
i=14(≙100 μV/pA), i=15(≙200 μV/pA), i=16(≙500 μV/pA), i=17(≙1 mV/nA), i=18(≙2 mV/nA), i=19(≙5 mV/nA), i=20(≙10 mV/nA),
i=21(≙20 mV/nA), i=22(≙50 mV/nA), i=23(≙100 mV/nA), i=24(≙200 mV/nA), i=25(≙500 mV/nA), i=26(≙1 V/μA)
"""
exception_text = "SetSens: parameter i can only be set to int or long values from 0 to 26\n";
exception_text += "i=0(≙2 nV/fA), i=1(≙5 nV/fA), i=2(≙10 nV/fA), i=3(≙20 nV/fA), i=4(≙50 nV/fA), i=5(≙100 nV/fA), i=6(≙200 nV/fA), "
exception_text += "i=7(≙500 nV/fA), i=8(≙1 μV/pA), i=9(≙2 μV/pA), i=10(≙5 μV/pA), i=11(≙10 μV/pA), i=12(≙20 μV/pA), i=13(≙50 μV/pA), "
exception_text += "i=14(≙100 μV/pA), i=15(≙200 μV/pA), i=16(≙500 μV/pA), i=17(≙1 mV/nA), i=18(≙2 mV/nA), i=19(≙5 mV/nA), i=20(≙10 mV/nA), "
exception_text += "i=21(≙20 mV/nA), i=22(≙50 mV/nA), i=23(≙100 mV/nA), i=24(≙200 mV/nA), i=25(≙500 mV/nA), i=26(≙1 V/μA)"
self.__checkFractionalDigits(i, exception_text);
try:
i = int(i)
except:
raise Exception(exception_text)
if i < 0 or i > 26 or not(isinstance( i, ( int, long ) )):
raise Exception(exception_text)
self.__SetSomething('SENS', i)
def GetSens(self):
"""
duplicate to method getSens
The SENS? command queries the sensitivity[1].
i=0(≙2 nV/fA), i=1(≙5 nV/fA), i=2(≙10 nV/fA), i=3(≙20 nV/fA), i=4(≙50 nV/fA), i=5(≙100 nV/fA), i=6(≙200 nV/fA),
i=7(≙500 nV/fA), i=8(≙1 μV/pA), i=9(≙2 μV/pA), i=10(≙5 μV/pA), i=11(≙10 μV/pA), i=12(≙20 μV/pA), i=13(≙50 μV/pA),
i=14(≙100 μV/pA), i=15(≙200 μV/pA), i=16(≙500 μV/pA), i=17(≙1 mV/nA), i=18(≙2 mV/nA), i=19(≙5 mV/nA), i=20(≙10 mV/nA),
i=21(≙20 mV/nA), i=22(≙50 mV/nA), i=23(≙100 mV/nA), i=24(≙200 mV/nA), i=25(≙500 mV/nA), i=26(≙1 V/μA)
"""
R = self.__GetSomething('SENS?')
return int(R)
def SetReserve(self, reserve):
"""
The RMOD i command sets the reserve mode. The parameter i
selects High Reserve (i=0), Normal (i=1) or Low Noise (minimum) (i=2).
See in the manual-description of the [Reserve] key for the actual reserves for each
sensitivity[1].
"""
if reserve not in (0,1,2):
raise Exception("SetReserve: parameter reserve can only be set to the values 0(≙High Reserve), 1(≙Normal) or 2(≙Low Noise)")
self.__SetSomething('RMOD', str(reserve))
def GetReserve(self):
"""
The RMOD? command queries the reserve mode[1].
reserve=0(≙High Reserve), reserve=1(≙Normal) or reserve=2(≙Low Noise)
"""
reserve = self.__GetSomething('RMOD?')
return int(reserve)
def SetTimeConst(self,i):
"""
The OFLT i command sets the time constant[1].
i=0(≙10 μs), i=1(≙30 μs), i=2(≙100 μs), i=3(≙300 μs), i=4(≙1 ms), i=5(≙3 ms), i=6(≙10 ms),
i=7(≙30 ms), i=8(≙100 ms), i=9(≙300 ms), i=10(≙1 s), i=11(≙3 s), i=12(≙10 s), i=13(≙30 s),
i=14(≙100 s), i=15(≙300 s), i=16(≙1 ks), i=17(≙3 ks), i=18(≙10 ks), i=19(≙30 ks)
use the method self.ConvertTimeconstantToi to convert your timeconstant to the needed parameter for this method
Time constants greater than 30s may NOT be set if the harmonic x ref. frequency (detection frequency) exceeds 200 Hz.
Time constants shorter than the minimum time constant (based upon the filter slope and dynamic reserve) will set the
time constant to the minimum allowed time constant[1]. See the Gain and Time Constant operation section in the manual.
"""
exception_text = "SetTimeConst: parameter i can only be set to values from 0 to 19\n"
exception_text += "i=0(≙10 μs), i=1(≙30 μs), i=2(≙100 μs), i=3(≙300 μs), i=4(≙1 ms), i=5(≙3 ms), i=6(≙10 ms), "
exception_text += "i=7(≙30 ms), i=8(≙100 ms), i=9(≙300 ms), i=10(≙1 s), i=11(≙3 s), i=12(≙10 s), i=13(≙30 s), "
exception_text += "i=14(≙100 s), i=15(≙300 s), i=16(≙1 ks), i=17(≙3 ks), i=18(≙10 ks), i=19(≙30 ks)"
self.__checkFractionalDigits(i, exception_text);
try:
i = int(i)
except:
raise Exception(exception_text)
if i < 0 or i > 19 or not(isinstance( i, ( int, long ) )):
raise Exception(exception_text)
self.__SetSomething('OFLT', i)
def GetTimeConst(self):
"""
The OFLT? command queries the time constant[1].
use the method self.ConvertiToTimeconstant to convert the return-value of this method to the actual timeconstant
"""
tc = self.__GetSomething('OFLT?')
# 1e-5 * 10**np.floor(int(tc)/2) * (1+2*(int(tc)%2)) #numerischer Wert
return int(tc)
def SetSlope(self,slope):
"""
The OFSL i command setsthe low pass filter slope. The
parameter slope selects 6 dB/oct (slope=0), 12 dB/oct (slope=1), 18 dB/oct (slope=2) or
24 dB/oct (slope=3)[1].
"""
exception_text = "SetSlope: parameter slope can only be set to the values 0(≙6 dB/oct), 1(≙12 dB/oct), 2(≙18 dB/oct) or 3(≙24 dB/oct)."
self.__checkFractionalDigits(slope, exception_text);
try:
slope = int(slope)
except:
raise Exception(exception_text)
if slope < 0 or slope > 3 or not(isinstance( slope, ( int, long ) )):
raise Exception(exception_text)
self.__SetSomething('OFSL', slope)
def GetSlope(self):
"""
The OFSL? command queries the low pass filter slope[1].
slope=0(≙6 dB/oct), slope=1(≙12 dB/oct), slope=2(≙18 dB/oct) or
slope=3(≙24 dB/oct)
"""
slope = self.__GetSomething('OFSL?')
return int(slope)
def SetSyncFilter(self, sync):
"""
The SYNC i command sets the synchronous filter status. The
parameter i selects Off (i=0) or synchronous filtering below 200 Hz (i=1).
Synchronous filtering is turned on only if the detection frequency (refer-
ence x harmonic number) is less than 200 Hz[1].
"""
exception_text = "SetSyncFilter: parameter sync can only be set to 0(≙Off) or 1(≙synchronous filtering below 200 Hz)."
self.__checkFractionalDigits(sync, exception_text);
try:
sync = int(sync)
except:
raise Exception(exception_text)
if sync < 0 or sync > 1 or not(isinstance( sync, ( int, long ) )):
raise Exception(exception_text)
self.__SetSomething('SYNC', sync)
def GetSyncFilter(self):
"""
The SYNC? command queries the synchronous filter status[1].
sync=0(≙Off) or sync=1(≙synchronous filtering below 200 Hz).
"""
sync = self.__GetSomething('SYNC?')
return int(sync)
def SetDisplay(self, channel, j, ratio=0):
"""
The DDEF i, j, k command selects the CH1 and CH2 displays. The parameter
channel selects CH1 (channel=1) or CH2 (channel=2) and is required.
This command sets channel i to parameter j with ratio k as listed below.
CH1 (i=1) 4 CH2 (i=2)
j display j display
0 X 0 Y
1 R 1 θ
2 X Noise 2 Y Noise
3 Aux In 1 3 Aux In 3
4 Aux In 2 4 Aux In 4
k ratio k ratio
0 none 0 none
1 Aux In 1 1 Aux In 3
2 Aux In 2 2 Aux In 4
[1]
"""
ch = str(channel)
k = str(j)
rat = str(ratio)
Cmd = 'DDEF'+ ch + ',' + k + ',' + rat
self.SendString(Cmd)
return
def GetDisplay(self, channel = 1):
"""
The DDEF? i command queries the display and ratio of display i. The
returned string contains both j and k separated by a comma. For exam-
ple, if the DDEF? 1 command returns "1,0" then the CH1 display is R
with no ratio[1].
"""
resp = self.__GetSomething('DDEF? ' + str(channel));
[j,ratio] = resp.rsplit(',')
return [j,ratio]
def SetInterface(self, GPIB = True, RS232 =False):
"""
The OUTX i command sets the output interface to RS232 (i=0) or GPIB(i=1).
The OUTX i command should be sent before any query com-
mands to direct the responses to the interface in use[1].
"""
if GPIB:
Cmd = 'OUTX 1'#sets te output interface to GPIB
else:
Cmd = 'OUTX 0'#sets the output interface to RS232
self.SendString(Cmd)
return
def GetInterface(self, GPIB = False, RS232 =False):
"""
The OUTX? command queries the interface[1].
Interface=0(≙RS232) or Interface=1(≙GPIB).
"""
Ifc = self.__GetSomething('OUTX?')
if int(Ifc) == 1 :
Interface = 'GPIB'
else:
Interface = 'RS232'
return int(Ifc), Interface
def SetDisableRemoteLockoutState(self, On = True):
"""
In general, every GPIB interface command will put the SR830 into the
REMOTE state with the front panel deactivated. To defeat this feature,
use the OVRM 1 command to overide the GPIB remote. In this mode, the
front panel is not locked out when the unit is in the REMOTE state. The
OVRM 0 command returns the unit to normal remote operation[1].
"""
if On:
Cmd = 'OVRM 1' #Front panel is not locked out
else:
Cmd = 'OVRM 0' #Front panel is locked out
self.SendString(Cmd)
return
def SetKlickOn(self, On=False):
"""
The KCLK i command sets the key click On (i=1) or Off (i=0) state[1].
"""
if On:
Cmd = 'KCLK 1'
else:
Cmd = 'KCLK 0'
self.SendString(Cmd)
return
def GetKlickOn(self,On=False):
"""
The KCLK i command queries the key[1].
"""
KlickOn = self.__GetSomething('KCLK?')
return int(KlickOn)
def SetAlarm(self, On=False):
"""
The ALRM i command sets the alarm On (i=1) or Off (i=0) state[1].
"""
if On:
Cmd = 'ALRM 1'
else:
Cmd = 'ALRM 0'
self.SendString(Cmd)
return
def GetAlarm(self,On=False):
"""
The ALRM? command queries the alarm[1]
Alarm=1(≙On) or Alarm=0(≙Off).
"""
Alarm = self.__GetSomething('ALRM?')
return int(Alarm)
def SaveSettings(self, BufferAddress = 1):
"""
The SSET i command saves the lock-in setup in setting buffer i (1<i<9).
The setting buffers are retained when the power is turned off[1].
"""
self.__SetSomething('SSET', BufferAddress)
def ReactivateSettings(self, BufferAddress = 1):
"""
The RSET i command recalls the lock-in setup from setting buffer i
(1≤i≤9). Interface parameters are not changed when a setting buffer is
recalled with the RSET command. If setting i has not been saved prior to
the RSET i command, then an error will result[1].
"""
self.__SetSomething('RSET', BufferAddress)
def SetAutoGain(self):
"""
The AGAN command performs the Auto Gain function. This command is
the same as pressing the [Auto Gain] key. Auto Gain may take some
time if the time constant is long. AGAN does nothing if the time constant
is greater than 1 second. Check the command execution in progress bit
in the Serial Poll Status Byte (bit 1) to determine when the function is
finished[1].
"""
cmd = 'AGAN'
self.SendString(cmd)
return
def SetFrontOutputSource(self, which = None, Type = None):
"""
The FPOP i,j command sets the front panel (CH1 and CH2) output sources.
The parameter i selects CH1 (i=1) or CH2 (i=2) and is required.
The FPOP i, j command sets output i to quantity j where j is
listed below.
CH1 (i=1) 4 CH2 (i=2)
j output quantity j output quantity
0 CH 1 Display 0 CH 2 Display
1 X 1 Y
[1]
"""
cmd = 'FPOP ' + str(which) + ',' + str(Type)
self.SendString(cmd)
def GetFrontOutputSource(self, which= None):
"""
The FPOP? command queries the front panel (CH1 and CH2) output sources[1].
"""
resp = self.__GetSomething('FPOP?' + str(which))
if str(resp)==0:
Type = 'Display Channel '+ str(which)
else:
if which == 1:
Type = 'X'
else:
Type = 'Y'
return Type
def GetOutputOffsetAndExpand(self, i):
"""
The OEXP? i command queries the output offsets and expand of quantity i.
The parameter i selects X (i=1), Y (i=2) or R (i=3) and is required.
The returned string contains both the offset and
expand separated by a comma. For example, if the OEXP? 2 command
returns "50.00,1" then the Y offset is 50.00% and the Y expand is 10.
Setting an offset to zero turns the offset off. Querying an offset which is
off will return 0% for the offset value[1].
"""
exception_text = "GetOutputOffsetAndExpand: parameter i can only be 1(≙X), 2(≙Y) or 3(≙R)"
self.__checkFractionalDigits(i, exception_text);
try:
i = int(i)
except:
raise Exception(exception_text)
if i < 1 or i > 3 or not(isinstance( i, ( int, long ) )):
raise Exception(exception_text)
Type = ['X','Y','R']
cmd = 'OEXP? '+ str(i)
resp = self.__GetSomething(cmd)
[offset, expand] = resp.rsplit(',')
return Type[i-1], offset, expand