aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scope.py139
1 files changed, 139 insertions, 0 deletions
diff --git a/scope.py b/scope.py
new file mode 100644
index 0000000..dadb09a
--- /dev/null
+++ b/scope.py
@@ -0,0 +1,139 @@
+"""
+Provide basic class to operate scope
+Created by Eugeniy E. Mikhailov 2021/11/29
+"""
+
+import pyvisa
+import scpi
+import re
+import numpy as np
+
+class Scope(scpi.SCPIinstr):
+ """
+ Do not instantiate directly, use
+ rm = pyvisa.ResourceManager()
+ Scope(rm.open_resource('TCPIP::192.168.0.2::INSTR'))
+ """
+ def __init__(self, resource):
+ super().__init__(resource)
+
+class SDS1104x(Scope):
+ def __init__(self, resource):
+ super().__init__(resource)
+ self.resource.read_termination='\n'
+ self.maxRequiredPoints = 1000; # desired number of points per channel, can return twice more
+
+ def mean(self, chNum):
+ # get mean on a specific channel calculated by scope
+ # PAVA stands for PArameter VAlue
+ qstr = f'C{chNum}:PAVA? MEAN'
+ rstr = self.query(qstr);
+ # reply is in the form 'C1:PAVA MEAN,3.00E-02V'
+ spltStr = re.split(',', rstr)
+ rstr = spltStr[1]
+ spltStr = re.split('V', rstr)
+ rstr = spltStr[0]
+ return( float(rstr) )
+
+ def getAvailableNumberOfPoints(self, chNum):
+ if chNum != 1 and chNum != 3:
+ # for whatever reason 'SAMPLE_NUM' fails for channel 2 and 4
+ chNum = 1
+ qstr = f'SAMPLE_NUM? C{chNum}'
+ rstr = self.query(qstr)
+ # reply is in the form 'SANU 7.00E+01pts'
+ spltStr = re.split(' ', rstr)
+ spltStr = re.split('pts', spltStr[1])
+ rstr = spltStr[0]
+ return( int(float(rstr)) )
+
+ def getSampleRate(self):
+ rstr = self.query('SAMPLE_RATE?');
+ # expected reply is like 'SARA 1.00E+09Sa/s'
+ spltStr = re.split(' ', rstr)
+ spltStr = re.split('Sa/s', spltStr[1])
+ rstr = spltStr[0]
+ return( int(float(rstr)) )
+
+ def getRawWaveform(self, chNum, availableNpnts=None, sampleRate=None, maxRequiredPoints=None):
+ if availableNpnts == None:
+ availableNpnts = self.getAvailableNumberOfPoints(chNum)
+ if sampleRate == None:
+ sampleRate = self.getSampleRate()
+ if maxRequiredPoints == None:
+ maxRequiredPoints = self.maxRequiredPoints
+
+ if availableNpnts <= maxRequiredPoints*2:
+ Npnts = availableNpnts
+ sparsing = 1
+ cstr = f'WAVEFORM_SETUP NP,0,FP,0,SP,{sparsing}'
+ self.write(cstr)
+ else:
+ sparsing = int(np.floor(availableNpnts/maxRequiredPoints))
+ Npnts = int(np.floor(availableNpnts/sparsing))
+ cstr = f'WAVEFORM_SETUP SP,{sparsing},NP,{Npnts},FP,0'
+ # Note: it is not enough to provide sparsing (SP),
+ # number of points (NP) needed to be calculated properly too!
+ # From the manual
+ # WAVEFORM_SETUP SP,<sparsing>,NP,<number>,FP,<point>
+ # SP Sparse point. It defines the interval between data points.
+ # For example:
+ # SP = 0 sends all data points.
+ # SP = 1 sends all data points.
+ # SP = 4 sends every 4th data point
+ # NP — Number of points. It indicates how many points should be transmitted.
+ # For example:
+ # NP = 0 sends all data points.
+ # NP = 50 sends a maximum of 50 data points.
+ # FP — First point. It specifies the address of the first data point to be sent.
+ # For example:
+ # FP = 0 corresponds to the first data point.
+ # FP = 1 corresponds to the second data point
+
+ qstr = f'C{chNum}:WAVEFORM? DAT2'
+ wfRaw=self.query_binary_values(qstr, datatype='b', header_fmt='ieee', container=np.array)
+ # expected full reply: 'C1:WF DAT2,#9000000140.........'
+ return(wfRaw)
+
+ def getChanVoltsPerDiv(self, chNum):
+ qstr = f'C{chNum}:VDIV?'
+ rstr = self.query(qstr)
+ # expected reply to query: 'C1:VDIV 1.04E+00V'
+ res = re.split(' ', rstr)
+ res = re.split('V', res[1])
+ VoltsPerDiv = float(res[0])
+ return(VoltsPerDiv)
+
+ def getChanOffset(self, chNum):
+ qstr = f'C{chNum}:OFST?'
+ rstr = self.query(qstr)
+ # expected reply to query: 'C1:OFST -1.27E+00V'
+ res = re.split(' ', rstr)
+ res = re.split('V', res[1])
+ VoltageOffset = float(res[0])
+ return(VoltageOffset)
+
+ def getWaveform(self, chNum, availableNpnts=None, sampleRate=None, maxRequiredPoints=None):
+ wfRaw = self.getRawWaveform(chNum, availableNpnts=availableNpnts, sampleRate=sampleRate, maxRequiredPoints=maxRequiredPoints)
+ vertDivOnScreen = 10
+ VoltageOffset = self.getChanOffset(chNum)
+ VoltsPerDiv = self.getChanVoltsPerDiv(chNum)
+ return( wfRaw * VoltsPerDiv * vertDivOnScreen/250 -VoltageOffset )
+
+
+if __name__ == '__main__':
+ print("testing")
+ rm = pyvisa.ResourceManager()
+ print(rm.list_resources())
+ instr=rm.open_resource('TCPIP::192.168.0.61::INSTR')
+ scope = SDS1104x(instr)
+ print(scope.idn)
+ print(scope.mean(1))
+ print(scope.getAvailableNumberOfPoints(1))
+ print(scope.getSampleRate())
+ print(scope.getChanVoltsPerDiv(1))
+ print(scope.getChanOffset(1))
+ wf = scope.getWaveform(1)
+
+
+