FreeDV on Android

This blog post presents the content from my linux.conf.au 2013 presentation Droids that talk: Pairing Codec2 and Android, where I presented some background on radio theory, and followed by a discussion of the software components required to run Codec2 and Fdmdv2 on Android, via a USB sound card.

joel_preso_1

Codec2 a digital voice codec for communication below 2400 bits per second, developed by local voice codec guru David Rowe. It is fully open – free software, as in both beer and speech sense. He as also created a modem designed for carrying Codec2 over HF channels, called Fdmdv2. David and his co-contributors have combined Codec2 and Fdmdv2 to create FreeDV, a free software digital voice application for communicating over HF radio using your Linux, Mac or PC.

Freedv

Hobbies

In addition to my FOSS hobbies, I’ve been getting involved in amateur radio these past few years. This began with meeting Mark in the final year of my degree, moved into my time spent playing with balloons as part of Project Horus, and now has continued with FreeDV.

Mark and Joel at Linux.conf.au 2011

Modern Communication

As technology progresses, more complex systems can be built and understood with the tools we have. Sophisticated DSP and SDR are within the reach of the linux.conf.au attendee skill set. DSP is digital signal processing; a field that moves signal processing from physical circuits to software that runs on a computer. It is relatively new, as it was only in the 80s that digital logic became fast enough to run the software in real time. SDR is software defined radio, where DSP techniques are applied to the building of radios. The following information describes the building blocks for using DSP and SDR to implement a digital voice over radio system.

Radio Theory

Radio Block Diagram

In studying for my Engineering degree, I learnt a bit about how radios work. Of interest for FreeDV is the use of a direct conversion receiver  Put simply, this kind of receiver uses the difference between a local oscillator and an amplified incoming HF signal to produce an image of the HF signal at baseband. Once amplified this baseband signal is suited for capture by a sound card, in order to be decoded and tuned using Software Defined Radio techniques. Using these simple building blocks a DSB receiver can be constructed for receiving FreeDV or SSB analog voice over the air.
Radio Frequency

Such a radio is described in my building a double sideband receiver blog post. The completed radio is show below, with the major stages compared to the block diagram above.

Radio Block Overlay

Software

Now that the HF signal present in the computer and ready to be processed, the software must be designed. The codec and modem is implemented in C; in order to save effort in re-implementing in Java and staying up to date with changes, it was decided to use the C libraries directly, and interface them with the Java’s foreign function interface; Java Native Interface. The Android team provide a cross complier for the supported applications called the Native Development Kit (NDK).

Android Audio Input

Android handsets have a connector for microphones, however, they are not suitable as a line-in in the same way as a PC sound input, as the connector pins vary between phone manufacturers  as does the specification for the impedance between pins in order to detect the microphone. Instead, it was decided to use a USB Audio Class (UAC) soundcard device digitise the baseband radio signal.

Android runs the Linux kernel, however, unlike a desktop Linux operating system, it does not include a driver for supporting UAC devices. A user space driver for supporting the UAC device was written, using the c libusb library. This sets up an isochronous transfer from the appropriate descriptor to get 16-bit PCM audio at 48kHz delivered to a callback. The configuration is currently hardcoded for the TI PCM2900C device; this will be made generic in time.

Another complication that Android brings is the security architecture  An application can only access a USB device if it has requested permission through the USB host API. This is only provided on Android 3.1 (API 12), which means pre-4.0 devices are not supported. This compromise is acceptable, as in general older devices lack the CPU cycles to run the application. A modified version of libusb that requests permission on open, and is buildable by the Android NDK toolchain, can be found on github. Thanks to Роман Донченко for releasing this work!

Android Integration

FreeDV Android Software

The C code is all built using the NDK build system. Each component is built as a separate shared library, with the JNI code initialising each of the modules below it and registering handles for the appropriate Java callback functions. The USB callback receives the sound samples from the radio, and calls into a processing loop that is shared with the FreeDV desktop software. When enough samples to decode an entire frame, this loop uses the modem to decode a frame, which itself passes the bits to the codec if the modem is in sync.

The modem depends on the quality of the HF channel; when the demodulation side of the modem cannot sync, no data can be recovered.  Synchronisation state, as well as estimates of the timing and frequency offset of the recovered signal is passed to the Java side of the app to be displayed. When the modem is in sync, the decoded phase information is also passed to Java so it can be plotted in a scatter plot. This plot allows the user to adjust their radio’s output levels to ensure a good spread, as well as observe the effects of interference on the received data.

Android Graphing

In Android, there are no built-in widgets for drawing graphs of any kind. There does exist a library called GraphView, which provides various types of classes. As I had familiarity with the line graph class, I used this for the timing and frequency offset graphs. This required hacking GraphView a fair bit, as it did not at the time support the graphing of real-time data (since then it has gained this functionality).

joel_preso_3I decided to write my own scatter graph class, in order to learn about drawing on Android. It inherits from View, with data collected as it comes from the modem into a LinkedList of fixed size, and invalidate() is called so that the system knows to re-draw the graph when the UI thread is ready. The onDraw() call finds the largest points, scales and filters them, and draws circles for each point to a Canvas. It was easy enough to do drawing in Android by following the basic shape drawing tutorial, despite appearing complex when reading about it. I was worried about performance; should I be scaling the points when inserted, so they don’t happen when drawing? Or does that mean that I would be iterating over the list to update the scale more than once between onDraws, and therefore do unnecessary work? These are still good questions to answer, but for now, it Just Works.

Native Code Optimisation

The native code is built with -O2 -ffast-math flags for speed, as well as NEON support enabled through the NDK’s mechanism. There were optimisations provided to the codec2 mailing list some time ago, including using the float instead of double precision variant of the maths functions, and I incorporated some of these in the copy of the FreeDV software I used. It is not clear if these performance optimisations are necessary in order for real-time performance; some benchmarking is required. For now the NEON support means that the application will not run on all platforms, as there is no run-time detection performed.

Summary

In the near future, I plan to add a waterfall display of the received spectrum, and allow tuning within this range. I will also add support for generic USB Audio Class devices, as well as analog input for those who have line-in ability on their Android devices.

The source code can be found on Github. Please download, compile, code-review, hack, and test. Any feedback is welcome.

Thanks to David and Mark for your help with all of the hacking, both hardware and software, to Kristina for your help in preparing my talk and taking the photos of me presenting that I’ve used on this blog post.

joel_preoso_6

Building a double sideband reciever

David, Mark and I sat down one weekend to build a direct-conversion double-sideband (DSB) radio receiver.

Direct-conversion indicates that the desired signal is mixed directly down to baseband using a local oscillator (LO), with no intermediate steps. Double-sideband means that signals above and below our local oscillator frequency are superimposed on each other and output at baseband. Because of this, a DSB receiver can be used as an AM receiver, though we were only using it to receive single-sideband communications.

The design we chose to build was based on the Porta 40, from the November 2012 edition of Amateur Radio Australia by Peter VK3YE. The schematic for the circuit is not online, but an explanation is on YouTube and a similar design is the DC40. The components for the design could be purchased from a local electronics store, which made it attractive for fast prototyping and experimentation. As we couldn’t obtain 7.2MHz resonators quickly, we used 7.158MHz crystals. This limited our tuning range, but this was acceptable for our purposes.

Porta40_coffee

With the parts in hand I built it up on some blank PCB material, starting with the local oscillator. While I built the LO Mark wound the transformers that were required for the mixers. We tested the LO with David’s old HP oscilloscope and found it resonating at 7.143MHz, close enough to the 7.158MHz we were expecting.

Porta40_LO_scope

The pre-amp was pretty straight forward, with the exception of a mistake in the published schematic where the Zener diode was drawn with reversed polarity.

Pre-amp testing

Next up was the mixer. The hardest part of building this part was remembering which of the three windings had to go where. I recommend using different coloured wire for the windings, which reduces confusion and allows the design to be checked before powering on.

Porta40_complete

Finally the audio amp was built, and we tested the entire setup by connecting to the antenna on a pole, and the output to the soundcard on Mark’s laptop. Using some SDR software (Spectravue), we were able to tune to a SSB voice transmission right at the edge of our 24kHz of bandwidth provided by the soundcard. Not only had the design worked first time, but we were about to hear two operators from Victoria having a conversation using the SDR software!

Porta40_sdr

Porta40_decoding

Aside from using it as a single frequency analog voice receiver I plan to use this radio as a downconverter to demonstrate a SDR based implementation of FreeDV of Android.

Thanks to Peter VK3YE for publishing his design, and to David VK5DGR and Mark VK5QI for their help building and testing the radio.

How warm is my beer?

A few weekends ago I went around to Andrew’s place to brew some beer. He’d been given a Coopers Homebrew Kit for his 21st birthday which hadn’t been used, so after replacing the hopped malt concentrate that had expired a few years ago, we set about sterilising the brewing vessel, boiling the water, adding the sugar and concentrate and finally the yeast.

beerlog_brewing

The instructions suggest that the particular strain yeast will ferment best between 21 and 31°C. There’s a stick-on heat sensitive sticker that gives some indication of temperature, however if this is covered by a warming blanket, it’s a bit hard to read. Also, it doesn’t do a good job of measuring fluctuations over time, leaving us with questions such as was the mix getting too cold overnight?

beerlog_setup

Luckily, I had a Arduino shield that I assembled at linux.conf.au: the Pebble. Designed by Luke Weston of MobSenDat fame, and put together as a kit by Jon Oxer and his colleges at the Melbourne hackerspace. The features we used were the DS18B20 temperature sensor and the 4-line LCD display. The Akio scheduling framework was used to poll the temp sensor and update the display with the current, minimum and maximum recorded temperature. The current reading is also sent down the serial port for logging. The Arduino sketch can be found here.

beerlog_lcd

An OLPC XO-1 was used for the logging and to provide power. This meant that we could have monitored it over the network; my plan was to use David’s HOWTO to set up a Munin graph. This didn’t eventuate for this brew, but perhaps will be implemented for the next.

beer-plot

Post-fermentation we took a look at the logged data. As can be seen below, there is a daily cycle as the day/night ambient temperature change occurs. There is also an overall downward trend. As the yeast metabolises the sugars into ethanol, I imagine they become less active over time and hence give off less heat. Or it could have just been a warm day followed by successively cooler days (probably not though – brewing started on the forth. But perhaps Andrew was running his air conditioner?). Another addition for next time would be to I will look at the correlation between the logged data, daily temperature and room tempature.