main: refactor send and recv

This commit is contained in:
Roman Zeyde
2015-02-04 08:16:12 +02:00
parent 53559ff8df
commit ef8a75f10e
5 changed files with 76 additions and 74 deletions

View File

@@ -19,7 +19,7 @@ except ImportError:
log = logging.getLogger('__name__')
from amodem import recv, send, calib, audio, async
from amodem import main, calib, audio, async
from amodem.config import bitrates
bitrate = os.environ.get('BITRATE', 1)
@@ -96,7 +96,7 @@ def get_volume_cmd(args):
return c[args.command]
def main():
def _main():
fmt = ('Audio OFDM MODEM: {0:.1f} kb/s ({1:d}-QAM x {2:d} carriers) '
'Fs={3:.1f} kHz')
description = fmt.format(config.modem_bps / 1e3, len(config.symbols),
@@ -118,7 +118,7 @@ def main():
'-o', '--output', help='output file (use "-" for stdout).'
' if not specified, `aplay` tool will be used.')
sender.set_defaults(
main=lambda config, args: send.main(
main=lambda config, args: main.send(
config, src=wrap(Compressor, args.src, args.zip), dst=args.dst
),
calib=lambda config, args: calib.send(
@@ -145,7 +145,7 @@ def main():
'--plot', action='store_true', default=False,
help='plot results using pylab module')
receiver.set_defaults(
main=lambda config, args: recv.main(
main=lambda config, args: main.recv(
config, src=args.src, dst=wrap(Decompressor, args.dst, args.zip),
pylab=args.pylab, dump_audio=args.dump
),
@@ -213,5 +213,5 @@ def main():
if __name__ == '__main__':
success = main()
success = _main()
sys.exit(0 if success else 1)

68
amodem/main.py Normal file
View File

@@ -0,0 +1,68 @@
import numpy as np
import logging
import itertools
from . import send as _send
from . import recv as _recv
from . import framing, common, stream, detect, sampling
log = logging.getLogger(__name__)
def send(config, src, dst):
sender = _send.Sender(dst, config=config)
Fs = config.Fs
# pre-padding audio with silence (priming the audio sending queue)
sender.write(np.zeros(int(Fs * config.silence_start)))
sender.start()
training_duration = sender.offset
log.info('Sending %.3f seconds of training audio', training_duration / Fs)
reader = stream.Reader(src, eof=True)
data = itertools.chain.from_iterable(reader)
bits = framing.encode(data)
log.info('Starting modulation')
sender.modulate(bits=bits)
data_duration = sender.offset - training_duration
log.info('Sent %.3f kB @ %.3f seconds',
reader.total / 1e3, data_duration / Fs)
# post-padding audio with silence
sender.write(np.zeros(int(Fs * config.silence_stop)))
return True
def recv(config, src, dst, dump_audio=None, pylab=None):
if dump_audio:
src = stream.Dumper(src, dump_audio)
reader = stream.Reader(src, data_type=common.loads)
signal = itertools.chain.from_iterable(reader)
log.debug('Skipping %.3f seconds', config.skip_start)
common.take(signal, int(config.skip_start * config.Fs))
pylab = pylab or common.Dummy()
detector = detect.Detector(config=config, pylab=pylab)
receiver = _recv.Receiver(config=config, pylab=pylab)
try:
log.info('Waiting for carrier tone: %.1f kHz', config.Fc / 1e3)
signal, amplitude, freq_error = detector.run(signal)
freq = 1 / (1.0 + freq_error) # receiver's compensated frequency
log.debug('Frequency correction: %.3f ppm', (freq - 1) * 1e6)
gain = 1.0 / amplitude
log.debug('Gain correction: %.3f', gain)
sampler = sampling.Sampler(signal, sampling.Interpolator(), freq=freq)
receiver.run(sampler, gain=1.0/amplitude, output=dst)
return True
except BaseException:
log.exception('Decoding failed')
return False
finally:
dst.flush()
receiver.report()

View File

@@ -6,13 +6,10 @@ import time
log = logging.getLogger(__name__)
from . import stream
from . import dsp
from . import sampling
from . import common
from . import framing
from . import equalizer
from . import detect
class Receiver(object):
@@ -193,36 +190,3 @@ class Receiver(object):
self.plt.axis('equal')
self.plt.axis(np.array([-1, 1, -1, 1])*1.1)
self.plt.title(title)
def main(config, src, dst, dump_audio=None, pylab=None):
if dump_audio:
src = stream.Dumper(src, dump_audio)
reader = stream.Reader(src, data_type=common.loads)
signal = itertools.chain.from_iterable(reader)
log.debug('Skipping %.3f seconds', config.skip_start)
common.take(signal, int(config.skip_start * config.Fs))
pylab = pylab or common.Dummy()
detector = detect.Detector(config=config, pylab=pylab)
receiver = Receiver(config=config, pylab=pylab)
try:
log.info('Waiting for carrier tone: %.1f kHz', config.Fc / 1e3)
signal, amplitude, freq_error = detector.run(signal)
freq = 1 / (1.0 + freq_error) # receiver's compensated frequency
log.debug('Frequency correction: %.3f ppm', (freq - 1) * 1e6)
gain = 1.0 / amplitude
log.debug('Gain correction: %.3f', gain)
sampler = sampling.Sampler(signal, sampling.Interpolator(), freq=freq)
receiver.run(sampler, gain=1.0/amplitude, output=dst)
return True
except BaseException:
log.exception('Decoding failed')
return False
finally:
dst.flush()
receiver.report()

View File

@@ -5,8 +5,6 @@ import itertools
log = logging.getLogger(__name__)
from . import common
from . import stream
from . import framing
from . import equalizer
from . import dsp
@@ -48,30 +46,3 @@ class Sender(object):
if i % self.iters_per_report == 0:
total_bits = i * Nfreq * self.modem.bits_per_symbol
log.debug('Sent %10.3f kB', total_bits / 8e3)
def main(config, src, dst):
sender = Sender(dst, config=config)
Fs = config.Fs
# pre-padding audio with silence (priming the audio sending queue)
sender.write(np.zeros(int(Fs * config.silence_start)))
sender.start()
training_duration = sender.offset
log.info('Sending %.3f seconds of training audio', training_duration / Fs)
reader = stream.Reader(src, eof=True)
data = itertools.chain.from_iterable(reader)
bits = framing.encode(data)
log.info('Starting modulation')
sender.modulate(bits=bits)
data_duration = sender.offset - training_duration
log.info('Sent %.3f kB @ %.3f seconds',
reader.total / 1e3, data_duration / Fs)
# post-padding audio with silence
sender.write(np.zeros(int(Fs * config.silence_stop)))
return True

View File

@@ -3,8 +3,7 @@ from io import BytesIO
import numpy as np
from amodem import send
from amodem import recv
from amodem import main
from amodem import common
from amodem import dsp
from amodem import sampling
@@ -30,7 +29,7 @@ class Args(object):
def run(size, chan=None, df=0, success=True, reader=None):
tx_data = os.urandom(size)
tx_audio = BytesIO()
send.main(config=config, src=BytesIO(tx_data), dst=tx_audio)
main.send(config=config, src=BytesIO(tx_data), dst=tx_audio)
data = tx_audio.getvalue()
data = common.loads(data)
@@ -49,7 +48,7 @@ def run(size, chan=None, df=0, success=True, reader=None):
if reader:
rx_audio = reader(rx_audio)
try:
result = recv.main(config=config, src=rx_audio, dst=rx_data,
result = main.recv(config=config, src=rx_audio, dst=rx_data,
dump_audio=dump)
finally:
rx_audio.close()