前回までで、OWON の USBオシロスコープ VDS3104(LAN無しモデル) をpythonで制御することができるようになりました。私にとって、VDS3104の一番の不満点は波形のズーム機能がまともに使えないことです。そこで、VDS3104から保存したバイナリーデータを解析して、matplotlibで表示するようにしてみました。
#データ解析
何パターンかのデータをバイナリーエディターで眺めてみて、データフォーマットが分かってきましたので、下記のデータ解析クラスを作りました。コード中、d0~d8、およびstruct.unpackのパデング(x)にした部分のデータが今のところ謎なのですが、とりあえず、表示に必要な項目はわかりました。
vdsDat.py
import struct
TBScales = [float(str(a)+'e'+str(b)) for b in range(-9,3) for a in [1,2,5]][1:34]
VScales = [float(str(a)+'e'+str(b)) for b in range(-3,1) for a in [1,2,5]][1:12]
class vdsDat:
sizHed = 32 #ヘッダーのサイズ
sizChI = 67 #チャネル情報(1ch分)のサイズ
sizTbI = 27 #タイムベース情報のサイズ
class chInfo:
def __init__(self, src):
self.dat = src
name, self.sizInfo, self.inv, d0, self.samplesPerScreen, d1, d2, d3, d4, \
self.sizDat, d6, self.vOffset, self.scaleCode, self.probeRateCode, d7, d8, self.ofsDat \
= struct.unpack('>3s16i', src)
self.name = name.decode()
self.probeRate = 10**self.probeRateCode
self.scale = VScales[self.scaleCode] * self.probeRate
self.VPP = self.scale / 25
def __init__(self, src):
self.header = src[0:self.sizHed]
model, self.sizFile, self.sizDat = struct.unpack('>10s13x1i1x1i', self.header)
self.model = model.decode
pt = self.sizHed + self.sizDat #データポインター
self.tbInfo = src[pt:pt+self.sizTbI]
self.tbScaleCode, self.tbOffset, self.sizChIs = struct.unpack('>17x1b1i3x1H', self.tbInfo)
self.tbScale = TBScales[self.tbScaleCode]
self.numCh = self.sizChIs // self.sizChI
pt += self.sizTbI
self.chI = [self.chInfo(src[p:p+self.sizChI]) for p in range(pt, pt+self.sizChIs, self.sizChI)]
self.sizChD = self.sizDat // self.numCh
pt = self.sizHed
f = str(self.sizChD) + 'b'
self.chDat = [struct.unpack(f, src[p:p+self.sizChD]) for p in range(pt, pt + self.sizDat, self.sizChD)]
#matplotlibで表示
vds_datPlot.py
import sys
import matplotlib.pyplot as plt
import numpy as np
from vdsDat import *
pltColor = {
'CH1' : 'red',
'CH2' : 'orange',
'CH3' : 'blue',
'CH4' : 'purple'
}
if __name__ == '__main__':
srcFile = sys.argv[1]
with open(srcFile, 'rb') as f:
srcDat = f.read()
dat0 = vdsDat(srcDat)
unitTime = 20 * dat0.tbScale / dat0.chI[0].samplesPerScreen
xmin = unitTime * (dat0.chI[0].samplesPerScreen * dat0.tbOffset / 1000 - dat0.chI[0].sizDat / 2)
xmax = unitTime * dat0.chI[0].sizDat + xmin
xax = np.arange(xmin, xmax, unitTime)
fig, ax = plt.subplots(2, 1, sharex = True)
for chi, chd in zip(dat0.chI, dat0.chDat):
name = chi.name
ax[0].plot(xax, chd, label=name, color=pltColor[name])
dat = (np.array(chd) - chi.vOffset) * chi.VPP
ax[1].plot(xax, dat, label=name, color=pltColor[name])
ax[0].legend(loc='upper right')
ax[0].set_xlim(xmin, xmax)
ax[0].set_ylim(-128, 127)
plt.show()