diff --git a/README.md b/README.md index 29e1e5d..26b3c92 100644 --- a/README.md +++ b/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. diff --git a/test.py b/test.py index 6f7e5bc..8a2ccf3 100644 --- a/test.py +++ b/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()