colinoflynn/pico-python

ps6000.py _lowLevelGetTimebase returns error 14 for timebase 0 (200 ps) for PS6404C

otamichalekSTFC opened this issue · 14 comments

Hi, I am trying to use timebase 0 as in Programmer's guide/2.7 Timebases. I am currently only able to achieve timebase 2 (800 ps between points), but for 1 and 0, the device returns an error 14.

The error comes from the ps6000.py _lowLevelGetTimebase method: m = self.lib.ps6000GetTimebase2 ... on line 298 of ps6000.py. I tried the following to see if I might not be using too many or not enough samples (timebase only works when > 2):

    peaksmax = 100
    samples = int(((12.5E-9)*peaksmax)/(2E-10))
    timebase =0

    for i in range(0,samples):
        m = ps.lib.ps6000GetTimebase2(c_int16(ps.handle), c_uint32(timebase),
                                            c_uint32(i), byref(c_float()),
                                            c_int16(0), byref(c_int32()),
                                            c_uint32(0))
        print("{} samples, error: {}".format(i,m))
        if m == 0:
            break

I kept getting m = 14, which stops the script from claiming an incorrect time base.

  File "ps6000_demo.py", line 83, in <module>
    ps.setSamplingInterval(sampling_interval, obs_duration)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 376, in setSamplingInterval
    self.timebase, noSamples, oversample, segmentIndex)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/ps6000.py", line 302, in _lowLevelGetTimebase
    self.checkResult(m)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 1150, in checkResult
    str(inspect.stack()[1][3]), ecName, ecDesc))
OSError: Error calling _lowLevelGetTimebase: PICO_INVALID_TIMEBASE (The timebase is not supported or is invalid.)

Could you please help? Maybe I'm doing something wrong or it also might be the c wrapper issue?

Please provide full code needed to reproduce the issue. Some notes in the guide state that the maximum time base depends on the number of enabled channels.

Hi, here you go. There's the few testing lines added with the for loop...

from __future__ import division
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

import time
from picoscope import ps6000
import matplotlib.pyplot as plt
import numpy as np

if __name__ == "__main__":
    #print(__doc__)

    print("Attempting to open Picoscope 6000...")

    ps = ps6000.PS6000()

    print("Found the following picoscope:")
    #print(ps.getAllUnitInfo())

    
    obs_duration = 1E-9 #(12.5E-9)*5
    #sampling = 64
    
    sampling_interval = 0.2E-9

    #sampling_interval = obs_duration / sampling

    """ 
    (actualSamplingInterval, nSamples, maxSamples) = \
        ps.setSamplingInterval(sampling_interval, obs_duration)

    """  
    
    
    peaksmax = 100
    samples = int(((12.5E-9)*peaksmax)/(2E-10))
    timebase =0

    for i in range(0,samples):
        m = ps.lib.ps6000GetTimebase2(c_int16(ps.handle), c_uint32(timebase),
                                            c_uint32(i), byref(c_float()),
                                            c_int16(0), byref(c_int32()),
                                            c_uint32(0))
        print("{} samples, error: {}".format(i,m))
        if m == 0:
            break

    (actualSamplingInterval, nSamples, maxSamples) = \
        ps.setSamplingInterval(sampling_interval, obs_duration)
    
    print("Sampling interval = {:.3f} ns".format(actualSamplingInterval * 1E9))
    print("Taking  samples = %d" % nSamples)
    print("Maximum samples = %d" % maxSamples)

    channelRange = ps.setChannel('A', 'DC', 0.05, 0.0, enabled=True,
                                 BWLimited=False)
    print("Chosen channel range = {:.3f}".format(channelRange))

    ps.setSimpleTrigger('A', 0.025, 'Rising', timeout_ms=1, enabled=True)


    time.sleep(2.0)
    ps.runBlock()
    ps.waitReady()
    print("Done waiting for trigger")
    
    dataA = ps.getDataV('A', nSamples, returnOverflow=False)
    dataTimeAxis = np.arange(nSamples) * actualSamplingInterval * 1E9

    ps.stop()
    ps.close()

    plt.plot(dataTimeAxis, dataA,"-o")
    plt.grid(True, which='major')
    plt.title("Picoscope 6000 waveforms")
    plt.ylabel("Voltage (V)")
    plt.xlabel("Time (ns)")
    plt.show()

Many thanks!

where is line 83 in the provided example....

Excuse me? It's 79 lines total?

Oh I see. Sorry. The for loop was for testing. This is the initial code which returned the error. In this code the line 83 from error message is on line 25 as I removed the docs (I edited the example for ps5000).

from __future__ import division
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

import time
from picoscope import ps6000
import matplotlib.pyplot as plt
import numpy as np

if __name__ == "__main__":
    #print(__doc__)

    print("Attempting to open Picoscope 6000...")

    ps = ps6000.PS6000()

    print("Found the following picoscope:")
    #print(ps.getAllUnitInfo())

    
    obs_duration = (12.5E-9)*5    
    sampling_interval = 0.2E-9

    (actualSamplingInterval, nSamples, maxSamples) = ps.setSamplingInterval(sampling_interval, obs_duration)
    
    print("Sampling interval = {:.3f} ns".format(actualSamplingInterval * 1E9))
    print("Taking  samples = %d" % nSamples)
    print("Maximum samples = %d" % maxSamples)

    channelRange = ps.setChannel('A', 'DC', 0.05, 0.0, enabled=True,
                                 BWLimited=False)
    print("Chosen channel range = {:.3f}".format(channelRange))

    ps.setSimpleTrigger('A', 0.025, 'Rising', timeout_ms=1, enabled=True)


    time.sleep(2.0)
    ps.runBlock()
    ps.waitReady()
    print("Done waiting for trigger")
    
    dataA = ps.getDataV('A', nSamples, returnOverflow=False)
    dataTimeAxis = np.arange(nSamples) * actualSamplingInterval * 1E9

    ps.stop()
    ps.close()

    plt.plot(dataTimeAxis, dataA,"-o")
    plt.grid(True, which='major')
    plt.title("Picoscope 6000 waveforms")
    plt.ylabel("Voltage (V)")
    plt.xlabel("Time (ns)")
    plt.show()

So the error message reads

  File "ps6000_demo.py", line 25, in <module>
    ps.setSamplingInterval(sampling_interval, obs_duration)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 376, in setSamplingInterval
    self.timebase, noSamples, oversample, segmentIndex)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/ps6000.py", line 302, in _lowLevelGetTimebase
    self.checkResult(m)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 1150, in checkResult
    str(inspect.stack()[1][3]), ecName, ecDesc))
OSError: Error calling _lowLevelGetTimebase: PICO_INVALID_TIMEBASE (The timebase is not supported or is invalid.)

I'm going to ask one more thing:

Can you remove all lines of code after the error.
Then remove all lines of code before the error that are unrelated to the error.

This helps us really focus.

Ok. Hopefully, this is ok.

Used python script:

from __future__ import division
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

from picoscope import ps6000

ps = ps6000.PS6000()

obs_duration = (12.5E-9)*5    
sampling_interval = 0.2E-9

(actualSamplingInterval, nSamples, maxSamples) = ps.setSamplingInterval(sampling_interval, obs_duration)

Returned Error:

Traceback (most recent call last):
  File "simple.py", line 13, in <module>
    (actualSamplingInterval, nSamples, maxSamples) = ps.setSamplingInterval(sampling_interval, obs_duration)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 376, in setSamplingInterval
    self.timebase, noSamples, oversample, segmentIndex)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/ps6000.py", line 302, in _lowLevelGetTimebase
    self.checkResult(m)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 1150, in checkResult
    str(inspect.stack()[1][3]), ecName, ecDesc))
OSError: Error calling _lowLevelGetTimebase: PICO_INVALID_TIMEBASE (The timebase is not supported or is invalid.)

Yes much better! Great minimum reproducing example. It really helps us focus.

Honestly, I wonder if any of the "special" timebases work:
image

I dont have a picoscope, so I can't actually try it. It is likely the fact that we don't compute any of those correctly.

Can you edit: /home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py to print out the values of all the parameters that are passed?

I also edited it to print values from ps600.py as that is where the timebase is first evaluated.

For ps6000.py it starts on line 293.

def _lowLevelGetTimebase(self, tb, noSamples, oversample, segmentIndex):
        """Return (timeIntervalSeconds, maxSamples)."""
        maxSamples = c_int32()
        sampleRate = c_float()
        
        print("_lowLevelGetTimebase in ps6000.py parameters for ps6000GetTimebase2(...):")
        print(c_int16(self.handle))
        print(c_uint32(tb))
        print(c_uint32(noSamples))
        print(byref(sampleRate))
        print(c_int16(oversample))
        print(byref(maxSamples))
        print(c_uint32(segmentIndex))

        m = self.lib.ps6000GetTimebase2(c_int16(self.handle), c_uint32(tb),
                                        c_uint32(noSamples), byref(sampleRate),
                                        c_int16(oversample), byref(maxSamples),
                                        c_uint32(segmentIndex))
        print("_lowLevelGetTimebase in ps6000.py m value for checkResult(m):")
        print(m)
        self.checkResult(m)

        return (sampleRate.value / 1.0E9, maxSamples.value)

And for picobase.py it is on line 1137.

    def checkResult(self, errorCode):
        """Check result of function calls, raise exception if not 0."""
        # NOTE: This will break some oscilloscopes that are powered by USB.
        # Some of the newer scopes, can actually be powered by USB and will
        # return a useful value. That should be given back to the user.
        # I guess we can deal with these edge cases in the functions themselves
        if errorCode == 0:
            return

        else:
            ecName = self.errorNumToName(errorCode)
            print("ecName")
            print(ecName)
            ecDesc = self.errorNumToDesc(errorCode)
            print("ecName")
            print(ecName)
            raise IOError('Error calling %s: %s (%s)' % (
                str(inspect.stack()[1][3]), ecName, ecDesc))

And this is the output:

checkResult in picobase.py
_lowLevelGetTimebase in ps6000.py parameters for ps6000GetTimebase2(...):
c_short(1)
c_ulong(0)
c_ulong(312)
<cparam 'P' (0x756b6eb8)>
c_short(0)
<cparam 'P' (0x7661df58)>
c_ulong(0)
_lowLevelGetTimebase in ps6000.py m value for checkResult(m):
14
checkResult in picobase.py
ecName
PICO_INVALID_TIMEBASE
ecDesc
The timebase is not supported or is invalid.
Traceback (most recent call last):
  File "simple.py", line 13, in <module>
    (actualSamplingInterval, nSamples, maxSamples) = ps.setSamplingInterval(sampling_interval, obs_duration)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 376, in setSamplingInterval
    self.timebase, noSamples, oversample, segmentIndex)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/ps6000.py", line 313, in _lowLevelGetTimebase
    self.checkResult(m)
  File "/home/user/.local/lib/python3.7/site-packages/picoscope/picobase.py", line 1155, in checkResult
    str(inspect.stack()[1][3]), ecName, ecDesc))
OSError: Error calling _lowLevelGetTimebase: PICO_INVALID_TIMEBASE (The timebase is not supported or is invalid.)
checkResult in picobase.py

so timebase is being correctly provided a value of 0. You might need to disable cannels to get that "fastest" timebase. I know that their scope shares the bandwidth between probes. So you can run all 4 at a sampling rate of 800 pss, or 1 of them at a sampling rate of 200 ps

Yes. So you want me to add before the ps.SetSamplingInterval something like this?

ps.setChannel(channel='A',enabled=True)
ps.setChannel(channel='B',enabled=False)
ps.setChannel(channel='C',enabled=False)
ps.setChannel(channel='D',enabled=False)

Because that executes without a problem! :)

Yeah, that does not return the error value (i.e. m = 0, so no error)! Thank you!

I will test it with an oscillator running as it is off now and let you know it works as a whole (which it now seems to). Then we can close the issue.

Ok, that works! The other channels need to be disabled prior to going to timebase below 2. Thank you so much!!!

Happy it works. Honestly, their useguide is well written. I would give it a full pass one day:

image