rtl-sdr: Pd, Max and Mac

Notes on compiling rtl_sdr in Mac OS – writing Max and Pd Externals.

 

update 3/31/2014

Today I got the Pd external running – using essentially same source code as Max. There is occasional weirdness going on with audio clicks when starting/stopping the radio, but other than that it seems fine and it runs. wooHOO. More to follow…

 

update 3/28/2014

Now have set up a skeleton for Pd, called rtlfmz~ (inside the Pd application bundle) which does absolutely nothing but compiles all of the project files and calls a function in rtl_fm.  Next step will be to port the actual Max external code and do the conversion.

updates 3/38/2014 before working on Pd version

There is now a fairly solid max external (rtlfmz~) using a recent version for rtl_fm. Also there is a simple Makefile that compiles local version of rtl_fm3.c in:

tkzic/rtl-sdr-new/rtl-sdr/rtl-fm3

There are very minor changes to rtl_fm.c (for includes) and also a local version of librtlsdr.a (librtlsdr32.a) that is 32 bit.

The current state of the Max external does both pre-demodulated and raw IQ output, but you can only run one copy  of the object due to excess use of global variables and my uncertainty over how to run multiple devices, threading, etc.,  – but we’ll go with it an try porting to Pd now.

update 2/27 – converted to using new version of rtl_fm

I had been using an older version of rtl_fm –

renamed external to rtlfmz~ and now using new version as (rtl_fm3.c) in the project

In addition to recopying the librtlsdr.a – I also recopied all of the include files and added two new files

convenience.c convenience.h

There is a different method of threading and reading which I haven’t looked at yet, but it is now doing what it did before inside Max, which is read FM for a few seconds and write audio data to a file

plan: Set up a circular buffer accessible to the output thread and to the max perform function. – then see if we can get it to run for a few seconds.

The main thing to think about is how to let the processing happen in another thread while returning control to max. Then there really should be a way to interrupt processing from max.

There needs to be a max instance variable that tells whether the radio is running or not. Then, when its time to stop – you just do all the cleanup stuff that is at the end of the rtl_fm main() function.

 

update 2/18/2014 – Max external

Now have rtl_fm function within the plussztz~ external

It detects, opens device, demodulates about 30 seconds of FM, and writes audio at 44.1kHz. to a file /tmp/radio.bin – which can be played by the play command

Changes to code included:

  • removing exit calls
  • changing printf to post()
  • removing signal interrupt handling
remaining to do:
  • Need a way to get the device to read in the background – so its not blocking the Max thread
  • Need a way to stop/restrart the device – because if we aren’t, the continual sync_reads will waste a lot of cpu cycles.

update 2/15/2014 – Max external

Have now successfully  compiled a test external in Max 6.1.4 – name is plussztz~ and it includes the rtl_fm code.  Made 2 changes so far:

  • in build settings, set architectures to i386
  • in rtl_fm2, changed <include> libusb.h to “include” libusb.h

original post

Today I was able to write a simple makefile to compile the rtl_fm app using the libusb and librtlsdr dynamic libraries.

Pd requires i386 architecture for externals (i386) so I then compiled the app using static libraries and the i386 architecture.

libusb-1.0 already had a 32 bit version in /usr/local/lib/libusb32-1.0.a (note that this version also requires compiling these frameworks:

-framework foundation -framework iokit

For librtlsdr, I rebuilt, using cmake with the following flags:

cmake ../ -DCMAKE_OSX_ARCHITECTURES=i386 -DINSTALL_UDEV_RULES=ON

But did not install the result. See this link for details on building with cmake: http://sdr.osmocom.org/trac/wiki/rtl-sdr

This produced a 32 bit static version of librtlsdr.a that could be used for building the app.

See this Stack Overflow post for more on cmake and architectures: http://stackoverflow.com/questions/5334095/cmake-multiarchitecture-compilation

local files:

currently local version of this test is in: tkzic/rtl-sdr-tz/rtl_fm2/

The default makefile builds the 32 bit architecture.

Next:

  • try to move the makefile into Xcode
  • try compiling rtl_sdr or rtl_fm as a simple max object – the fm app might be better to start with since it gives an audio signal output.
  • then try in pd

 

 

 

Software Defined Radio in Pd

This is based on the Max tutorials. I have only written one external (for Soft66LC2). But everything seems to be working well with minimal filtering. After watching the video, I think the next feature should be an AGC (automatic gain control) on the input stage.

converting IQ audio files using sox

To get information about a file:

# sox --i 10meter96.wav

Input File : '10meter96.wav'
Channels : 2
Sample Rate : 96000
Precision : 16-bit
Duration : 00:00:16.50 = 1584387 samples ~ 1237.8 CDDA sectors
File Size : 6.34M
Bit Rate : 3.07M
Sample Encoding: 16-bit Signed Integer PCM

#

To convert the sample rate:

# sox 10meter96.wav -r 44100 10meter44.wav

More useful hints about sox by Selvaganeshan at “The Geek Stuff”

http://www.thegeekstuff.com/2009/05/sound-exchange-sox-15-examples-to-manipulate-audio-files/

Here are the commands that worked to get the raw IQ data from rtl_sdr into Max

rtl_sdr -f 94900000 -s 1024000 -g 50 iq.raw

To convert the above to 96k 16bit wav format

sox -e unsigned-integer -r 1024k -t raw -b 8 -c 2 iq.raw -r 96k -b 16 iq.wav

Note: I could not get the above conversion to work with device sampling rates below 1024k. Didn’t try anything higher.

 

 

near-ultrasound data transfer in Max using FSK (rtty)

An example of sending data through the air, from one computer to another, using sound. The carrier frequency – 18Khz – just below ultrasound, is inaudible to most humans. The data protocol is Audio Frequency Shift Keying (AFSK) at 45 bits/second. It uses two tones – to encode 1’s and 0’s. This protocol was developed for radio teletype (rtty).

One computer sends the word “hello” to the other computer every 10 seconds.

The idea came from a paper by Michael Hanspach and Michael Goetz – “On Covert Acoustical Mesh Networks in Air” – http://www.jocm.us/uploadfile/2013/1125/20131125103803901.pdf. In the paper they explain that the concept was borrowed from current technology for underwater data networks. They warn of the vulnerability of “air-gapping” as a method of computer security.

Actually, after watching the video I realized its difficult to make exciting videos that feature sounds you can’t hear. Especially when you are whispering. Well, the pro camera crew should be knocking on the door at any moment.

download

https://github.com/tkzic/max-projects

folder: frequency-shift-keying

patches:

  • rtty-recv12.maxpat
  • rtty-send12.maxpat
javascript files:
  • rtty-encode10.js
  • rtty-recv9.js

Notes:

To run patches:

  • in rtty-send12 set carrier frequency to something like 200
  • then toggle start/stop
  • You may want to increase the speed to 32
  • On the receive side, clear the text box
  • Make sure to set audio as described below

In audio settings try

  • io vector = 512,
  •  signal vector = 32,
  •  overdrive and audio-interrupt should be enabled,
  •  SR=96 Khz.

Interesting discovery – or maybe a coincidence. Bit rates which are powers of 2 seem to work way better than arbitrary speeds.  I wonder if its because the signal vector size is also a power of 2?

Going from a direct audio connection to an through-the-air connection led to a number of issues with filtering and and levels.  The latest version of the Max patches have been organized into modules, like: encoder, transmitter, decoder, phasor-clock, etc., But they would benefit from some encapsulation.

It was interesting that throughput was better above 14Khz. Possibly due to less interference from environmental sounds – and less critical filtering. During the video I was able to talk (whisper), without interfering  with data transfer. But if I squeaked a chair or tapped the desk, it would screw-up. Also, the builtin mic/speaker on MacBooks have response curves that are all over the place.

The next version will have sharper filters and an automatic level control (compressor).  There’s  difficult interaction in the detection process between filtering and timing. Up to this point I’ve been reluctant to use frequency domain filtering due to loss of timing resolution. Latency is ok though. But the other thing is that we don’t want filters which soften or distort the shapes of the pulses.

So one question is how high can you go – with the built-in mic and speaker. They are not rated above 20 Khz. but you never know?

 

FM, AM, and SSB modulation/demodulation in Max

This is a radio – but also a modem, in a literal sense of the word. You may be familiar with AM and FM. Have your tried using them backwards?

In this patch, an audio signal is modulated using SSB, AM, and FM then frequency shifted to about 1/4 the nyquist frequency. Then the process is reversed revealing the original audio.

notes

Have improved and simplified FM and AM detection. There is no frequency shift prior to detection. This eliminates some phase distortion.

Pd Version. (runs at 44.1 kHz, because I was too lazy to figure out how to do audio file playback which detects the SR of the audio file.

FM detection: The DC offset and makeup gain levels are sensitive to carrier frequency and SR. Will need to automate these corrections to prevent audio output problems.

download

max-projects: https://github.com/tkzic/max-projects

folder: demodulation/max

  • modem3.maxpat
  • obama.aiff

folder: demodulation/pd

  • modem-pd.pd
  • freqshift-abs~.pd
  • obama.aiff

 

RTTY at 300+ bps in Max

notes

After a few vexing timing issues I have been able to send and decode RTTY (technically AFSK audio frequency shift keying ) in Max at 300 baud. Click hear to listen to an example of a 13 word message at 300 bps (300 baud)

The js object adds significant delays (on the order of a few milliseconds) – so I replaced the encoder with a coll and that cleaned up the timing problems when encoding. This patch demonstrates the issue:

Also… You can use threshold~ instead of snapshot~to feed binary pulse amplitude detection logic into edge~ – but you need to run the signal through average~ to prevent the amplitude from repeatedly dropping to zero at the signal frequency. Like this:

Is it better than snapshot~? it seems to be, but who knows – at these speeds it would probably be better to write the whole thing in gen~

There are a few other things – like using counter~ instead of phasor~ to drive the decoder clock. This allows you to restart the clock, when the onset of the start bit is detected – and you can add a variable amount of delay to find optimal point in the signal vector to read the pulse. At 300 bps, at 96k SR, each pulse is 320 samples (3.1 milliseconds) –

I’ll write more on this later –

The Katja Vetter article on Beat-Slicing was helpful – along with several Max tutorials on Audio control rates, and envelope followers.

Local Patches are in;

tkzic/ max teaching examples/

  • rtty-send10.maxpat
  • rtty-recv9a.maxpat