colinoflynn / pico-python Goto Github PK
View Code? Open in Web Editor NEWPicoScope Python Interface
License: Other
PicoScope Python Interface
License: Other
Was there any reason for your code to be written this way
if sampleTimeS < 6.4E-9:
if sampleTimeS < 200E-12:
st = 0
st = math.floor(1/math.log(2, (sampleTimeS * 5E9)))
Did you have the parameters flipped in the math.log function?
Personally, I think this is easier to read:
if sampleTimeS < 6.4E-9:
st = math.floor(math.log(sampleTimeS*5E9, 2))
st = max(st, 0)
mainly because it more naturally follows their timebase formula.
Can we have absolutely correct integer math for this function?
I'm thinking
pretrig_samples = int(round(int(nSamples * pretrig))
post_trip = nSamples - pretig_samples
This is just a suggestion for somebody to fix. I'm making this an issue for a later time
I've added an option here - the user can request an exception on overflow. It shouldn't be default, as if you get an overflow exception during interactive use it's a huge hassle, and you might get a string of overflow exceptions. Will commit in a second..
Wow, sorry.
I think I may have typed the wrong in vim, and now i changed all the line endings in picoscope.py
It looks like a totally new file. Can you please put autocrlf in your gitconfig file.
Thanks.
Mark
_lowLevelSetSigGenBuiltInSimple() was missing from ps3000a
I added that to my local libs and would like to contribute them.
Whats the procedure for doing that?
-Remove the 'other stuff' files colinoflynn was stashing
-Make an examples directory perhaps?
Some notes on things which will be fixed/improved:
-Pick a license (FreeBSD perhaps?)
-Add @hmaarrfk to copyright text
-Remove the 'other stuff' files I was stashing
-Make an examples directory perhaps?
I don't have a scope with me right now (holidays) so won't be commit anything w/o one, since I can't check if I've broken something!
@hmaarrfk: If you see big changes are needed somewhere (e.g. you think there is a better way to do something) let me know, I'm very open to large changes! I don't claim to have done everything correctly ;-)
I've got a 5442B that I'm trying to get going under linux. I've installed the drivers and picoscope and I can view waveforms which is great.
So now I'm trying to get to the automated data collection part which is where pico-python comes in. I got it installed as devel and then copied & pasted the discover_devices.py file and changed everything from ps6000 to ps5000a since I have a 5000 series scope.
sandford@MikeLinux ~/software $ python discover_devices.py
Traceback (most recent call last):
File "discover_devices.py", line 14, in <module>
allSerialNumbers = ps.enumerateUnits()
File "/home/sandford/software/pico-python/picoscope/picobase.py", line 707, in enumerateUnits
return self._lowLevelEnumerateUnits()
AttributeError: 'PS5000a' object has no attribute '_lowLevelEnumerateUnits'
sandford@MikeLinux ~/software $
I am not really sure where to go from here. I am running Picoscope 6 Beta which I have installed from the Picoscope dpkg repo as described on their website: http://www.picotech.com/linux.html
Any help would be greatly appreciated!
I've started using Python (x,y) because I was able to get it to work.
I don't have much experience with programming language other than Matlab on Windows.
Do you recommend a specific python IDE?
Taken from the ps6000pg manual section 3.6
Note: This feature is provided for backward-compatibility only. The same effect can be
obtained more efficiently with the PicoScope 6000 Series using the hardware
averaging feature (see Downsampling modes).
I think this will fix the issue with the ps5000a not having a oversampling feature.
Hi,
I'm interested in your package and I wonder if it is possible to ask a Picoscope to dump data into binary formats such as np/npz, hdf5, parquet, etc.. ?
Added support for external trigger in 762ab4e. Created this issue to follow it, as I still need to fix negative trigger thresholds.
I've started adding support for the 5000 series device. There is subtle differences between the 6000 vs 5000, but so far the idea of subclassing seems to be working well. Just a few notes:
That's all I can think of right now that's important...
The overflow variable right now is passed as a bit-mask back from the PicoScope. I originally thought it would be best to cast to bool as was just thinking it was either 'yes' or 'no'... I admit I just pushed that commit without fully thinking.
But that means you don't know where the overflow occurred. Thoughts? I wasn't thinking about that when committing so figured it wouldn't break anything, but I may have...
I am using a ps5242a and since updating my repository with the branch master I get an error upon initialising the picoscope. The line:
self.model = super(PS5000a, self).getUnitInfo('VarianInfo')
brings up the error
TypeError: an integer is required (got type NoneType)
when executing
m = self.lib.ps5000aGetUnitInfo(c_int16(self.handle), byref(s), c_int16(len(s)), byref(requiredSize), c_enum(info))
For the moment I have commented out self.model part and by default just use the statements in the else section.
I think this would be an easy ish enhancement. Don't know how valuable it would be.
I don't think we should worry about any more enhancements to this function. The user can always look at the python source code to write his own functions should he need better performance.
So there is definitly a pointer issue somewhere in the code.
I have't much spend time debugging it.
My environment is Windows 7 with Python(x,y).
I have a feeling set databuffer isn't setting subsequent buffers correctly and therefore it is writing at the old location of the buffer which may or may not be deleted by the python garbage collector.
So I ran ps6000_demo.py
in Spyder with the run file button
and it returned
Exception TypeError: "'NoneType' object is not callable" in <bound method PS6000.__del__ of <ps6000.PS6000 object at 0x07279E90>> ignored
at the end...
Should the picoscope automatically open when we create a new instance of the class?
eg
what we have.
from ps6000 import PS6000
ps = PS6000()
ps.open(sn)
vs
from ps6000 import PS6000
ps = PS6000(sn)
for the devices that I have matlab code written, I generally do the later.
The python community seems to love Pep8 and Pep257.
They seem to like to adhere to the rules almost religiously.
Should we follow them?
Many IDEs/text Editors have linters.
Some things to think about
With my PS6403(B???) the voltage scaling given in the programming manual seems to be wrong.
I reported the bug here:
http://www.picotech.com/support/topic13217.html
but they seem reluctant to actually replicate it.
Has anyone got a way to avoid the error when the picoscope is powered from USB rather than from the power supply?
Just a placeholder. I've got a 2204A which I can use to test code with those models. Will commit actual code later.
Firstly- my thanks for creating the easiest to use and access (from the perspective of a python novice) python library for the picoscope. Been able to get up and running in a matter of hours which is big plus over the official one :)
I've been playing around with the AWG functionality - and a bit confused about why the waveforms were coming out radically the wrong scale and offset. Upon some digging it appears that the AWG scaling is hardcoded in ps3000a to
AWGMaxVal = 0x0FFF
AWGMinVal = 0x0000
For the 3403D, which happens to be the one I've got I've found that this needs to be:
AWGMaxVal = 32767
AWGMinVal = -32768
I guess this varies on a device by device basis. The official API documentation points you to 'ps3000aSigGenArbitraryMinMaxValues' but from my limited searching it looks like this isn't captured yet. Is that correct?
Cheers
Sam
##edited to correct the required 3403D values.
ps3000a.py implements _lowLevelGetValuesBulk with the wrong integer types, causing overflows and partially empty traces.
Where did we get the value for MAX_VALUE?
The datasheet at page 7 say taht
PS6000_MIN_VALUE is -32512 and not -32767
similarly for PS6000_MAX_VALUE. 32767 is 2^15 -1 (16 bit number max value). Did we just assume that?
Currently our __del__
calls close,
Is this going to cause a problem if the picoscope object get copied then one of the copies get cleaned up by memory?
Is there a way to force python to only copy by reference?
It seems that the PS5000a series has a PS5000A_LOST_DATA defined.
They don't explain what the defined value means, but it might be interesting to raise an exception on it.
Python 3 brings in some pretty cool compatibility things.
I would like to propose that we adopt some Python 3 styles:
from future import division
We are dealing with integer numbers allot and it can cause us problems if we aren't careful
This makes 1/2 = 0.5 and 1//2 = 0
The second thing I would like to propose is not to not use the
print "Hello world"
in favour of
print("Hello world")
the later being a function call. Python 3 actually drops the former synthax.
I think there might be a few differences in how we declare classes as well, but I don't really want to deal with that now. These two changes are pretty straightforward and I think they will help us.
You were using CaseInsensitiveDict for some of the dictionaries.
I don't think it is a bad idea to use it, but it wasn't working when I tried to use it, your samples didn't seem to test it either, so I just commented it out.
Do you think we should use it?
The Picoscope's basic triggering feature is not very good at triggering on ramps. For example, if you give it a triangular ramp it will like to trigger on the quantization noise. Therefore, it will trigger on either what you consider the up edge or the down edge.
It would be interesting if we could figure out how to a add hysteresis to the trigger to avoid this problem.
So technically our python calls should be agnostic as to weather or not linux is used.
I added the appropriate checking when the library is loaded. (at least in PS6000)
Unfortuantely, it seems that their Linux library is pretty buggy. I don't feel like ironing out the bugs for them. So I'll just leave this as an enhancement.
My lab computers all run windows anyway. Linux is just a far away pipedream.
We should probably add this thing to pip - any issues anyone sees?
FreeBSD?
Hi, version 0.4 on PyPI predates the PS2000A support added in the git version recently. Would you consider updating it? Thanks!
Hi all,
The ping branch needs testing.
I just want to make sure there are no syntax errors.
Maybe just open a ps5000a or ps3000a scope and let me know if it complains.
If you feel inclined, you can try to ping them.
Thanks,
I'll merge this in a few weeks and see if anybody complains.
I think we should go through some of the PS6000con.c code, especially the get_info
function and apply some of the defaults to our program.
Ignoring some of the documentation errors, their code is rather good at following the programmer guide and setting the correct defaults.
One of the mistakes we are doing, is assuming some the channels are disabled by default.
The picoscope (6000 only?) enables all channels by default. In our implementation we set their state as being undefined.
It seems that the signal generator is in some weird state during bootup.
I've reported the bug here
http://www.picotech.com/support/topic12969.html
this appears to be an issue with both
ps6000SetSigGenBuiltIn and ps6000SetSigGenArbitrary
at boot up.
Once it stabilizes (after a few minutes) you seem to be able to close and open the picoscope a number of times and it doesn't seem to show up.
This may have a simple solution, but we can't figure out how to output the acquired data in histogram form, and we're a little confused about settings.
We'd like to run a PS6407 in rapid block mode with the following settings, using channel A for data and channel C for thresholding:
Channel A Settings and Channel C settings:
Channel Status: Enabled
Range: 100mV
Coupling: DC 50 Ohm
Analogue Offset: 0
Bandwidth: FullPicoscope Settings:
Pretrigger Samples: 0
Posttrigger Samples: 20
Timebase: 1
Oversample: 1
Number of Captures: 100
Four Channel Device: False
Below is our test script and output.
import picoscope
import matplotlib.pyplot as plt
import numpy as np
import time
from ctypes import *
picoscope = reload(picoscope)
from picoscope import ps6000
ps6000 = reload(ps6000)
SERIAL_NUM = 'AR566/012\x00'
ps = ps6000.PS6000(SERIAL_NUM)
#trigger settings
trigger_channel="A"
threshold_V=0.01
trigger_type='Rising'
trigger_delay=0
ps.setSimpleTrigger(trigger_channel, threshold_V, direction=trigger_type, delay=trigger_delay)
#channel settings
ps.setChannel(channel="A", coupling="DC50", VRange=100E-3, VOffset=0.0, enabled=True, BWLimited=False)
ps.setChannel(channel="C", coupling="DC50", VRange=100E-3, VOffset=0.0, enabled=True, BWLimited=False)
c = 3e8
#picoscope settings
n_captures = 1 #int(600 * 1.4)
sample_interval = 5 / c
sample_duration = 1e3 * 2 / c
ps.noSamples=20
ps.sampleFreq=1e8
ps.timebase=1
ps.oversample=1
ps.setSamplingInterval(sample_interval, sample_duration)
#ps.setSamplingFrequency(ps.sampleFreq, ps.noSamples, ps.oversample, segmentIndex=0)
samples_per_segment = ps.memorySegments(n_captures)
ps.setNoOfCaptures(n_captures)
data = np.zeros((n_captures, samples_per_segment), dtype=np.int16)
t1 = time.time()
ps.runBlock()
ps.waitReady()
t2 = time.time()
print "Time to get sweep: ", str(t2 - t1)
ps.getDataRawBulk(channel="C",data=data)
#wait until ready
while ps.isReady()==False:
pass
for i in range(n_captures):
ps._lowLevelSetDataBuffer(ps.CHANNELS["A"],
data[i, :], 0, i)
ps._lowLevelSetDataBuffer(ps.CHANNELS["C"],
data[i, :], 0, i)
t2 = time.time()
nsamples = c_int32(ps.noSamples)
from_segment_index = 0
to_segment_index = n_captures - 1
downsample_ratio = 0
downsample_mode = 0
overflow = np.zeros(n_captures, dtype=np.int16)
overflow_ptr = overflow.ctypes.data_as(POINTER(c_int16))
m = ps.lib.ps6000GetValuesBulk(c_int16(ps.handle),
byref(nsamples),
c_int16(from_segment_index),
c_int16(to_segment_index),
c_int32(downsample_ratio),
c_int16(downsample_mode),
overflow_ptr)
print m
ps.checkResult(m)
t3 = time.time()
print "Time to read data: ", str(t3 - t2)
try:
plt.imshow(data[:, 0:ps.noSamples], aspect='auto', interpolation='none',
cmap=plt.cm.hot)
plt.colorbar()
plt.show()
except:
print 'Nope'
ps.close()
ps.close()
I added stub functions for many things in the ps6000 programmer guide.
It would be nice if we could support Bulk or Streaming options.
Bulk handling basically requires us to be very careful with memory management.
It only makes sense for Bulk to ask the user for the numpy array to use.
For this to be possible, we need to check a few of the numpy array flags, like CONTIGUOUS.
Use case where this is not true:
User creates an array
User slices array
User passes sliced array hoping to store information in a sliced fashion
We don't have to check this in our current functions because we always create an ``empy` array
I might actually have to use this soon so it might be implemented in the near future. But I just wanted to document the possible bug.
The order of variables passed to _lowLevelSetSimpleTrigger for ps6000 appears wrong - timeout_ms is called 'delay', whereas the timeout_ms becomes 'auto'.
The way I envision using the functions is that timeout_ms is the time to wait for a trigger, after which it auto-triggers. the 'delay' function is number of samples to wait after trigger.
Will fix this in a second & close.
I recently stumbled on this project and decided to try to start using it, but, having never programmed these scopes directly I'm not entirely sure how to start fixing bugs like this one:
Time to get sweep: 0.246327161789
Traceback (most recent call last):
File "test_ps3000a.py2", line 51, in <module>
ps.getDataRawBulk(data=data)
File "/usr/lib/python2.7/site-packages/picoscope/picobase.py", line 506, in getDataRawBulk
self._lowLevelSetDataBufferBulk(channel,
AttributeError: 'PS3000a' object has no attribute '_lowLevelSetDataBufferBulk'
Looking through the repo only two modules implement this function. I've found no corresponding ps3000aSetDataBufferBulk in the ps3000a programmer's manual. What am I missing here? Did this test simply never run in the first place?
The last comment in #44 was
I do agree that implementing the change power source function by default isn't pretty and could potentially hide other bugs. Would it possibly make sense to add a parameter to _lowLevelOpenUnit that by default is set to use DC power but could be set by a user for USB power. Then an if function after ps5000aOpenUnit can change the power source if the parameter is set to USB?
I want to continue the discussion here because the original bug was technically fixed. This is a new one.
PicoTech decided to calculate delta phase in a very strange manner
See bug report:
HI i am quite new using picoscope with python... i cant find any streaming function.. As am trying to get a continous stream of data (some hours) from a channel at 16bit resolution and 5Ms/s i wold like not to have it in block mode but to be able to analize in real time. Has anyone something useful for it?
thanks!!
Hi,
If somebody could test the BWLimit function for the PS5000a that would be great.
It is in the branch ps5000aBWLimit
I think running https://github.com/colinoflynn/pico-python/blob/master/examples/freqmeasure.py should be enough. I just want to make sure that the setChannel function isn't broken.
Thanks,
I'll pull in a few weeks if nobody has done this and see if anybody complains
The trigger level setting doesn't take into account channel probe attenuation, should it? e.g. calling the API with setting of 3V on 10:1 probe channel = 0.3V. The only possible problem is if you change the probe attenuation the trigger level wouldn't be automatically updated, but could just document that.
Should also validate trigger level is within allowed range of given channel, ps6000SetSimpleTrigger doesn't validate this it seems.
Didn't want to change this without checking if it will break anything for @hmaarrfk first though (e.g. do you assume trigger level is 'raw' at scope?).
We should probably support this correctly:
typedef enum
enPS6000BandwidthLimiter
{
PS6000_BW_FULL,
PS6000_BW_20MHZ,
PS6000_BW_25MHZ,
} PS6000_BANDWIDTH_LIMITER;
we can change the code from taking true/false to taking strings like most other options do.
Olivier Doaré [email protected]
Jan 30 (1 day ago)
to coflynn, me
Hello,
I am planning to buy a Picoscope 4262 and would use it with Python under Linux with the help of the extensions you have developed. You don't mention this scope, but on the documentation in github, there is a part about the 4000 series. Is there any chance for it to work ?
There is also the PicoScope 5242A, which seems similar in terms of features, should I buy this one ? (I know this is a question I should ask to Picotech, hence I would understand if you ignore this one...)
Thank you for developing and sharing your work,
best regards,
Olivier Doaré
Mark Harfouche [email protected]
Jan 30 (1 day ago)
to Olivier, coflynn
Hi,
We do not have an extensive list of scopes that work with our code, rather just as people report it to us.
If you see a scope that uses the same programming manual as yours, it means your scope is almost sure compatible with our code.
Have you ever programmed in C?
If so, it should be rather straightforward to adapt the code to any oscilloscope you buy.
That said, I think it is better if you open an issue on GitHub, that way others can chime in as well.
Cheers,
Mark
Colin O'Flynn
9:43 AM (23 hours ago)
to Olivier, me
Hi Olivier,
I haven’t used the 4000 series, but I think someone else added support for this scope. You’d have to check back in the GIT log to see where it came from.
As Mark mentioned the critical part is just if it uses the same programming manual, it should be OK. It’s not a major issue to add support, but it may require a small amount of effort on your side.
I’ve used the 5000-series and was very happy with it… the flexible resolution is nice rather than committing to a higher resolution but at a lower sampling rate (as in the 4262). The 4262 seems designed for some sort of specific applications (the 16-bit resolution, but very low 5 MHz bandwidth), so it might be you specifically need that?
Regards,
-Colin O’Flynn
Hello,
Thanks a lot for your kind and useful responses.
5MHz is largely enough for me as my main intersest are vibration and (audible) acoustics. 16 bits are a minimum requirement, but I understand that it is possible to oversample to increanse bit depth with both cards. So in fact both options are OK for my application.
For the effort I would have to furnish to implement support for the 4262, I am unfortunately not very experienced in C programming. I would be glad to learrn, but that is a matter of time, and I unfortunately don't have a lot.
Thank you again for your responses !
Best regards,
Olivier
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.