Rendering PCM with simulated phosphor persistence

When PCM waveforms and similar oscillograms are displayed on screen, computational speed is often preferred over beauty and information content. For example, Audacity only draws the local maximum envelope amplitude and (what appears to be) RMS power when zoomed out, and when zoomed in, displays a very straightforward linear interpolation between samples.

Here's the startup beep of my Kenwood TK-2302, rendered by Audacity:

[Image: Screenshot showing the oscillogram viewer of Audacity. 500 milliseconds of a signal is shown, beginning as a thin line that suddenly makes a positive rise, a slightly slower fall and then changes into a wide, solidly filled surface, with a lighter color in the middle.]

Analogue oscilloscopes, on the other hand, do things differently. An electron beam scans a phosphor screen at a constant X velocity, lighting a dot everywhere it hits. The dot brightness is proportional to the time the electron beam was directed at it. Because the X speed of the beam is constant and the Y position is modulated by the waveform, brightness gives information about the local derivative of the function.

Of course, PCM is all about "dots" as well, so we could possibly mimic this behavior digitally. I'm going to simulate an electron beam by first oversampling the above waveform by an insane amount – at 1 megahertz, that is. Lowpass filtering follows, with a cutoff frequency at the Nyquist frequency of the original PCM. Now, a program reads in the processed PCM and for each sample will make the corresponding dot on the XY plane a little brighter. (Actually each sample will affect 4 image pixels because of bilinear interpolation.) This method gives us a much more interesting rendering:

[Image: An oscillogram with the same features as in the above picture, but the solid surface appears transparent and there are variations to its brightness in both X and Y directions, revealing structures not present in the above image.

Now how cool is that? It looks like an X-ray of the signal. We can see right away that the beep is roughly a square wave, because there's light on top and bottom of the oscillation envelope but mostly darkness in between. Minute changes in the harmonic content are also visible as interesting banding and ribbons.

At very high zoom, Audacity doesn't even bother reconstructing the actual waveform but just thinks of it as a "connect the dots" puzzle. This is computationally feasible, of course. Oversampling at 3,000,017 Hz and downpass filtering at the original Nyquist frequency, on the other hand, results in an apparent reconstruction of the analogue wave:

[Image: An Audacity oscillogram zoomed in so much that only a few dozen samples span the picture. Samples are drawn as dots that are connected by straight lines. Below it, another oscillogram of the same waveform, with a smooth waveform passing through all the samples.]

Finally, the soprano section of the Finnish Radio Chamber Choir singing a D note in a piece by Einojuhani Rautavaara:

[Image: An oscillogram of a signal varying in both time and frequency, revealing inner structure as brightness variations.]

Relevant code for scientific interest in this Gist.

Eavesdropping on a wireless keyboard

Some time ago, I needed to find a new wireless keyboard. With the level of digital paranoia that I have, my main priority was security. But is eavesdropping a justifiable concern? How insecure would it actually be to type your passwords using an older type of wireless keyboard?

To investigate this, I bought an old Logitech iTouch PS/2 cordless keyboard at an online auction. It's dated July 2000. Back in those days, wireless desktops used the 27 MHz shortwave band; later they've largely moved to 2.4 GHz. This one happens to be of the shortwave type. They've been tapped before (pdf), but no proof-of-concept was published.

I actually disposed of the keyboard before I could photograph it, so here's a newer Logitech S510 from 2005, still using the same technology:

[Image: Photo of a black cordless QWERTY keyboard with a Logitech logo.]

Compared to modern USB wireless dongles, the receiver of the iTouch is huge. It isn't a one chip wonder either, and contains a PCB with multiple crystal oscillators and decoder ICs. Based on Google results, one of the Motorola chips is an FM receiver, which gives us a hint about the mode of transmission.

[Image: On the left, a gray box with the Logitech logo, a button labeled 'CONNECT', and a wire coming out of it, ending in two PS/2 connectors. On the right, the box opened and its PCB revealed. On the PCB there are three metal-colored crystals (16.4200 0014TC, 10.1700 0011TC3, 10.2700 HELE), two bulky components labeled LT455EW, and three microchips with Motorola logos. An array of wires goes out.]

But because eavesdropping is our goal here, I'm tossing the receiver. Afterall, the signal is well within the 11-meter band of any home receiver with an SW band. For bandwidth reasons however, I'll use my RTL2838-based television receiver dongle, which can be tuned to an arbitrary frequency and commanded to just dump the I/Q sample stream (using rtl-sdr).

The transmission is clearly visible at 27.14 MHz. Zooming closer and taking a spectrogram, the binary FM/FSK nature of the transmission becomes obvious:

[Image: Spectrogram showing a constant sinusoid and, below it, a burst of data encoded in the frequency of another sinusoid.]

The sample length of one bit indicates a bitrate of 850 bps. A reference oscillator with a digital PLL can be easily implemented in software. I assumed there's a delta encoding on top of the FSK.

One keypress produces about 85 bits of data. The bit pattern seems to always correlate with the key being pressed, so there's no encryption at all. Pressing the reassociation button doesn't change things either. Without going too much into the details of the obscure protocol, I just mapped all keys to their bit patterns, like so:

w 111111101111011111101111101101011011100111111111001111111101111011111101111101101
e 111111101111011111101111110101011011100111111111001111111101111011111101111110101
1 111111101111011111101111110110110111001111111110011111111011110111111111110110110
2 111111101111011111101111110110111111100111111111001111111101111011111101111110110
3 111111101111011111101111111010111101001111111110011111111011110111111011111110101
7 111111101111011111101111111110110110110011111111100111111110111101111111011111111
8 111111101111011111101111101110111110011111111100111111110111101111110111110111011
9 111111101111011111101111101110110101100111111111001111111101111011111101111110110
0 111111101111011111101111110110111011001111111110011111111011110111111011111101110
u 111111101111011111101111111101011110011111111100111111110111101111110111111110101
i 111111101111011111101111111101010111001111111110011111111011110111111011111111010
                                                               6,8              40% 

The bitstrings are so much correlated between keystrokes that we can calculate the Levenshtein distance of the received bitstring to all the mapped keys, find the smallest distance, and behold, we can receive text from the keyboard!

$ rtl_sdr - -f 27132000 -g 32.8 -s 96000 |\
> sox -r .raw -c 2 -r 96000 -e unsigned -b 8 - -t .raw -r 22050 - |\
> ./fm |perl
Found 1 device(s):
  0:  Realtek, RTL2838UHIDIR, SN: 00000013

Using device 0: ezcap USB 2.0 DVB-T/DAB/FM dongle
Found Rafael Micro R820T tuner
Tuned to 27132000 Hz.
Tuner gain set to 32.800000 dB.
Reading samples in async mode...

So, when buying a keyboard for personal use, I chose one with 128-bit AES air interface encryption.

Update: This post was mostly about accomplishing this with low-level stuff readily available at home. For anyone needing a proof of concept or even decoder hardware, there's KeyKeriki.

Update #2: Due to requests, my code is here: fm.c, Of course it's for reference only, as it's not a working piece of software, and never will be. Oh and it's not pretty either.

RDS display on a Raspberry Pi

Earlier I modified my radio to output raw bits from its RDS decoder chip. The radio already displays a Programme Service name, but for FM DX purposes, it's fun to see more data. Also, the Programme Identification code can be decoded from very weak signals, identifying distant stations. And I can receive interesting traffic information messages by decrypting RDS-TMC with the encryption keys I've recovered. Now that I have a Raspberry Pi, it's time to make a dedicated little display.

First, I changed the radio connector from my previous modification. This one, salvaged from a mystery phone device I found at a flea market, doesn't come loose as easily as the Mini-DIN:

[Image: A corner of a radio labeled 'SANGEAN', with a hole cut in it and a phone connector in the hole. A phone connector is being held next to it.]

I bought a discount 2x16-character HD44780-compliant LCD at the local parts store and made a 4-pin connection to the Raspberry Pi GPIO header. I used another two GPIO pins to interface the Pi with my radio (one for data, one for clock). I then wrote a C program to read the 1187 bps RDS data, process it for error correction and synchronization, and output it to a Perl script for interpretation. The script then returns a text string to be displayed on the LCD. The bcm2835 library is used for GPIO interaction.

Turns out GPIO is not very good for data rates this high. The C program takes about 5 samples per RDS clock cycle, and uses 97 % of the CPU time. With the Perl script and LCD update running, the poor Pi can't keep up with realtime data, and lots of bits are lost. But after waiting patiently, I finally get a Programme Service name, Programme Identification code, and RadioText.

On the left, my radio. On the right, the RasPi in its doghouse:

[Image: The same radio as above, but now its LCD display and dozens of buttons are shown. On the display, the text '87.90 YLE YKSI', the time 18:41, and indicators 'FM', 'Stereo', 'RDS', 'HOME', 'Page 1'. A cable goes from the radio to a device on the right which is contained in a little thrash can of sorts. The device has a small LCD display that reads 'YLE YKSI 6201 Kultakuume'.]

Experimenting with lower sampling rates will hopefully alleviate the problems. But it kind of works already.

Update 2013-04-01: According to this benchmark, this very library should be able to handle GPIO speeds of several megahertz. So I tried running the program in strace to see what it's doing to burn so much CPU. Turns out it's sitting in a single nanosleep() call and never returning!

I experimented a bit and ended up replacing all calls to bcm2835_delayMicroseconds() (which uses nanosleep()) with calls to usleep(). And it works! CPU utilization is at 10% maximum, and a PS name appears lightning fast when changing stations. So, something was probably wrong with nanosleep() or bcm2835's implementation thereof.

Beyond the hiss

The tape on a compact cassette imposes all kinds of noise and distortion on a recorded signal. Much of it is so quiet that it's practically inaudible, but with some signal processing we can zoom into some fascinating details.

[Image: A spectrogram, 0 to 22 kHz, of a 5-second test signal recorded on a cassette tape and played back.]

(There's a high-res version of the enclosed infographic at Dropbox.)

I generated a test tone that sweeps from 50 Hz up to 21 kHz in 5 seconds, then recorded it onto a cassette. I played the tone back and plotted it above, in turquoise. I also monitored the "dry" signal passing through the circuitry and plotted it in red, to see what was actually caused by the tape.

There's a prominent banding that seems to follow the rising frequency of the tone. The pattern, with its mirrored sidebands, looks very similar to a frequency-modulated carrier, and that's effectively what it is. The tone frequency is being modulated by rapid fluctuations in tape speed during recording and playback, also known as flutter.

Another persistent signal is visible in the leftmost part of the picture, or the low part of the spectrum. It's the humming sound of the power grid, 50 Hz in this part of the world, leaking to the tape because of an unwanted ground loop somewhere in the circuit. Ultimately, it's the sound of the steam turbine rotor turning at the nearest power station. The hum has several harmonics at integer multiple frequencies.

Some harmonic multiples of the test tone are also visible. These are caused by gross distortion of the original waveform, most probably by magnetic saturation (clipping) of the tape media, or they may be crossover distortion from an amplifier stage. The harmonics are repeated in the end of the sample as a zig-zag pattern, which is probably a digital aliasing artifact.

The noise floor on the cassette is set by what is commonly known as tape hiss. It is caused by the finite size of the magnetic particles that the audio is recorded on. This is similar to the grainy pattern on an enlarged film photograph, or pixels in a digital one. A faster-running tape will have more hiss, but at the same time can record information at a greater bandwidth.