mirror of
https://github.com/jonathanhogg/scopething
synced 2025-07-13 10:52:08 +01:00
Extend README as people seem to be suddenly looking at this code; remove cruft from analysis test script.
This commit is contained in:
55
README.md
55
README.md
@ -8,3 +8,58 @@
|
||||
- Also requires **NumPy** and **SciPy** if you want to do analog range calibration
|
||||
- Having **Pandas** is useful for wrapping capture results for further processing
|
||||
|
||||
## Longer Notes
|
||||
|
||||
### Why have I written this?
|
||||
|
||||
BitScope helpfully provide applications and libraries for talking to their USB
|
||||
capture devices, so one can just use those. I wrote this code because I want
|
||||
to be able to grab the raw data and further process it in various ways. I'm
|
||||
accustomed to working at a Python prompt with various toolkits like SciPy and
|
||||
Matplotlib, so I wanted a simple way to just grab a trace as an array.
|
||||
|
||||
The BitScope library is pretty simple to use, but also requires you to
|
||||
understand a fair amount about how the scope works and make a bunch of decisions
|
||||
about what capture mode and rate to use. I want to just specify a time period,
|
||||
voltage range and a rough number of samples and have all of that worked out for
|
||||
me, same way as I'd use an actual oscilloscope: twiddle the knobs and look at
|
||||
the trace.
|
||||
|
||||
Of course, I could have wrapped the BitScope library in something that would do
|
||||
this, but after reading a bit about how the scope works I was fascinated with
|
||||
understanding it further and so I decided to go back to first principles and
|
||||
start with just talking to it with a serial library. This code thus serves as
|
||||
(sort of) documentation for the VM registers, capture modes and how to use them.
|
||||
It also has the advantage of being pure Python.
|
||||
|
||||
The code prefers the highest capture resolution possible and will do the mapping
|
||||
from high/low/trigger voltages to the mysterious magic numbers that the device
|
||||
needs. It can also do logic and mixed-signal capture.
|
||||
|
||||
In addition to capturing, the code can also generate waveforms at arbitrary
|
||||
frequencies – something that is tricky to do as the device operates at specific
|
||||
frequencies and so one has to massage the width of the waveform buffer to get a
|
||||
frequency outside of these. It can also control the clock generator.
|
||||
|
||||
I've gone for an underlying async design as it makes it easy to integrate the
|
||||
code into UI programs or network servers – both of which interest me as the end
|
||||
purpose for this code. However, for shell use there are synchronous wrapper
|
||||
functions. Of particular note is that the synchronous wrapper understands
|
||||
keyboard interrupt and will cancel a capture returning the trace around the
|
||||
cancel point. This is useful if your trigger doesn't fire and you want to
|
||||
understand why.
|
||||
|
||||
### Where's the documentation, mate?
|
||||
|
||||
Yeah, yeah. I know.
|
||||
|
||||
### Also, I see no unit tests...
|
||||
|
||||
It's pretty hard to do unit tests for a physical device. That's my excuse and
|
||||
I'm sticking to it.
|
||||
|
||||
### Long lines and ignoring E221, eh?
|
||||
|
||||
"A foolish consistency is the hobgoblin of little minds"
|
||||
|
||||
Also, I haven't used an 80 character wide terminal in this century.
|
||||
|
19
test.py
19
test.py
@ -1,26 +1,12 @@
|
||||
|
||||
import numpy as np
|
||||
from pylab import figure, plot, show
|
||||
|
||||
from analysis import annotate_series
|
||||
from scope import await_, capture, main
|
||||
from utils import DotDict
|
||||
|
||||
|
||||
await_(main())
|
||||
|
||||
# o = 400
|
||||
# m = 5
|
||||
# n = o * m
|
||||
# samples = square_wave(o)
|
||||
# samples = np.hstack([samples] * m) * 2
|
||||
# samples = np.hstack([samples[100:], samples[:100]])
|
||||
# samples += np.random.normal(size=n) * 0.1
|
||||
# samples += np.linspace(4.5, 5.5, n)
|
||||
# series = DotDict(samples=samples, sample_rate=1000000)
|
||||
|
||||
data = capture(['A'], period=20e-3, nsamples=2000)
|
||||
series = data.A
|
||||
series = capture(['A'], period=20e-3, nsamples=2000).A
|
||||
|
||||
figure(1)
|
||||
plot(series.timestamps, series.samples)
|
||||
@ -35,6 +21,7 @@ if annotate_series(series):
|
||||
print(f"Found {waveform.frequency:.0f}Hz {waveform.shape} wave, "
|
||||
f"with amplitude ±{waveform.amplitude:.2f}V and offset {waveform.offset:.2f}V")
|
||||
|
||||
plot(waveform.timestamps + waveform.capture_start - series.capture_start, waveform.samples * waveform.amplitude + waveform.offset)
|
||||
plot(waveform.timestamps + waveform.capture_start - series.capture_start,
|
||||
waveform.samples * waveform.amplitude + waveform.offset)
|
||||
|
||||
show()
|
||||
|
Reference in New Issue
Block a user