#!/usr/bin/env python3
'''runs shots with one continuous AWG as Master and multiple UUTs using MGTDRAM
assuming a system with 1 x AWG, 2+ x AI, run shots and offload the data
'''
import sys
import subprocess
import time
import acq400_hapi
import argparse
import os
import numpy as np
import re
save_mat_ok = True
try:
import scipy.io
except:
print("sorry, save_mat option not supported")
save_mat_ok = False
from functools import wraps
[docs]def timing(f):
@wraps(f)
def wrap(*args, **kw):
ts = time.time()
result = f(*args, **kw)
te = time.time()
print('TIMING:func:%r took: %2.2f sec' % (f.__name__, te-ts))
return result
return wrap
[docs]def get_parser():
parser = argparse.ArgumentParser(description='runs shots with one continuous AWG')
parser.add_argument('--aiseconds', type=int, default=10, help="number of seconds to run AI capture")
parser.add_argument('--shots', type=int, default=1, help="number of shots to run")
parser.add_argument('--plot', type=int, default=0,
help="0: no plot, OR of 1: plot raw, 2:plot gated, 4 plot first burst, 8 plot delta.")
parser.add_argument('--verbose', type=int, default=0)
parser.add_argument('--mu', help="master uut, for trigger")
parser.add_argument('--nbufs', default=800, type=int, help="number of 4MB buffers to capture")
parser.add_argument('--shot_seconds', default=None, type=int, help="specify shot duration in seconds. Overwrites --nbufs")
parser.add_argument('--awg_restart', default=1, type=int, help="force awg restart for constant phase")
parser.add_argument('--save_egu', default=0, type=int, help="save data in engineering units")
parser.add_argument('--save_mat', default=0, type=int, help="save data in engineering units as .mat file [libraries permitting]")
parser.add_argument('uut_names', nargs='+', help="uut names")
return parser
procs = []
[docs]def set_shot_seconds(args):
ssb = int(args.uuts[0].s0.ssb)
fs = int(acq400_hapi.freq(args.uuts[0].s0.SIG_CLK_S1_FREQ))
mbps = fs*ssb/1000000
nbufs = int(mbps*args.shot_seconds//4)
nbufs += 16
if nbufs >= 2000:
nbufs = 2000
print("fs:{} ssb:{} MBPS:{} nbufs:{}".format(ssb, fs, mbps, nbufs))
args.nbufs = nbufs
[docs]@timing
def run_shot(args, uut_names, shot, trigger):
print("\nrun_shot {}\n".format(shot))
if args.awg_restart:
restart_awg(args)
procs.clear()
for uut in uut_names:
f = open("{}/{:04d}.log".format(uut, shot), 'w')
p = subprocess.Popen([ sys.executable, './user_apps/acq2106/mgtdramshot.py',
'--captureblocks', str(args.nbufs), '--offloadblocks', str(args.nbufs), uut ], stdout=f)
procs.append((uut, p, f))
print("spawned {}".format(uut))
trigger(args)
capture_monitor(args)
offload_monitor(args)
for uut, p, f in procs:
p.wait()
print("reaped {}".format(uut))
f.close()
if args.save_egu:
save_egu(args)
[docs]@timing
def restart_awg(args):
if not args.mu:
print("ERROR: master unit not defined")
sys.exit(1)
playloop_length = int(args.mu.s1.playloop_length.split(' ')[0])
if playloop_length == 0:
print("WARNING: AWG not setup")
else:
args.mu.s1.AWG_MODE_ABO = '1'
time.sleep(1)
while acq400_hapi.intpv(args.mu.s1.AWG_MODE_ABO) == 1:
time.sleep(0.2)
args.mu.s1.playloop_length = '0'
time.sleep(0.1)
args.mu.s1.playloop_length = '{} 0'.format(playloop_length)
[docs]@timing
def trigger(args):
for u in args.uuts:
armed = False
while not armed:
cstate = u.s0.cstate.split(' ')[0]
if cstate == '1':
armed = True
print("{} ARMED".format(u.uut))
elif cstate == '0':
time.sleep(0.3)
else:
print("{} ERROR BAD STATE {}".format(u.uut, cstate))
sys.exit(1)
if args.mu:
print("{} trigger".format(args.mu.uut))
args.mu.s0.soft_trigger = '1'
else:
print("trigger")
[docs]@timing
def offload_monitor(args):
idle = np.array([0] * len(args.uuts))
runs = 0
print("Offload Monitor")
print("{:>3} {:8} {}".format('s', 'uut', 'pull buffers'))
while True:
time.sleep(2)
runs += 2
print("{:3d}:".format(runs), end='')
for ix, uut in enumerate(args.uuts):
npull = acq400_hapi.intpv(uut.cA.SIG_MGT_PULL_BUFS_COUNT)
idle[ix] = 1 if npull > (args.nbufs-64) else 0
print("{:11} {:3d}".format(uut.uut, npull), end=', ' if ix < len(args.uuts)-1 else '\n')
if np.all(idle) == 1:
break
[docs]@timing
def capture_monitor(args):
idle = np.array([0] * len(args.uuts))
runs = 0
print("Capture Monitor")
print("{:>3}:{:11} {} {:8}".format('s', 'uut', 'S', 'samples s:seconds, S:state'))
while True:
time.sleep(1)
runs += 1
print("{:3d}:".format(runs), end='')
for ix, uut in enumerate(args.uuts):
cs = uut.s0.cstate.split(' ')
idle[ix] = int(cs[0])
print("{:11} {:1} {:8d}".format(uut.uut, cs[0], int(cs[3])), end=', ' if ix < len(args.uuts)-1 else '\n')
if np.all(idle) == 0:
break
[docs]def save_egu1(uut, shot, rawfile, save_mat):
nchan = int(uut.s0.NCHAN)
raw = np.fromfile(rawfile, np.int16).reshape(-1, nchan)
volts = np.zeros(len(raw)*nchan).reshape(-1, nchan)
for ch in range(1, nchan+1):
volts[:,ch-1] = uut.chan2volts(ch, raw[:,ch-1])
npfile = re.sub(r'\.dat', r'.volts', rawfile)
with open(npfile, "wb") as vp:
volts.astype(np.dtype('f4')).tofile(vp)
if save_mat and save_mat_ok:
f_root = re.sub(r'\.dat', r'', rawfile)
print("Saving matfile in blocks of 16ch")
for block in range(0,nchan,16):
matfile = "{}_{:03d}-{:03d}.mat".format(f_root, block+1, block+16)
scipy.io.savemat(matfile, { '{}_{:03d}v'.format(uut.uut, block): volts[:,block:block+16] })
[docs]@timing
def save_egu(args):
for uut in args.uuts:
shot = int(uut.s1.shot)
save_egu1(uut, shot, "{}/{:04d}.dat".format(uut.uut, shot), args.save_mat)
[docs]def run_main(args):
args.uuts = [ acq400_hapi.factory(name) for name in args.uut_names]
for name in args.uut_names:
os.makedirs("{}".format(name), exist_ok=True)
if args.mu:
args.mu = acq400_hapi.factory(args.mu)
if args.shot_seconds:
set_shot_seconds(args)
if args.save_mat > 0 and args.save_egu == 0:
args.save_egu = 1
for u in args.uuts:
u.s1.shot = 0
if args.mu:
args.mu.s1.shot = 0
for shot in range(1, args.shots+1):
run_shot(args, args.uut_names, shot, trigger)
if __name__ == '__main__':
run_main(get_parser().parse_args())