From 3a59a54107f01ae33c12b41ae2bb8b931ec23008 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 21 Oct 2014 10:42:13 +0300 Subject: [PATCH] refactor calibration `recv` script --- amodem/calib.py | 69 ++++++++++++++++++++++++++++++--------------- scripts/amodem | 4 +-- tests/test_calib.py | 2 +- 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/amodem/calib.py b/amodem/calib.py index 9ef3c0c..2f0bf6d 100644 --- a/amodem/calib.py +++ b/amodem/calib.py @@ -12,7 +12,7 @@ CALIBRATION_SYMBOLS = int(1.0 * config.Fs) ALLOWED_EXCEPTIONS = (IOError, KeyboardInterrupt) -def send(wave_play=wave.play): +def send(wave_play=wave.play, verbose=False): t = np.arange(0, CALIBRATION_SYMBOLS) * config.Ts signal = [np.sin(2 * np.pi * f * t) for f in config.frequencies] signal = common.dumps(np.concatenate(signal)) @@ -28,41 +28,66 @@ def send(wave_play=wave.play): p.kill() -FRAME_LENGTH = 100 * config.Nsym +FRAME_LENGTH = 200 * config.Nsym def recorder(process): + t = np.arange(0, FRAME_LENGTH) * config.Ts + scaling_factor = 0.5 * len(t) + carriers = [np.exp(2j * np.pi * f * t) for f in config.frequencies] + carriers = np.array(carriers) / scaling_factor + frame_size = int(wave.bytes_per_sample * FRAME_LENGTH) fd = process.stdout + + states = [True] + errors = ['weak', 'strong', 'noisy'] try: while True: data = fd.read(frame_size) if len(data) < frame_size: return data = common.loads(data) - data = data - np.mean(data) - yield data + frame = data - np.mean(data) + + coeffs = np.dot(carriers, frame) + peak = np.max(np.abs(frame)) + total = np.sqrt(np.dot(frame, frame) / scaling_factor) + + max_index = np.argmax(np.abs(coeffs)) + freq = config.frequencies[max_index] + rms = abs(coeffs[max_index]) + coherency = rms / total + flags = [rms > 0.1, peak < 1.0, coherency > 0.9999] + + states.append(all(flags)) + states = states[-2:] + + message = 'good signal' + error = not any(states) + if error: + error_index = flags.index(False) + message = 'too {} signal'.format(errors[error_index]) + + yield dict( + freq=freq, rms=rms, peak=peak, coherency=coherency, + total=total, error=error, message=message + ) except ALLOWED_EXCEPTIONS: pass finally: process.kill() +fmt = '{freq:6.0f} Hz: {message:s}{extra:s}' +fields = ['peak', 'total', 'rms', 'coherency'] -def recv(wave_record=wave.record, log=sys.stdout.write): - t = np.arange(0, FRAME_LENGTH) * config.Ts - carriers = [np.exp(2j * np.pi * f * t) for f in config.frequencies] - carriers = np.array(carriers) / (0.5 * len(t)) - - for frame in recorder(wave_record(stdout=wave.sp.PIPE)): - peak = np.max(np.abs(frame)) - coeffs = np.dot(carriers, frame) - max_index = np.argmax(np.abs(coeffs)) - max_coeff = coeffs[max_index] - - freq = config.frequencies[max_index] - rms = abs(max_coeff) - total = np.sqrt(np.dot(frame, frame) / (0.5 * len(t))) - coherency = rms / total - log(fmt.format(freq / 1e3, 100 * coherency, rms, total, peak)) - -fmt = '{:4.0f} kHz @ {:6.2f}% : RMS = {:.4f}, Total = {:.4f}, Peak = {:.4f}\n' +def recv(wave_record=wave.record, printer=sys.stdout.write, verbose=False): + extra = '' + if verbose: + extra = ''.join(', {0}={{{0}:.4f}}'.format(f) for f in fields) + for r in recorder(wave_record(stdout=wave.sp.PIPE)): + msg = fmt.format(extra=extra.format(**r), **r) + if not r['error']: + log.info(msg) + else: + log.error(msg) diff --git a/scripts/amodem b/scripts/amodem index 5ce5791..5ffb541 100755 --- a/scripts/amodem +++ b/scripts/amodem @@ -148,7 +148,7 @@ def run_modem(args, func): def run_send(args): if args.calibrate: - calib.send() + calib.send(verbose=args.verbose) elif args.wave: join_process(wave.play(fname=args.input)) else: @@ -157,7 +157,7 @@ def run_send(args): def run_recv(args): if args.calibrate: - calib.recv() + calib.recv(verbose=args.verbose) elif args.wave: join_process(wave.record(fname=args.output)) else: diff --git a/tests/test_calib.py b/tests/test_calib.py index 97bf248..6adc712 100644 --- a/tests/test_calib.py +++ b/tests/test_calib.py @@ -43,5 +43,5 @@ def test_errors(): def _read(data): raise KeyboardInterrupt() p.read = _read - calib.recv(p) + calib.recv(p, verbose=True) assert p.buf.tell() == 0