December 1, 2012

What interesting stuff can you do with a wideband software-defined transceiver? This question started bugging me when I got access at work to an N200 USRP with a WBX daughter board. The N200 is a DAC/ADC motherboard that can stream up to 50M samples per second to/from a computer using a gigabit Ethernet cable, and the WBX is an up/down converter that covers 50 to 2200 MHz. Together, they can receive and transmit signals with bandwidth of up to about 25 MHz almost anywhere in the VHF and UHF bands.

The coolest thing I could think of is to transmit digital television in a standard format that could hopefully be received by normal televisions, set-top boxes, and USB TV dongles. I almost succeeded, and this post tells the story. (For the impatient, here is the summary: I managed to transmit digital TV to a standard dongle, but in order to do this both legally and ethically, I had to hack its driver a bit; the video is jumpy, but it’s there.)

Standard and Frequency Selection

Choosing a digital video standard to transmit was easy. The on-the-air TV stations here transmit DVB-T (a widely-used standard for terrestrial digital TV), and I already had a DVB-T USB donble (which I used as an SDR receiver up to now), so the obvious choice was DVB-T.

Selecting a frequency to transmit is more of a problem, because the easy choice is not a good choice. Terrestrial digital TV is transmitted in VHF and low-UHF channels, from 50 to 862 MHz. DVB-T channels are 6, 7, or 8 MHz wide. The only amateur band within this range that is wide enough is the 430-440 MHz band, and it’s only 10MHz wide here; in other parts of the world it covers 420-450 MHz. If I transmit DVB-T within these 10 MHz, I will transmit over many other signals, including satellites, repeaters, and simplex channels, so this band is really not an option. The next band up is 1240-1300 MHz, which is both wide enough and almost completely unused here, except for some EME usage near 1296 MHz. So the choice is easy; I have to transmit at 1.2 GHz. But DVB-T receivers won’t tune that high, given that all of the channels are at 862 MHz or below, so it’s a choice with a problem.

Still, I knew that my DVB-T dongle can physically tune up to 1700 MHz (this is also true for many other dongles, and I image also for many set-top boxes and built-in tuners in TVs). So I decided to transmit at 1.2 GHz and to try to force the dongle to tune.

I thought that it would be easier to convince the dongle to receive at 1.2 GHz on Linux than on Windows. I managed to do it on Linux and it was not hard; I still don’t know if this is possible at all on Windows, and if it’s possible how difficult it is. But the main thing for now is that it’s manageable on Linux.

Preparing for DVB-T Reception on Linux

My dongle is based on the Realtek RTL2832U demodulator chip (and on the Elonics E4000 tuner chip). I wanted to use it on a computer running Ubuntu 12.04; the Linux kernel in Ubuntu 12.04 does not support this dongle. This turned out to be a blessing in disguise, however.

Hubert Lin’s blog shows how to install the driver on Ubuntu 12.04 (and using a somewhat different procedure, on 12.10). I tried to follow the instructions but the processed failed at some point. Fortunately, Chris Merrett packaged the driver in an easier to install format called DKMS, and he explained how to install it in a comment in Hubert’s blog. I followed the instructions and everything worked just fine. A DKMS driver is installed in a source-code format and this source code is compiled for every version of the kernel that you use. This turned out to be very useful. Installing the driver is very easy:

$ sudo apt-add-repository ppa:chrisfu/rt2832u-dkms $ sudo apt-get update $ sudo apt-get install rtl2832u-dkms

With the driver installed, I installed an Ubuntu package called dvbt-apps, which contains a necessary channel-enumeration utility, and I was ready to try receiving the local on-the-air DVB-T transmissions.

The process starts with a utility called scan. It takes a file containing tuning information for local stations and tries to tune the dongle to them. The station information includes the center frequency, the modulation format, and a bunch of parameters that specify how the transmission is encoded. A DVB-T transmission (station) can transmit multiple channels (simultaneous programs), and scan lists all the channels that it finds within the transmission. I found a file listing the parameters for the local transmissions (at 514 and 538 MHz, transmitting the same channels), ran scan, and it found about 5 TV channels and more than 10 radio stations within the transmissions. Here is the input file to scan (for Israel):

# Initial scan config for Israel # T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy T 538000000 8MHz 2/3 NONE QAM16 8k 1/32 AUTO T 514000000 8MHz 2/3 NONE QAM16 8k 1/32 AUTO

The output looks like this (chopped here for conciseness; the first two programs are TV and the other two are radio):

Ch 1:538000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:2561:2562:1 Ch 2:538000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:2593:2594:2 ... 88FM:538000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:2897:26 MUSICA:538000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:2913:27 ...

Next, I ran the vlc video viewer, providing it with the file that scan produced. I was able to view TV. I also recorded the video+audio stream of one of the channels using vlc in a format called a transport stream in order to try to transmit it later.

Tuning the Dongle to 1.2 GHz

At this point I created a copy of the scan input file and changed the center frequency to a frequency in the 1.2 GHz band. Scan failed; it could not tune the dongle to this frequency. I knew that the dongle can physically tune that high so I assumed that some piece of software was aware of the allocation of DVB-T frequencies and did not allow tuning any higher. I tried various frequencies until I realized that the dongle tunes up to 862 MHz. I searched for this number in the sources of the driver and found one C file that contained the number 3 or 4 times. It was the value for a field called frequency_max in structures that describe the capabilities of the dongle for several digital TV formats, including DVB-T.

I changed the value from 862000000 to 1700000000 and tried to get the driver to re-compile. It took me a while to figure out that the correct process is to remove the driver entirely and then to rebuild and install it.

$ sudo dkms remove -m rtl2832u/3.0.1 --all $ sudo dkms add -m rtl2832u -v 3.0.1 $ sudo dkms build -m rtl2832u -v 3.0.1 $ sudo dkms install -m rtl2832u -v 3.0.1

Now the dongle tuned to 1.2 GHz. Scan obviously did not find any transmissions there, but I was now ready to receive my transmissions.

If somebody can figure out how to get these dongles to tune to 1.2 GHz under Windows, please let me know.

Producing the DVB-T Baseband Signal

There are several software packages on the web that produce a DVB-T baseband signal from an MPEG stream. I used a package called gbDVB written by Giuseppe Baruffa. It comes in binary format only for Windows and Linux, and it can produce (and decode) DVB-T in pretty much any format and modulation. It is fast: it works faster than real time on my desktop (with an i7 processor). I used version 3.3; the latest is 3.4, but it requires a somewhat complicated registration procedure. I did register it, but on Windows, not Linux; I plan to register on Linux and upgrade.

Another option I considered is OpenDVB by Gordon Cichon, which comes in source form and is written in Matlab. It is somewhat harder to use. I plan to try it out in the future.

Before you can use either of them, you need an MPEG (video or audio) file in a format called a transport stream. I generated several of these, always using vlc, a viewer that can also write the movie to a file in various formats. To save a transport stream, I used

vlc movie --sout=file/ts:movie.ts

I called dvbtenco (part of gbDVB) with options that told it to generate a DVB-T transmission using the same format and modulation as the local broadcasts, which I knew work with my dongle.

gbdvb/dvbtenco -i movie.ts -M 16 -m 2k -d t -l movie.log -o movie

This command generates a file called movie.bin with complex baseband samples at a sampling rate of 9.142857 M samples/s. The USRP cannot transmit at that rate (it needs a rate that divides 100 M samples/s), so I used a simple gnuradio-companion program to upsample the signal to by a 70/64 to 10 M samples/s, using a rational resampler.

Putting it all Together

That was basically it. I used a USRP utility to tx_samples_from_file to transmit the 10 M samples/s baseband file at 1.2GHz (actually near 1.3) and I called scan with an input file telling it to look for a DVB-T transmission there. Scan found my USRP transmission and produced an ouput that allowed vlc to tune and display the video I transmitted!

Actually, the video was very jumpy. I think this happened because tx_samples_from_file did not manage to read the baseband file and to send it to the USRP quickly enough. I managed to improve things a bit by converting the baseband file from a floating-point representation (8 bytes per sample) to short integers (4 bytes per sample), but it was still jumpy. Maybe the disk is not fast enough. I’ll try to transmit with a 6MHz bandwidth rather than 8 and hopefully the sampling rate can be reduced, which will shrink the rate at which the samples need to be read from the file and sent to the USRP. I need to investigate.

As I wrote above, dvbtenco runs faster than real time on my desktop, so in theory, I may be able to transmit live video with this setup. But the gnuradio resampler is very slow; maybe I can optimize it and run the whole thing live. But the first step should be to transmit a video from a file without jumps.

Another thing that is still missing is an identification of the program that is being transmitted. This information needs to be multiplexed into the transport stream. I am trying to learn how to do that.