Hands-on Digital transmission with your soundcard

This article is part of the fundamentals of my real-world tutorial on digital communications using a cheap soundcard as the radio. If this notebook is interesting to you, check out the full tutorial!

01 - Setting up the Audio Interface

Welcome to this series of Jupyter Notebooks from dspillustrations.com. In this series, we employ the soundcard of your computer as a wireless transmitter and receiver. The audio output and loudspeaker will model the transmit antenna, whereas your microphone will mimic the receive antenna. In between there is the wireless channel, i.e. the environment of the room you are sitting in.

In the notebooks of this series we assemble the fundamental building blocks of a basic digital transmission. Eventually, we will be able to transmit digital data received from a UDP socket over the wireless audio channel.

In this notebook, we setup the audio environment. Therefore, we transmit a constant frequency sine wave and plot the time-domain waveform and frequency spectrum of the signal at the receiver side. In addition we introduce the general streaming framework we use for subsequent notebooks.

First, we import some standard packages and enable the IPython autoload extension.

In [1]:
# Source code has been redacted in online version
# Omitting 11 lines of source code
In [2]:
    %load_ext tikzmagic
except ModuleNotFoundError:
    print ("Did not find tikzmagic. You will not be able to compile the tex code!")
In [3]:
%matplotlib notebook

Now, we import the required classes from the supplied library audioComms which contains the fundamental building blocks for our system:

In [4]:
from audioComms import Environment

Every experiment needs to run in an environment, which is represented by an instance of the class Environment. In the environment, we register several components. Subsequently, we start the audio streaming by running the environment.

In [5]:
from audioComms import TX

An instance of the class TX describes a component which generates the transmit signal. We will use it as the base class for our waveform transmitter below.

In [6]:
from audioComms.channels import AudioChannel

The AudioChannel class implements the actual audio streaming, i.e. replaying the waveform at the audio output and recording the microphone input.

In [7]:
from audioComms.plotting import PlotSpectrum, PlotWaveform

Eventually, PlotSpectrum und PlotWaveform visually display the received signal as a frequency or time-domain plot.

Let's define our signal generator below. We subclass the TX class and overwrite the _generalSignal method. This method is called, whenever the transmit signal audio buffer is running out of data. In this case, we have to generate more transmit samples. Here, in order to generate a sine wave with no phase jumps, we save the number of transmitted already samples and adjust the argument to the sine function accordingly.

In [8]:
class TransmitSine(TX):
    def __init__(self, environment, Fc=440):
        self._Fc = Fc            # the frequency of the sine wave
        self._numsamples = 0     # the number of transmitted samples
    def _generateSignal(self):
        N = 10000
        t = (np.arange(N) + self._numsamples) / self._samplerate
        self._numsamples += N
        return np.sin(2*np.pi*self._Fc*t)

In the following code cell, we setup our experiment. In general, we think of the following signal flow between the blocks:

In [9]:
# Source code has been redacted in online version
# Omitting 11 lines of source code

Hence, we first define our environment with the samplerate to use. Second, we create the components in the diagram and third, we establish the connections between the building blocks. Eventually, we start the experiment. You can stop the experiment with the "Stop" button in the toolbar.

Attention: Due to some jupyter caveats, the stop button does not always work reliably. In case the system cannot be stopped with the stop button, you can use another python process to stop the system via UDP:

  • go to the directory containing audioComms.py
  • run `python -c "import audioComms; audioComms.stopEnvironmentViaUDP()"
In [11]:
# 1 - Create the environment
samplerate = 44100
env = Environment(samplerate)

# 2 - Setup the components
tx = TransmitSine(environment=env, Fc=440)
channel = AudioChannel(environment=env)
fig = env.figure(figsize=(10,3))
showSpec = PlotSpectrum(environment=env, windowDuration=1, logScale=True, axes=fig.add_subplot(121))
showWave = PlotWaveform(environment=env, windowDuration=0.05, axes=fig.add_subplot(122))

# 3 - Establish connections between the blocks

# 4 - run the experiment
Stop received from external

If everything works well, you will hear a smooth sine tone of 440Hz frequency. In addition, the signal recorded by the microphone should show a sine wave of 440Hz with varying amplitude, depending on the volume and position of the microphone.

If you cannot hear a tone or no signal is recorded, please refer to the documentation of python-sounddevice how to setup the audio system. In addition, you might need to associate the right audio device to the python process in the operating system's settings.

Use a cable between audio output and microphone input

Even though it is interesting and encouraging to actually hear the transmitted signals, soon the sound will be annoying your (and your neighbors/parents/flatmates/partners) ears. In this situation, just use a cable between the audio output and microphone input, which shortcuts the wireless link.


In the following notebook we will introduce a class to simulate the audio transmission, named SimulatedChannel.

This article is part of the fundamentals of my real-world tutorial on digital communications using a cheap soundcard as the radio. If this notebook is interesting to you, check out the full tutorial!

Copyright (C) 2018 - dspillustrations.com

DSPIllustrations.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to amazon.com, amazon.de, amazon.co.uk, amazon.it.