How to easily write a GNU Radio Signal Processing Block and understand the architecture
Windows and Linux
GNU Radio these days works on Windows and Linux systems. So I started using the new cmake based build system on both systems. You can use VisualStudio to write Signal Processing blocks. Alternatively of course you can use cmake to generate Code::Blocks or CodeLite projects. So from a developer's perspective this means freedom: use what you like best.
In the following this is about how to utilize cmake after a Windows installation to bring a Signal Block into VisualStudio 2010 (setting variables to let cmake track all the necessary dependencies). Also it's about understanding the architecture of GR. I keep is very concise here, but hopefully not to short. The next part will be about working with the block-template.
GR architecture
GR has a Layers architecture.
- You have a radio peripheral device, let's say a USRP2. In that case these days you use the UHD device drivers which utilize UDP/IP. Otherwise a USRP1 uses USB.
- Either way these radios pass vectors (discrete values, bytes) to the GR Scheduler which keeps a ringbuffer of vectors accessible to your signal processing logics
- the signal processing logic which remains with the GR Blocks.
- the illustration names Vn as vector n, and mentions that the ringbuffer might increment n to remove vectors that are unnessary - to push them out of the buffer's ring. At the blocks you iterate over a continous stream of vectors via (Boost) Shared Pointers that refer to Vn. Concretely this is in[i] or out[i]. Where i iterates over the Vn, Vn+1 sequence within the stream.
- Vn is controlled by the ringbuffer, but depending on your inherited Block class the ringbuffer changes. You can either just rewrite some vectors and apply your math in sync, decimate or interpolate, or just consume. You tell the GR Scheduler what you want by inheriting from the appropriate C++ class.
- the GR Top Block connects Block instances into a Flow-Graph. This means your Signal Processing Scheme consists of multiple blocks, connected, and some parameters (sample-rate, USRP IP, interpolation and what not).
- the language interoperability (data-types need to be rewritten e.g.) is done with SWIG. You can also implement entire new blocks in Python. But this is not jet as fast as the C++ stuff with Boost'ed coolness. And this not just the Python vs. C++ prejudice.
- in short this is like a clockwork: imagine the GR Scheduler like a cog-wheel that is transporting the bytes (vectors) into the Blocks. These blocks are cog-wheels again, which are build with more, less or equal prongs (faster, slower - consume, produce, in sync). While all cog-wheels are instances of a whole greater logic that is the Flow-Graph in the Top Block.
- for the vocabulary: an item in GR is a "vector" that is passed between the Blocks.
Writing a new block therefore has a number of issues:
- language interoperability: SWIG interfaces need to be written
- GR has a load of dependencies, but I mentioned Windows & Linux (GNU stuff on Windows)
- there's some performance impact. That in short means no Cygwin or something.
- It needs a concrete example. DSP for software developers is a challenge. Since we are not accustomed to think of these low-level interactions. Modelling these in OOP is pretty amazing though.
- While we are at it: the GNU Radio companion is a Model Driven Development environment. We will write a block that extends the GRC library. This needs XML. The GRC abstracts the Top Block again by letting you design a transmission scheme (Flow-Graph) in a UML like manner. It generates an XML file to hold the connections and parameters and uses this XML file for Python code-generation.
- We need some C++ (Boost libs, OOP, inheritance), Python (OOP, special APIs, SWIG interface operability), XML (just some definitions on an XML scheme), basic networking skills (static IP setup on Windows, maybe some network analysis) and last but not least cmake and your IDE - in my case VisualStudio 2010. In short: some awesome developer who knows his stuff.
Dependency tracking- Oh my ...
Please take your time here to read carefully what is in the readmes. This is not easy. Remember to restart cmake if you change your PATH variable.
- Josh Blum has a GNU Radio installation manual for Windows. There's a port in MacPorts and your favorite Linux distribution (Fedora, Ubuntu, Arch AUR, gentoo), too. You may want to build it manually. On Windows I cannot recommend this - although is is possible.
- make sure you have at least GR 3.4 anyway
- install Git (on Windows mysysgit and SmartGit(r) (free for non-commercial use))
- set your PYTHONPATH with the Rapid Environment Editor or on Linux/Mac via Terminal to meet the gnuradio/lib/site-packages. You can also use Powershell on Windows.
- LXML and Cheetah are harder to build on Windows, even with easy_install. This fails sometimes... but here are setup files. Use the base and lxml pack and you're done.
- fire up your Terminal and start gnuradio-companion(.py)
- if that worked you have all the runtime dependencies. That doesn't mean you have all the developer dependencies.
- install cppunit. I don't know why, but the distribution of cppunit is inadequate to say the least... Use the SVN, because the developer chose not to distribute his work and just threw it on the internet. Anyhow, this happens from time to time. Just as a hint: there will be build errors. Don't mind that. It's dead code anyway.
- install Boost stuff cmake asks for. Unit test stuff etc. Yes, it may be 1 GB or so.
- just in case you compile more than just the howto block: make sure you manually link the MinGW cross-compiled libfftw libs with the mentioned lib command (lib /def:libfftw3-3.de, lib /def:libfftw3f-3.def, lib /def:libfftw3l-3.def). Same thing with GSL. This is important because we are using VisualStudio here later with its native compiler. It's recommended to stay x86 here.
- if that worked install SWIG (from here). It needs to be put into PATH.
- git clone the current master and copy the gr-how-to-write-a-block-cmake
- fire up cmake-gui, source folder is the mentioned block-howto folder. build is a new sub-directory build.
- and take a look at the screen-shot. I build most stuff into ~/Documents and that's where I made cmake resolve the dependencies mentioned.
Now that was fun, wasn't it? Yes... this is it. You never need to touch these dependencies again for a while. cmake generated a VisualStudio project file. We open it and voilà:
Quadrature Demodulator - a DSP example
The Quadrature Demodulator is used to demodulate FM, GMSK or oQPSK for example. - So to receive Bluetooth (802.15.1) or Zigbee (802.15.4) signals. With GR you can implement the entire protocol stacks in Python, after receiving the bits. It's not restricted to signal level.
Take a look at this Flow-Graph on GRC (doesn't need a USRP btw.):
The Quadrature Demod Block at the bottom is equivalent with the Multiplication and Complex-conjugation above. This is one way to represent this. Here's the same in C++:int
gr_quadrature_demod_cf::work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
gr_complex *in = (gr_complex *) input_items[0];
float *out = (float *) output_items[0];
in++; // ensure that in[-1] is valid
for (int i = 0; i < noutput_items; i++){
gr_complex product = in[i] * conj (in[i-1]);
// out[i] = d_gain * arg (product);
out[i] = d_gain * gr_fast_atan2f(imag(product), real(product));
}
return noutput_items;
}
This is a sync block. The number of items it outputs are equal with the input's. So the GR scheduler doesn't need to remove or add any space for vectors in the sequence.
Let's say for research purposes we now want a higher delay. And for performance reasons we don't want to set this via the Flow-Graph above but embed this in one C++ block file. We need to rename the block, change the work method, and delete some of the clutter around the howto-came block. You can easily do this from within the VS project-explorer now. Ensure that you add the GR source as dependency to resolve the headers.
To be continued: the next part very soon will cover renaming blocks using the cmake-howto file form the current GR master.
Have fun,
wishi

