Modern oscilloscopes can be used for much more than just displaying a waveform. With the some programming, you can use it as a logic analyzer, for jitter measurements or run use it as a spectrum analyzer. In a later article I will show how to do jitter measurements with a digital storage oscilloscope (DSO). You can argue that there are instruments that are more specialized for these use cases than an oscilloscope. You’re right. However if you don’t need the all the features and the superior performance of these instruments (like a logic analyzer or a spectrum analyzer), a DSO might be a cheap alternative. For some specific use cases it might be even superior.
Even relatively cheap scopes like a Rigol DS2072 can already sample data with rates of 2GSamples/s which means one sample every 0.5 nanoseconds. The resolution is usually limited to 8 bit, but the first scopes are already available with 12bit resolution. For many use cases, even 8 bit are more than enough.
The basic approach is to let the scope sample into its internal memory with the sample rate you need, then load the data to a PC and do all the post-processing on the PC. My Rigol scope has an internal memory of 56MSamples – that’s a lot.
The example code at the end of this picture shows how to do this with a Rigol DS2xx2 scope. The standard version of this scope has a memory of only 14MSamples. You can upgrade the memory with a license key. However, for most tasks even the 14MSamples are enough.
There are some things you have to do to get the data from the scope and use the full 56MSamples memory:
- Timing is important
I had quite some problems getting the program to work. In most cases I was sending new command to fast. If the scope still processes the last command, it ignores new commands.
In worst case it is not even responding anymore.
As a rule of thumb I use 100ms delay after every command and one second after some commands like “AUTO”, “RUN” or “STOP”. This has been found by trial-and-error. - Activate only one channel if you don’t need the second
If you use both channels, the sample memory per channel is only the half. - Stop the recording
With live display only 1400 samples are available.
One characteristic I don’t like with this specific Rigol oscilloscope: data transfers over the network are quite slow. I was able to transfer 110kSamples/s over TCP/IP. That means reading out the full memory of the scope takes over 8 minutes! That’s not really fast. If you don’t need all the samples, reduce the number of samples with the “:WAVeform:POINts” command.
Now some example code how to get the data. You will see, that some parts are missing. It should just give you an idea how to do it by yourself. I have programmed my own measurement toolkit. However the code still needs some cleanup, therefore I won’t publish it now. I plan to publish it later. Note that this is not a high-priority task, therefore I can’t say when it will be ready.
def readdata(instrument): global samples line=str(instrument.connection.read(12)) if not line.startswith("#9"): raise Exception("unknown data format: {}.".format(line)) samplecount=int(line[2:11]) data=instrument.connection.read(samplecount) for d in data: samples.append(ord(d)) lf=instrument.connection.readline() if (len(lf))>2: raise Exception("additional data after samples: {}".format(lf)) def read_from_scope(): global samples global periods samples=[] ins=get_instrument("DS2202") print ins.identify() ins.send_command(":AUT") time.sleep(2) ins.send_command(":CHAN2:DISP 0") ins.mem_depth(points) ins.set_aquisition_type("HRES") time.sleep(2) ins.send_command(":CHANNEL1:BWLimit OFF") ins.send_command(":CHANNEL1:COUPLING DC") ins.send_command(":CHANNEL1:DISPLAY ON") ins.send_command(":RUN") time.sleep(1) ins.send_command(":ACQuire:MDEP {}".format(points)) ins.send_command(":STOP") time.sleep(1) ins.send_command(":WAVeform:MODE RAW") ins.send_command(":WAVeform:POINts {}".format(points)) ins.send_command(":WAVeform:FORMAT BYTE") ins.send_command(":WAVeform:SOURCE CHAN1") ins.send_command(":WAVeform:RESet") time.sleep(1) ins.send_command(":WAVeform:BEGIN") time.sleep(1) starttime=datetime.datetime.now() while True: stat=ins.send_command(":WAVeform:STATUS?").lower() if stat.startswith("idle"): ins.send_command(":WAVeform:DATA?",auto_read=False) readdata(ins) break elif stat.startswith("read,"): count=int(stat[5:]) if count==0: break ins.send_command(":WAVeform:DATA?",auto_read=False) readdata(ins) else: print "unexpected return string" sys.exit(1) endtime=datetime.datetime.now() sec=(endtime-starttime).total_seconds() slen=len(samples) print("Retrieved {} samples in {} seconds ({}kSamples/s)".format(slen,sec,slen/sec/1000))
Hi,
is there any way to download the raw data from DS2072 to the USB without loading it in its internal memory? I want to stream live data directly to the computer and use the oscilloscope just for its ADC.
Hi Daniel, I’ve just got an entry-level Rigol 4-channel scope, and I’ve had some fun grabbing I2S signals via a USB stick, bringing them into a PC and decoding them back into audio using a little PHP script. I’ve shared my findings and code here: http://tuck1s.blogspot.co.uk/2015/08/rigol-ds1054z-digital-storage-scope.html
Hello Daniel, I was thinking about your problem with transfer speed of the Rigol oscilloscope point memory. Maybe it makes sense to translate your code into C and run it under Windows or Linux to get better bandwith. Have a look at the following tutorial how to do that from C level: http://linkbone.com/rigol-oscilloscope-remote-control-visa-scpi/