468 lines
19 KiB
Python
468 lines
19 KiB
Python
#!/usr/bin/env python
|
|
# coding: utf-8
|
|
|
|
# In[17]:
|
|
|
|
|
|
import numpy as np
|
|
import numbers
|
|
import math
|
|
from scipy import signal as sig
|
|
import scipy.fftpack
|
|
import random
|
|
import struct
|
|
import random
|
|
import ipywidgets
|
|
import itertools
|
|
import datetime
|
|
import multiprocessing
|
|
import traceback
|
|
from collections import defaultdict
|
|
import json
|
|
|
|
from tqdm import tqdm
|
|
import colorednoise
|
|
|
|
np.set_printoptions(linewidth=240)
|
|
|
|
|
|
|
|
sampling_rate = 10 # sp/s
|
|
|
|
|
|
# In[4]:
|
|
|
|
|
|
# From https://github.com/mubeta06/python/blob/master/signal_processing/sp/gold.py
|
|
preferred_pairs = {5:[[2],[1,2,3]], 6:[[5],[1,4,5]], 7:[[4],[4,5,6]],
|
|
8:[[1,2,3,6,7],[1,2,7]], 9:[[5],[3,5,6]],
|
|
10:[[2,5,9],[3,4,6,8,9]], 11:[[9],[3,6,9]]}
|
|
|
|
def gen_gold(seq1, seq2):
|
|
gold = [seq1, seq2]
|
|
for shift in range(len(seq1)):
|
|
gold.append(seq1 ^ np.roll(seq2, -shift))
|
|
return gold
|
|
|
|
def gold(n):
|
|
n = int(n)
|
|
if not n in preferred_pairs:
|
|
raise KeyError('preferred pairs for %s bits unknown' % str(n))
|
|
t0, t1 = preferred_pairs[n]
|
|
(seq0, _st0), (seq1, _st1) = sig.max_len_seq(n, taps=t0), sig.max_len_seq(n, taps=t1)
|
|
return gen_gold(seq0, seq1)
|
|
|
|
|
|
# In[5]:
|
|
|
|
|
|
def modulate(data, nbits=5):
|
|
# 0, 1 -> -1, 1
|
|
mask = np.array(gold(nbits))*2 - 1
|
|
|
|
sel = mask[data>>1]
|
|
data_lsb_centered = ((data&1)*2 - 1)
|
|
|
|
signal = (np.multiply(sel, np.tile(data_lsb_centered, (2**nbits-1, 1)).T).flatten() + 1) // 2
|
|
return np.hstack([ np.zeros(len(mask)), signal, np.zeros(len(mask)) ])
|
|
|
|
|
|
# In[6]:
|
|
|
|
|
|
def correlate(sequence, nbits=5, decimation=1, mask_filter=lambda x: x):
|
|
mask = np.tile(np.array(gold(nbits))[:,:,np.newaxis]*2 - 1, (1, 1, decimation)).reshape((2**nbits + 1, (2**nbits-1) * decimation))
|
|
|
|
sequence -= np.mean(sequence)
|
|
|
|
return np.array([np.correlate(sequence, row, mode='full') for row in mask])
|
|
|
|
|
|
# In[7]:
|
|
|
|
|
|
def load_noise_meas_params(capture_file):
|
|
with open(capture_file, 'rb') as f:
|
|
meas_data = np.copy(np.frombuffer(f.read(), dtype='float32'))
|
|
print('mean:', np.mean(meas_data), 'len:', len(meas_data))
|
|
meas_data -= np.mean(meas_data)
|
|
return {'meas_data': meas_data}
|
|
|
|
def mains_noise_measured(n, meas_data):
|
|
last_valid = len(meas_data) - n
|
|
start = np.random.randint(last_valid)
|
|
return meas_data[start:start+n]
|
|
|
|
def load_noise_synth_params(specfile):
|
|
with open(specfile) as f:
|
|
d = json.load(f)
|
|
return {'spl_x': np.linspace(*d['x_spec']),
|
|
'spl_N': d['x_spec'][2],
|
|
'psd_spl': (d['t'], d['c'], d['k']) }
|
|
|
|
def mains_noise_synthetic(n, psd_spl, spl_N, spl_x):
|
|
noise = np.random.normal(size=spl_N) * 2
|
|
spec = scipy.fftpack.fft(noise) **2
|
|
|
|
spec *= np.exp(scipy.interpolate.splev(spl_x, psd_spl))
|
|
|
|
spec **= 1/2
|
|
|
|
renoise = scipy.fftpack.ifft(spec)
|
|
return renoise[10000:][:n]
|
|
|
|
# In[8]:
|
|
|
|
|
|
def generate_test_signal(duration, nbits=6, signal_amplitude=2.0e-3, decimation=10, seed=0):
|
|
test_data = np.random.RandomState(seed=seed).randint(0, 2 * (2**nbits), duration)
|
|
|
|
signal = np.repeat(modulate(test_data, nbits) * 2.0 - 1, decimation) * signal_amplitude
|
|
noise = mains_noise(len(signal))
|
|
|
|
return test_data, signal + noise
|
|
|
|
|
|
# In[9]:
|
|
|
|
|
|
nonlinear_distance = lambda x: 100**(2*np.abs(0.5-x%1)) / (np.abs(x)+3)**2 * (np.clip(np.abs(x), 0, 0.5) * 2)**5
|
|
|
|
# In[11]:
|
|
|
|
|
|
noprint = lambda *args, **kwargs: None
|
|
|
|
|
|
# In[12]:
|
|
|
|
|
|
def run_ser_test(sample_duration=128, nbits=6, signal_amplitude=2.0e-3, decimation=10, threshold_factor=4.0, power_avg_width=2.5, max_lookahead=6.5, pol_score_factor=1.0, seed=0, ax=None, print=print, ser_maxshift=3, debug_range=None):
|
|
|
|
test_data, signal = generate_test_signal(sample_duration, nbits, signal_amplitude, decimation, seed)
|
|
cor_an = correlate(signal, nbits=nbits, decimation=decimation)
|
|
|
|
power_avg_width = int(power_avg_width * (2**nbits - 1) * decimation)
|
|
|
|
bit_period = (2**nbits) * decimation
|
|
peak_group_threshold = 0.05 * bit_period
|
|
hole_patching_threshold = 0.01 * bit_period
|
|
|
|
cwt_res = np.array([ sig.cwt(row, sig.ricker, [0.73 * decimation]).flatten() for row in cor_an ])
|
|
if ax:
|
|
ax.grid()
|
|
ax.plot(cwt_res.T)
|
|
|
|
th = np.array([ np.convolve(np.abs(row), np.ones((power_avg_width,))/power_avg_width, mode='same') for row in cwt_res ])
|
|
|
|
def compare_th(elem):
|
|
idx, (th, val) = elem
|
|
#print('compare_th:', th.shape, val.shape)
|
|
return np.any(np.abs(val) > th*threshold_factor)
|
|
|
|
peaks = [ list(group) for val, group in itertools.groupby(enumerate(zip(th.T, cwt_res.T)), compare_th) if val ]
|
|
peaks_processed = []
|
|
peak_group = []
|
|
for group in peaks:
|
|
pos = np.mean([idx for idx, _val in group])
|
|
#pol = np.mean([max(val.min(), val.max(), key=abs) for _idx, (_th, val) in group])
|
|
pol = max([max(val.min(), val.max(), key=abs) for _idx, (_th, val) in group], key=abs)
|
|
pol_idx = np.argmax(np.bincount([ np.argmax(np.abs(val)) for _idx, (_th, val) in group ]))
|
|
peaks_processed.append((pos, pol, pol_idx))
|
|
#print(f'group', pos, pol, pol_idx)
|
|
#for pol, (_idx, (_th, val)) in zip([max(val.min(), val.max(), key=abs) for _idx, (_th, val) in group], group):
|
|
# print(' ', pol, val)
|
|
#if ax:
|
|
# ax.axvline(pos, color='cyan', alpha=0.3)
|
|
msg = f'peak at {pos} = {pol} idx {pol_idx}: '
|
|
|
|
if peak_group:
|
|
msg += f'continuing previous group: {peak_group[-1]},'
|
|
group_start, last_pos, last_pol, peak_pos, last_pol_idx = peak_group[-1]
|
|
|
|
if abs(pol) > abs(last_pol):
|
|
msg += 'larger, '
|
|
if ax:
|
|
ax.axvline(pos, color='magenta', alpha=0.5)
|
|
peak_group[-1] = (group_start, pos, pol, pos, pol_idx)
|
|
|
|
else:
|
|
msg += 'smaller, '
|
|
if ax:
|
|
ax.axvline(pos, color='blue', alpha=0.5)
|
|
peak_group[-1] = (group_start, pos, last_pol, peak_pos, last_pol_idx)
|
|
else:
|
|
last_pos = None
|
|
|
|
if not peak_group or pos - last_pos > peak_group_threshold:
|
|
msg += 'terminating, '
|
|
if peak_group:
|
|
msg += f'previous group: {peak_group[-1]},'
|
|
peak_pos = peak_group[-1][3]
|
|
if ax:
|
|
ax.axvline(peak_pos, color='red', alpha=0.6)
|
|
#ax3.text(peak_pos-20, 2.0, f'{0 if pol < 0 else 1}', horizontalalignment='right', verticalalignment='center', color='black')
|
|
|
|
msg += f'new group: {(pos, pos, pol, pos, pol_idx)} '
|
|
peak_group.append((pos, pos, pol, pos, pol_idx))
|
|
if ax:
|
|
ax.axvline(pos, color='cyan', alpha=0.5)
|
|
|
|
if debug_range:
|
|
low, high = debug_range
|
|
if low < pos < high:
|
|
print(msg)
|
|
print(group)
|
|
|
|
avg_peak = np.mean(np.abs(np.array([last_pol for _1, _2, last_pol, _3, _4 in peak_group])))
|
|
print('avg_peak', avg_peak)
|
|
|
|
noprint = lambda *args, **kwargs: None
|
|
def mle_decode(peak_groups, print=print):
|
|
peak_groups = [ (pos, pol, idx) for _1, _2, pol, pos, idx in peak_groups ]
|
|
candidates = [ (abs(pol)/avg_peak, [(pos, pol, idx)]) for pos, pol, idx in peak_groups if pos < bit_period*2.5 ]
|
|
|
|
while candidates:
|
|
chain_candidates = []
|
|
for chain_score, chain in candidates:
|
|
pos, ampl, _idx = chain[-1]
|
|
score_fun = lambda pos, npos, npol: pol_score_factor*abs(npol)/avg_peak + nonlinear_distance((npos-pos)/bit_period)
|
|
next_candidates = sorted([ (score_fun(pos, npos, npol), npos, npol, nidx) for npos, npol, nidx in peak_groups if pos < npos < pos + bit_period*max_lookahead ], reverse=True)
|
|
|
|
print(f' candidates for {pos}, {ampl}:')
|
|
for score, npos, npol, nidx in next_candidates:
|
|
print(f' {score:.4f} {npos:.2f} {npol:.2f} {nidx:.2f}')
|
|
|
|
nch, cor_len = cor_an.shape
|
|
if cor_len - pos < 1.5*bit_period or not next_candidates:
|
|
score = sum(score_fun(opos, npos, npol) for (opos, _opol, _oidx), (npos, npol, _nidx) in zip(chain[:-1], chain[1:])) / len(chain)
|
|
yield score, chain
|
|
|
|
else:
|
|
print('extending')
|
|
for score, npos, npol, nidx in next_candidates[:3]:
|
|
if score > 0.5:
|
|
new_chain_score = chain_score * 0.9 + score * 0.1
|
|
chain_candidates.append((new_chain_score, chain + [(npos, npol, nidx)]))
|
|
print('chain candidates:')
|
|
for score, chain in sorted(chain_candidates, reverse=True):
|
|
print(' ', [(score, [(f'{pos:.2f}', f'{pol:.2f}') for pos, pol, _idx in chain])])
|
|
candidates = [ (chain_score, chain) for chain_score, chain in sorted(chain_candidates, reverse=True)[:10] ]
|
|
|
|
res = sorted(mle_decode(peak_group, print=noprint), reverse=True)
|
|
#for i, (score, chain) in enumerate(res):
|
|
# print(f'Chain {i}@{score:.4f}: {chain}')
|
|
(_score, chain), *_ = res
|
|
|
|
def viz(chain, peaks):
|
|
last_pos = None
|
|
for pos, pol, nidx in chain:
|
|
if last_pos:
|
|
delta = int(round((pos - last_pos) / bit_period))
|
|
if delta > 1:
|
|
print(f'skipped {delta-1} symbols at {pos}/{last_pos}')
|
|
|
|
# Hole patching routine
|
|
for i in range(1, delta):
|
|
est_pos = last_pos + (pos - last_pos) / delta * i
|
|
|
|
icandidates = [ (ipos, ipol, iidx) for ipos, ipol, iidx in peaks if abs(est_pos - ipos) < hole_patching_threshold ]
|
|
if not icandidates:
|
|
yield None
|
|
continue
|
|
|
|
ipos, ipol, iidx = max(icandidates, key = lambda e: abs(e[1]))
|
|
|
|
decoded = iidx*2 + (0 if ipol < 0 else 1)
|
|
print(f'interpolating, last_pos={last_pos}, delta={delta}, pos={pos}, est={est_pos} dec={decoded}')
|
|
yield decoded
|
|
|
|
decoded = nidx*2 + (0 if pol < 0 else 1)
|
|
yield decoded
|
|
if ax:
|
|
ax.axvline(pos, color='blue', alpha=0.5)
|
|
ax.text(pos-20, 0.0, f'{decoded}', horizontalalignment='right', verticalalignment='center', color='black')
|
|
|
|
last_pos = pos
|
|
|
|
decoded = list(viz(chain, peaks_processed))
|
|
print('decoding [ref|dec]:')
|
|
match_result = []
|
|
for shift in range(-ser_maxshift, ser_maxshift):
|
|
msg = f'=== shift = {shift} ===\n'
|
|
failures = -shift if shift < 0 else 0 # we're skipping the first $shift symbols
|
|
a = test_data if shift > 0 else test_data[-shift:]
|
|
b = decoded if shift < 0 else decoded[shift:]
|
|
for i, (ref, found) in enumerate(itertools.zip_longest(a, b)):
|
|
if ref is None: # end of signal
|
|
break
|
|
msg += f'{ref if ref is not None else -1:>3d}|{found if found is not None else -1:>3d} {"✔" if ref==found else "✘" if found else " "} '
|
|
if ref != found:
|
|
failures += 1
|
|
if i%8 == 7:
|
|
msg += '\n'
|
|
match_result.append((failures, msg))
|
|
failures, msg = min(match_result, key=lambda e: e[0])
|
|
print(msg)
|
|
ser = failures/len(test_data)
|
|
print(f'Symbol error rate e={ser}: {failures}/{len(test_data)}')
|
|
br = sampling_rate / decimation / (2**nbits) * nbits * (1 - ser) * 3600
|
|
print(f'maximum bitrate r={br} b/h')
|
|
return ser, br
|
|
|
|
|
|
# In[13]:
|
|
|
|
|
|
default_params = dict(
|
|
power_avg_width=2.5,
|
|
max_lookahead=6.5)
|
|
|
|
def calculate_ser(reps, v, seed, nbits, thf, duration, decimation):
|
|
params = dict(default_params)
|
|
params['signal_amplitude'] = v
|
|
params['decimation'] = decimation
|
|
params['nbits'] = nbits
|
|
params['threshold_factor'] = thf
|
|
|
|
out = []
|
|
for _rep in range(reps):
|
|
sers, brs = [], []
|
|
try:
|
|
ser, br = run_ser_test(**params, sample_duration=duration, print=noprint, seed=seed)
|
|
out.append((ser, br, None))
|
|
except Exception as e:
|
|
#traceback.print_exc()
|
|
out.append((None, None, f'got {e} seed {seed:08x} params {params}'))
|
|
return out
|
|
|
|
import argparse
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('-i', '--index', type=int, default=0)
|
|
parser.add_argument('-b', '--batches', type=int, default=1)
|
|
parser.add_argument('-z', '--chunksize', type=int, default=50)
|
|
parser.add_argument('-r', '--run-id', type=str, default='default')
|
|
group = parser.add_mutually_exclusive_group()
|
|
group.add_argument('-s', '--synthetic-noise', nargs='?', const='grid_freq_psd_spl_108pt.json', type=str)
|
|
group.add_argument('-m', '--measured-noise', nargs='?', default='fmeas_export_ocxo_2day.bin', const='fmeas_export_ocxo_2day.bin', type=str)
|
|
args = parser.parse_args()
|
|
|
|
# scheduled = [
|
|
# (5, 1.5, 50, 50, 128),
|
|
# (6, 2.0, 50, 50, 128),
|
|
# (6, 2.5, 50, 50, 128),
|
|
# (6, 3.0, 50, 50, 128),
|
|
# (6, 3.5, 50, 50, 128),
|
|
# (6, 4.0, 50, 50, 128),
|
|
# (6, 4.5, 50, 50, 128),
|
|
# (6, 5.0, 50, 50, 128),
|
|
# (6, 5.5, 50, 50, 128),
|
|
# (6, 6.0, 50, 50, 128),
|
|
# (6, 6.5, 50, 50, 128),
|
|
# (6, 7.0, 50, 50, 128),
|
|
# (6, 7.5, 50, 50, 128),
|
|
# (6, 8.0, 50, 50, 128),
|
|
# (6, 8.5, 50, 50, 128),
|
|
# (6, 9.0, 50, 50, 128),
|
|
# (6, 9.5, 50, 50, 128),
|
|
# (6, 10.0, 50, 50, 128),
|
|
# ]
|
|
#scheduled = [ (5, 4.0, 50, 70, 100, dec) for dec in list(range(19)) + [int(round(20 * 10**dec)) for dec in np.linspace(0, 0.7, 20)] ] #int(round(1 * 10**dec))) for dec in np.linspace(0, 2, 30) ]
|
|
|
|
#param_name = 'par101'
|
|
#scheduled = [ (nbits, thf, 100, 30, duration, 10) for thf in [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0] for nbits, duration in [(5, 128), (6, 128), (7, 64), (8, 64)] ]# int(round(3 * 10**dec)) for dec in np.linspace(0, 2, 30) ]
|
|
|
|
#param_name = 'par102'
|
|
#scheduled = [ (nbits, thf, 1000, 50, duration, int(round(3 * 10**dec))) for thf in [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0] for nbits, duration in [(5, 128), (6, 128), (7, 64), (8, 64)] for dec in np.linspace(0, 2, 30) ]
|
|
|
|
#param_name = 'par103'
|
|
#scheduled = [ (nbits, thf, 1000, 50, duration, 10) for thf in [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0] for nbits, duration in [(5, 128), (6, 128), (7, 64), (8, 64)] ]
|
|
|
|
#param_name = 'par105'
|
|
#scheduled = [ (nbits, thf, 1000, 30, duration, int(round(3 * 10**dec))) for thf in [2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0] for nbits, duration in [(5, 128), (6, 128)] for dec in np.linspace(0, 2, 30) ]
|
|
|
|
#param_name = 'dbg106'
|
|
#scheduled = [ (nbits, thf, 20, 15, duration, 10) for thf in [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0] for nbits, duration in [(5, 128), (6, 128)] ]
|
|
|
|
#param_name = 'par107'
|
|
#scheduled = [ (nbits, thf, 100, 30, duration, 10) for thf in [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0] for nbits, duration in [(5, 128), (6, 128), (7, 64), (8, 64)] ]
|
|
|
|
#param_name = 'par108'
|
|
#scheduled = [ (nbits, thf, 100, 30, duration, int(round(3 * 10**dec))) for thf in [2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0] for nbits, duration in [(5, 128), (6, 128)] for dec in np.linspace(0, 2, 30) ]
|
|
|
|
#param_name = 'par110'
|
|
#scheduled = [ (nbits, thf, 100, 30, duration, int(round(1 * 10**dec))) for thf in [3.5, 4.0, 4.5, 5.0] for nbits, duration in [(5, 128), (6, 128)] for dec in np.linspace(0.15, 2, 15) ]
|
|
|
|
#param_name = 'par111'
|
|
#scheduled = [ (nbits, thf, 100, 30, duration, dec) for thf in [3.5, 4.0, 4.5, 5.0] for nbits, duration in [(5, 128), (6, 128)] for dec in [1, 2, 3, 4, 5, 6, 9, 12, 16, 22, 30, 40, 50] ]
|
|
|
|
# Faster chip duration graph
|
|
#param_name = 'par112'
|
|
#scheduled = [ (nbits, thf, 50, 30, duration, dec) for thf in [4.0] for nbits, duration in [(5, 100)] for dec in [1, 2, 3, 4, 5, 6, 9, 12, 16, 22, 30, 40, 50] ]
|
|
|
|
#param_name = 'par113'
|
|
#scheduled = [ (nbits, thf, 100, 30, duration, dec) for thf in [4.0, 4.5, 5.0, 5.5] for nbits, duration in [(5, 128), (6, 128)] for dec in [1, 2, 3, 4, 5, 6, 9, 12, 16, 22, 30, 40, 50] ]
|
|
|
|
#param_name = 'par114'
|
|
#scheduled = [ (nbits, thf, 100, 30, duration, dec) for nbits, thf, duration in [(5, 4.0, 128), (6, 5.0, 128)] for dec in [1, 2, 3, 4, 5, 6, 9, 12, 16, 22, 30, 40, 50] ]
|
|
|
|
# Extra amplitude for 5 and 6 bit graphs NOTE: accidental duplicate param_name, earlier run is above set, later run this one.
|
|
#param_name = 'par114'
|
|
param_name = 'par115'
|
|
scheduled = [ (nbits, thf, 100, 0.05e-3 * 10 ** np.linspace(0, 3.5, 50), duration, 10) for thf in [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0] for nbits, duration in [(5, 128), (6, 128)] ]
|
|
|
|
random.Random(0).shuffle(scheduled)
|
|
batch = scheduled[args.index::args.batches]
|
|
print('Parameter set name', param_name)
|
|
|
|
if args.synthetic_noise is not None:
|
|
noise_params = load_noise_synth_params(args.synthetic_noise)
|
|
mains_noise = lambda n: mains_noise_synthetic(n, **noise_params)
|
|
noise_source = 'synth'
|
|
else:
|
|
noise_params = load_noise_meas_params(args.measured_noise)
|
|
mains_noise = lambda n: mains_noise_measured(n, **noise_params)
|
|
noise_source = 'meas'
|
|
|
|
def chunked(n, size):
|
|
for start in range(0, n, size):
|
|
end = min(reps, start + size)
|
|
yield start, end
|
|
|
|
results = {}
|
|
with tqdm(total = 0) as tq:
|
|
with multiprocessing.Pool(multiprocessing.cpu_count()) as pool:
|
|
#for nbits, thf, reps, points, duration in [(5, 4.0, 50, 25, 128), (6, 4.0, 50, 25, 128), (7, 5.0, 25, 25, 128), (8, 6.0, 25, 25, 64)]:
|
|
#for nbits, thf, reps, points, duration in [(6, 4.5, 5, 25, 128), (6, 5.0, 5, 25, 128)]:
|
|
for nbits, thf, reps, points, duration, decimation in batch:
|
|
st = np.random.RandomState(0)
|
|
|
|
if isinstance(points, numbers.Number):
|
|
vs = 0.05e-3 * 10 ** np.linspace(0, 2.0, points)
|
|
points_id = points
|
|
else:
|
|
vs = points
|
|
points_id = len(vs)
|
|
tq.write('scheduled {}reps x {}pt {}b @ th={} t={}sym dec={}sp'.format(reps, points_id, nbits, thf, duration, decimation))
|
|
results[(nbits, thf, reps, points_id, duration, decimation)] = { v:
|
|
[ pool.apply_async(calculate_ser, (end - start, v, st.randint(0xffffffff), nbits, thf, duration, decimation), callback=lambda _res: tq.update(end - start)) for start, end in chunked(reps, args.chunksize) ]
|
|
for v in vs }
|
|
tq.total += len(vs) * reps
|
|
tq.refresh()
|
|
|
|
tq.write(f'scheduled {tq.total} tasks. waiting...')
|
|
pool.close()
|
|
pool.join()
|
|
|
|
results = [ (key, [ (v, [ x for res in chunks for x in res.get() ]) for v, chunks in series.items() ]) for key, series in results.items() ]
|
|
tq.write('done')
|
|
|
|
#sers, brs = np.array(sers), np.array(brs)
|
|
#ser, std = np.mean(sers), np.std(sers)
|
|
#print(f'signal_amplitude={v:<.5f}: ser={ser:<.5f} ±{std:<.5f}, br={np.mean(brs):<.5f}')
|
|
#return ser, std
|
|
|
|
with open(f'dsss_experiments_res-{param_name}-{noise_source}-{args.run_id}-{args.index}-{datetime.datetime.now():%Y-%m-%d-%H-%M-%S}.json', 'w') as f:
|
|
json.dump(results, f)
|
|
print(f'Wrote results to {f.name}')
|
|
|