Python Gateway Tutorial

The UnetStack Python gateway API is available via unet-contrib, or from PyPi.

Import unetpy

If you haven't installed unetpy, you need to do that first: pip install unetpy


In [ ]:
from unetpy import *

Open a connection to the modem or real-time simulator

For now, we'll assume that we have a modem running on localhost port 1100 (default):


In [ ]:
sock = UnetSocket('localhost', 1100)
modem = sock.getGateway()

Work with modem parameters

If we are connected to the modem, we can now access the agents and services that the modem provides. Let us try this with the physical layer first. What you'll see here depends on the modem you are using (we are using the portaudio modem on a laptop for this example).


In [ ]:
phy = modem.agentForService(Services.PHYSICAL)

In [ ]:
phy

We can query individual parameters or change them:


In [ ]:
phy.signalPowerLevel

In [ ]:
phy.signalPowerLevel = -6

In [ ]:
phy.signalPowerLevel

We can work with the CONTROL (1) or DATA (2) channels too...


In [ ]:
phy[1]

In [ ]:
phy[1].frameLength = 12

In [ ]:
phy[1].frameDuration

You can also work with higher layers:


In [ ]:
link = modem.agentForService(Services.LINK)

In [ ]:
link

Send and receive messages

The messages supported on the Python gatweway are pretty much the same as the Java/Groovy messages. In Python, the named parameters for message initialization use equals (=) instead of colon (:), and you don't need the new keyword. It's easy to get used to:


In [ ]:
phy << TxFrameReq(to=2, data=[1,2,3,4])

And read the TxFrameNtf notification once the packet is sent out:


In [ ]:
txntf = modem.receive(TxFrameNtf, timeout=2000)

Transmit and receive signals

For this part of the tutorial, we'll use numpy and arlpy. So if you don't have them installed, you'll need them: pip install arlpy (which will also install numpy).


In [ ]:
import numpy as np
import arlpy.signal as asig
import arlpy.plot as plt

Generate a passband 100 ms 12 kHz pulse at a sampling rate of 96 kSa/s:


In [ ]:
fs = 96000
x = asig.cw(12000, 0.1, fs)

and transmit it using the baseband service:


In [ ]:
bb = modem.agentForService(Services.BASEBAND)
bb << TxBasebandSignalReq(signal=x, fc=0, fs=fs)

In [ ]:
txntf = modem.receive(TxFrameNtf, timeout=2000)

By setting fc to 0, we told the modem that this was a passband signal. The sampling rate supported by passband signals will depend on the modem. In our case, the portaudio interface is set to accept 96 kSa/s passband signals.

Now let's ask the modem to record a signal for us:


In [ ]:
bb << RecordBasebandSignalReq(recLength=4800)

In [ ]:
rec = modem.receive(RxBasebandSignalNtf, timeout=2000)

In [ ]:
rec.fc

In [ ]:
rec.fs

The notification has 4800 baseband (complex) samples as we had asked, and is sampled at a baseband rate of 12 kSa/s. The carrier frequency used by the modem is 12 kHz. We can convert our recorded signal to passband if we like:


In [ ]:
y = asig.bb2pb(rec.signal, rec.fs, rec.fc, fs)

In [ ]:
plt.plot(y, fs=fs)

In [ ]:
plt.specgram(y, fs=fs)

Clean up

Once we are done, we can clean up by closing the connection to the modem.


In [ ]:
modem.close()