Status update -- bursty QPSK modem Wed, Aug 19 2015 AM
Theres been some really excellent progress towards implementing a working modem in Pothos. This announcement is primarily to show off some new blocks and changes to support the use of bursts using the communications blocks with SDR hardware.
New demo available: Modem0
Modem Example 0 is a demonstration design implementing a QPSK transmitter and receiver chain. The input and output are based around chat boxes located within the graphical designer, so its actually pretty fun to play with. Note: this is currently just a loopback demo (between TX and RX antenna on the same device), more work and validation are yet to be done to make this robust between multiple devices.
FIR Filter with burst flushing
The FIR filter exclusively operates on streams of samples. The problem is that the end of bursts get stuck in the filter. Because of convolution operation, the FIR filter needs to look ahead past the end of the burst to have samples to convolve with, but without a second burst right after, we get stuck, and even underflow the SDR sink. I added support for both length labels and end of frame labels to the FIR filter so the remaining burst could be flushed out and convolved with a buffer of trailing zeros.
Burst Timer for SDR Sink
To avoid underflowing in the middle of a transmitted burst, we want to specify a transmit time in the near future. The burst timer is a new block in the pothos-sdr toolkit that provides a convenient way to schedule bursts by keeping track of the current hardware time. In the screenshot, we have a little circuit with the periodic timer to keep the hardware time up-to-date.
Wave Monitor: new triggering capabilities
For the longest time, the wave monitor simply had a periodic trigger function. However, it was getting frustrating to debug the received bursts. I wanted to be able to trigger on a amplitude level, or other more complicated conditions.
I created a new utility block called "Wave Trigger" which implements many of the triggering features of an oscilloscope. The wave trigger can be used an independent block, but its now the backend processing for the Wave Monitor widget, implementing the trigger options in the screenshot.
The wave trigger also has a configurable number of windows. Windows helped to capture multiple trigger events back-to-back. This helped a lot to diagnose some burst fragmentation issues.
Frame insertion
To help make bursty modem possible, the bursts are framed with a header that provides a configurable training sequence and encodes the burst length. The companion frame synchronization block uses this header to detect and recover the frame. The block also provides a configurable padding, which may be needed to flush the burst through the filters in the SDR transmit chain (hardware dependent).
Frame synchronization
On the receiver side, the frame synchronization block searches a continuous receive stream for frame headers. The training sequence in the header is used to recover frequency, phase, and timing offsets. The block has several output modes including forwarding the raw payload, frequency offset correction, and timing recovery.
The recovery output modes are a convenience and do not track phase and timing error (they are recommended for short payloads). However, the frame sync block can easily be paired with a downstream Costas loop, matched filter, or MM clock reovery block. (Many of these blocks can be found in the GNU Radio toolkit).
Burst label conventions
After working on these demos and improving the blocks toolkit, I have come up with some conventions for using burst labels that seem to hold up very well in different use cases.
- Start label: The start label's position indicates the first element in a burst and may be paired with a MTU setting to indicate the length.
- End label: The end label's position indicates the last element in a burst, start is implied as the next element after the label.
- Length label: The length label is just like the start label except that its data field contains a configurable length in elements.
Now three different conventions may seem redundant (and they are). Some uses of the burst labels may be easier to implement then others. The SDR sink is easier to implement with an end label because the hardware driver expects an end of burst flag. The frame sync block is easier to implement with a length label because the length is found at the burst start within the frame header. In general, we try to make core toolkit blocks support all three so that the user will have maximum flexibility for their use-case.
Making use of the label width
Earlier this year I added the a width parameter to labels to deal with the ambiguity of the label position after a passing through a rate changing block. But the label width also works just as well well to interpret the label length after a rate change.
- Using a length label: The location of the last element can be calculated as index + length * label.width; In the modem 0 receiver chain, the frame sink produces a length label and sets the width to the output samples per symbol. A timing recovery block (not shown) would reduce the label width to 1, while decimating by the same ratio, meaning the length equation still holds.
- Using an end label: The location of the last element can be calculated as index + label.width-1; In the modem 0 transmit chain, the SDR sink uses this feature to know which sample is the end of burst, after the FIR filter performs its interpolation.
Anyway, there are still plenty of cases where this convention can break down. And really, some blocks will need to be configured to handle re-writing or repositioning burst labels based on the circumstances.