diff options
Diffstat (limited to 'tools/sweep_gr_sims.py')
-rw-r--r-- | tools/sweep_gr_sims.py | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/tools/sweep_gr_sims.py b/tools/sweep_gr_sims.py new file mode 100644 index 0000000..661af56 --- /dev/null +++ b/tools/sweep_gr_sims.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +import subprocess +import time +import struct +import random +import math +import statistics +import tempfile +import itertools +from collections import defaultdict +from os import path + +import tqdm + + +SIMS = [ 'dec_proto_am_ber_top.py', + 'dec_proto_am_dc_ber_top.py', + 'dec_proto_fm_ber_top.py', + ] +E12_SERIES = [1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2] +AMPLITUDES_MILLIHERTZ = [ x*y for y in [1, 10, 100] for x in E12_SERIES ] + +SIMULATION_DURATION = 30.0 # seconds realtime +MAX_CONCURRENT_PROCESSES = 8 + + +def run_simulation( + duration = SIMULATION_DURATION, + simulations = SIMS, + forklimit = MAX_CONCURRENT_PROCESSES, + amplitudes:'list(millihertz)' = AMPLITUDES_MILLIHERTZ, + terminate_timeout:'s' = 5.0, + communicate_timeout:'s' = 10.0, + repeat_runs = 1, + shuffle = False, + tqdm = tqdm.tqdm + ): + with tempfile.TemporaryDirectory() as tmpdir: + + jobs = list(enumerate(itertools.product(simulations, amplitudes * repeat_runs))) + if shuffle: + random.shuffle(jobs) + nchunks = int(math.ceil(len(jobs)/forklimit)) + + def start_processes(jobs): + for i, (sim, ampl_mhz) in jobs: + berfile = path.join(tmpdir, f'berfile_{i}') + proc = subprocess.Popen(['/usr/bin/python2', sim, + '--signal-strength', str(ampl_mhz), + '--ber-file', berfile], + stdin=subprocess.PIPE, stdout=subprocess.DEVNULL) + yield proc, sim, ampl_mhz, berfile + + results = { sim: defaultdict(lambda: ([], [])) for sim in simulations } + with tqdm(total = nchunks * duration, bar_format='{l_bar}{bar}| {elapsed}<{remaining}') as tq: + tq.write(f'Will launch {len(jobs)} simulation jobs in {nchunks} batches of {forklimit}') + for n, i in enumerate(range(0, len(jobs), forklimit)): + batch = jobs[i:][:forklimit] + tq.write(f'Starting batch {n+1}/{nchunks}...') + processes = list(start_processes(batch)) + tq.write('done.') + + tq.write('Waiting for simulation:') + for _ in range(100): + time.sleep(duration/100) + tq.update(duration/100) + + tq.write('Terminating processes...') + for proc, *_ in processes: + proc.communicate(b'\n', timeout=communicate_timeout) + + for proc, *_ in processes: + proc.wait(terminate_timeout) + tq.write('done.') + + tq.write('Processing simulation results') + for _proc, sim, ampl_mhz, berfile in processes: + + with open(berfile, 'rb') as f: + data = f.read() + + floats = struct.unpack(f'{len(data)//4}f', data) + ber = statistics.mean(floats[-256:]) + stdev = statistics.stdev(floats[-256:]) + + bers, stdevs = results[sim][ampl_mhz] + bers.append(ber) + stdevs.append(stdev) + + return results + +if __name__ == '__main__': + print(run_simulation()) |