mirror of
https://github.com/romanz/amodem.git
synced 2026-03-17 07:05:59 +08:00
main: refactor send and recv
This commit is contained in:
10
amodem-cli
10
amodem-cli
@@ -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
68
amodem/main.py
Normal 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()
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user