diff options
author | Eugeniy E. Mikhailov <evgmik@gmail.com> | 2021-11-29 23:24:53 -0500 |
---|---|---|
committer | Eugeniy E. Mikhailov <evgmik@gmail.com> | 2021-11-29 23:24:53 -0500 |
commit | 8ce6318636c98a2c051a9221d6509ca3f56bb224 (patch) | |
tree | fa432f42b8be1ce394ccad208c6b84bd69eb8885 /scope.py | |
parent | 36c7de408cc81c801e93060f606f37c486cd32e5 (diff) | |
download | qolab-8ce6318636c98a2c051a9221d6509ca3f56bb224.tar.gz qolab-8ce6318636c98a2c051a9221d6509ca3f56bb224.zip |
draft of the scope class with SDS1104x scope implementation
Diffstat (limited to 'scope.py')
-rw-r--r-- | scope.py | 139 |
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) + + + |