This article is currently an experimental machine translation and may contain errors. If anything is unclear, please refer to the original Chinese version. I am continuously working to improve the translation.
0x00 Preface
After hitting a wall in my RTL-SDR experiments (due to lack of open space for antennas), I gave up on buying a HackRF for further exploration.
However, during my research, I stumbled upon some rather creative — let’s say “wild” — SDR transmission methods that piqued my interest, prompting me to write this post.
Transmitting radio signals may very well violate local radio regulations. Before attempting any of these, make sure you're familiar with your country's laws and have sufficient knowledge of radio operations. Please refer to the warnings at the end of this article and in the respective project documentation.
0x01 rpitx
This is an SDR implementation for Raspberry Pi boards that only requires a compatible Raspberry Pi and optionally a short piece of wire as an antenna to transmit signals from 5kHz up to 1500MHz.
The author’s GitHub repository F5OEO/rpitx demonstrates several use cases, but doesn’t go into much detail about how it actually works. The only technical resource I found was a YouTube video by the author himself introducing the project — definitely worth watching if you’re curious.
(TL;DR: The author controls the frequency switching of the Broadcom BCM2835’s PLL across multiple selectable frequencies to simulate arbitrary output signals, and uses DMA to maintain a stable sample rate.)
Despite my usual complaints about the Raspberry Pi’s weak performance, limited I/O, and high price, its software support is indeed solid. So I immediately grabbed a Raspberry Pi Zero to run some tests. (p.s. In hindsight, a Pi Zero W would’ve been more convenient — no need for an extra USB Wi-Fi adapter.)
After installing Raspberry Pi OS and connecting to the internet, I simply cloned the rpitx repository and ran install.sh for a one-click setup.
I tested the official examples within China’s 430–440MHz amateur band, using an RTL-SDR as the receiver placed right next to the Pi:
The chirp example generates a sweeping signal peak near the specified frequency
Broadcasting a short audio clip via FM at 434.5MHz
As seen in the spectrum, aside from the intended signal at 434.5MHz, there are many other “noisy” spurious signals nearby. However, if the receiver is slightly farther away, only the target frequency remains visible.
At less than 2 meters away, noise signals are gone — only the target band remains (other peaks are from surrounding devices, not the Pi)
Of course, without any antenna, the signal becomes nearly undetectable beyond 10 meters.
In addition to the dozen or so examples provided, the author also includes a handy tool called sendiq, which can replay captured or externally generated IQ files (though due to the nature of this transmission method, the maximum sample rate is capped at 250kS/s, limiting the theoretical bandwidth to 125kHz):
1 | sendiq -0.2 |
0x02 osmo-fl2k
If RTL-SDR and rpitx feel like reasonable hacks, then osmo-fl2k is the kind of idea that makes you blink twice and question your sanity.
This project turns a USB3.0-to-VGA adapter (??) into an SDR capable of transmitting signals at up to 155MS/s. And because VGA outputs lack low-pass filters, we can exploit harmonics to reach frequencies far beyond the native 165MHz — such as simulating GPS signals up to 1575MHz.
You're reading that right — this little dongle, available online for under $30, is what we're turning into an SDR
As detailed on its project homepage, osmo-fl2k reverse-engineered the USB communication protocol of the Fresco Logic FL2000 chip, allowing custom data packets to generate arbitrary analog signals. (When you think about it, VGA is inherently a high-frequency analog signal, so the chip is basically acting as a DAC — not that crazy after all.)
Of course, when shopping for adapters, you must get one with the FL2000 chip. Nowadays, USB-to-VGA adapters come in two common variants: MS2160 and FL2000. The annoying part? They often come in identical enclosures, making visual identification impossible. Even sellers might not know what’s inside — I managed to buy the wrong one three times in a row.
The official guide suggests looking for products labeled as “USB3.0 to VGA”, not supporting macOS, and mentioning specs like “1920x1080 in USB3.0 mode, 800x600 in USB2.0 mode” — those are likely FL2000-based.
But honestly, this method isn’t reliable — many sellers copy descriptions or never update them. I bought one explicitly labeled as macOS-incompatible, only to find it worked perfectly on Mac — and sure enough, it had the MS2160 chip. Following that guideline, I ordered three in a row — all wrong.
Since USB3.0-to-VGA is a niche product, here’s a pro tip: go straight to 1688 and search for FL2000. Many suppliers list the actual chip model, and if they do, it’s usually accurate. You can also ask customer service — as wholesale vendors, they tend to know exactly what they’re selling.
After several rounds of trial and error (and four delivery attempts), I finally got my hands on the correct adapter. As the title suggests, it’s time to spoof some GPS signals.
No need to install the original driver. On Windows, just use Zadig to install a libusb driver, then download the pre-built Windows binaries from their git CI and you’re good to go.
First, run fl2k_test to check device detection and find a stable sample rate.
1 | $ ./fl2k_test.exe -s 158e6 |
My device managed around 155MS/s, close to the wiki-reported average, likely limited by USB3.0 bandwidth. But PPM fluctuation was wild, leading to unstable signal transmission — so I manually lowered the rate.
1 | $ ./fl2k_test.exe -s 138e6 |
After closing background apps and unplugging unnecessary USB devices, the PPM stabilized significantly at 138MS/s. I decided to go with 138MHz sample rate and a PPM offset of 130. GPS receivers are frequency-sensitive, so stability is key.
Using the GPS example from fl2k-examples, I generated a spoofed GPS signal IQ file with gps-sdr-sim:
1 | gps-sdr-sim -e brdc0660.25n -l 30.0,125.0,100 |
Here, brdc0660.25n is a RINEX-format ephemeris file from NASA’s daily GNSS broadcasts — available at NASA’s website (or you can use the outdated one included in the repo if you’re lazy). The three values specify the spoofed latitude, longitude, and altitude.
This generates a file named gpssim.bin. But our FL2000 can’t transmit this directly — we need GNU Radio. Open the provided .grc file from the repo and process gpssim.bin.
Remember to update the PPM variable in the top-left corner with your measured value, and set input/output file paths
After processing, the resampled .bin file is ready for transmission:
1 | fl2k_file -s 138e6 gpssim_resample.bin |
I tested with two receivers:
The first was a GPS module connected to my PC via USB-to-serial, equipped with a dedicated antenna. It acquired the signal quickly — within about ten seconds — and successfully locked onto the spoofed location when the FL2000 was within half a meter.
PC receives strong GPS signal and locks onto the fake position
The second was my smartphone. Mobile GPS reception was trickier — I had to press the phone right against the adapter and wait a few minutes for it to gradually lock onto the fake coordinates.
The phone's built-in GPS also picked up the spoofed satellites, showing location at 30.0,125.0 (which, on a map, places it floating over the ocean)
0x03 Summary & Warnings
Honestly, I never expected a VGA adapter could spoof GPS signals. These methods are clearly hacky, but they’re more than enough for small-scale experiments — and cost one to two orders of magnitude less than professional SDR gear.
That said, both methods produce significant harmonics and out-of-band noise. osmo-fl2k relies on harmonics to reach high frequencies, and rpitx’s PLL square wave naturally generates spurious emissions. If transmitted via an antenna without filtering, these signals can interfere with legitimate radio services — and might attract unwanted attention from regulatory authorities. So for serious applications, just buy proper equipment.
All my tests were conducted indoors, using minimal wire antennas. The signal range was limited to a single room, and I stopped transmission after just a few minutes.
This article is licensed under the CC BY-NC-SA 4.0 license.
Author: lyc8503, Article link: https://blog.lyc8503.net/en/post/hacky-tx-sdr/
If this article was helpful or interesting to you, consider buy me a coffee¬_¬
Feel free to comment in English below o/