Creating a simple radio

In this chapter you'll learn how to create a very simple radio consisting of a transmitter and a receiver. You should know the very basics of a digital transmission. For a short introduction in this matter, you can also go and read chapter <ref>cha:signal flow</ref>.

In figure <ref>fig:first_radio</ref> you see the goal of this tutorial: two radios, called Master and Client with the following functions:

  • Master: send the synchronisation, training-sequence and an image
  • Client: synchronize, do a channel estimation and decode the image

Graph
A very simple radio

Both the master and the client can be represented by a simple chain. So it will be very easy to implement these two radios as shown in the rest of this tutorial.

After explaining some more general things about the software-radio, we'll explain first the master, then the client. You can find the basic files with all the basic setup already done in the sub-directory Radios/ICS_Simple of the SRadio-project. Master/radio_master.c contais the basic setup of the master and Client/radio_client.c the basic setup of the client.

General Setup

This section is just a very brief introduction to the software-radio. For a more complete overview, follow the references. First some overview of the software-radio, then an explanation of the C-files.

Overview

As explained in chapter <ref>cha:modes of operation</ref>, the software-radio can be run either in simulation- or in real-time-mode. While it is possible to have both the master and the client on the same computer in simulation mode, this is not possible in real-time mode. The first part of this HOWTO works only in simulation-mode, so you need neither hardware nor two computers to run the examples.

In simulation mode, the master and the client connect to a channel-server which simulates a simple wireless connection with some noise and a fading-channel. Both the master and the client run independently of each other and the only connection is the channel-server. Each one has a complete software-radio environment with a CDB and a SDB (see also <ref>subsec:cdb and sdb</ref>), so that they can communicate only through the channel-server. This corresponds to the real transmission where the two radios can only communicate through the channel.

Files

Because the master and the client are independent entities, they are put in a seperate directory. In each directory a small template-file can be found that contains the initialisations necessary for the software-radio. For this tutorial, two functions are important:

  • start_it comparable to the main-function in C-programs or the constructor in a C++-class
  • um_module_exit which corresponds to the destructor-function in a C++-class.

In the start_it-function the radio initialises some modules and/or chains (see <ref>subsec:modules and chains</ref>) which are cleaned-up in the um_module_exit-function.

Master

The master needs to send an image, encode it using a spreading-sequence, add a trainig-sequence for the channel estimation and put a synchronisation-signal on top of this, so that the client can synchronise. Looking at figure <ref>fig:first_radio</ref>, we can directly deduce the necessary chain:

Graph

The most simplest way to do that is to create a chain with all the modules inside. In order to do that, open the file for the master in Radios/ICS_Simple/Master/radio_master.c and put the following text in the function start_it:

  swr_sdb_id img, spread;
  PR( "Setting up send-chain\n" );
  send_ch = swr_chain_create(
    NEW_SPC_VAR( "image_send", img ),
    NEW_SPC( "mapper" ),
    NEW_SPC_VAR( "spread", spread ),
    NEW_SPC( "chest_send" ),
    NEW_SPC( "synch_send" ),
    NEW_SPC( "rrc_complex_send" ),
    NEW_SPC_VAR( "stfa_ics", stfa ),
    CHAIN_END );

For more explanation on the NEW_* commands, see <ref>subsub:swr_chain_create</ref>. In short we use NEW_SPC to instantiate a new module and NEW_SPC_VAR to instantiate a module and get a reference-id back. Now that this chain is created, we need to tell the STFA1) that this is a transmission-chain. We use the following command:

  swr_stfa_notice_sdb( stfa, 0, img );

Now everytime the STFA wants to send slot 0, it will call the img-instantiation of the “image_send”-module. Finally we set up the STFA in transmission-mode and tell the spread-module to use a spreading-factor of two2):

  swr_sdb_set_config_int( stfa, "tx", 1 );
  swr_sdb_set_config_int( spread, "factor", 2 );

Now we're ready to start the STFA:

  swr_stfa_go( stfa );

That's it for the start_it function. Because we use the send_ch and the stfa globally, we need to define these above the start_it-function like this:

struct chain_t *send_ch;
swr_sdb_id stfa;

And, last but not least, we need to clean up the chain in case the radio gets stopped. This is done by inserting the following lines at the end of the um_module_exit-function:

  if ( stfa ){
    PR( "Stopping the STFA$\backslash$n" );
    swr_stfa_stop( stfa );
    PR( "Deleting Sending-chain$\backslash$n" );
    swr_chain_destroy( send );
  }

Testing the Master

Now that the master is written, we can test it. First of all, make sure that you can compile it, using

make

and that there are neither warnings nor errors. Then you can call

make show_local

and if everything is OK, you should see a window coming up that displays the STFA as a horizontal white bar and the chain attached to it. Right-clicking on the image_send-module you can chose Display Data and then picture which will pop up a window with the picture sent in it. Keeping this window and right-clicking on rrc_complex_send, then Display outputs and port_out_0 shows the output of this chain in complex format. In this new window you can click on Complex and chose FFT to see a fast-fourier transform of the same output. You can also change the behaviour of some of the modules. For example you can change the factor3) of the spread-module. Right-click on the spread-module and chose Change config. Now you can increase or decrease the factor-value. If you still have the image-window open, you can see how the image changes when increasing or decreasing the factor-value. The next subsection explains why this happens.

Slots and Blocks in the Software-Radio

This is a small excurse in the internals of the software-radio. It's goal is to give you some more understanding of how our implementation works. It is not elemental but quite useful to understand the rest of the software-radio.

The software-radio works with fixed blocks of data. Everything that goes over the air has to fit into one slot. In the current implementation, a slot is of length 2560 symbols4). Every time the software-radio wants to send a slot, the output of the chain has to fit in 2560 symbols.

Starting from the STFA, the software-radio calculates the maximum size available by asking each module how much symbols it needs:

moduleusesymbolsleft
stfaguard-period902470
synch_sendsynchronisation2562214
chest_sendtraining-sequence1362078
spreadspreading-sequenceGraphGraph
mapperbit-to-symbolsGraphGraphbits

This means that the image_send-module has a variable-sized output that can vary from 4156 to Graph bits5), depending on the spreading-factor chosen. Every time the output-size of the image_send-module changes, it adjusts the image-size so that it fits in the given place.

For this reason you see the image changing when you change the spreading-factor of the spreading-module.

Client

Looking at figure <ref>fig:first_radio</ref> we can see that we have to implement the following chain:

Graph

There are two small subtelties when implementing this receiver-chain: first, we put the synch_rcv-module in front of the rrc_rcv-module. Looking at the master, we'd expect to first do the rrc-reception and then the synchronisation. But as the rrc_rcv-module downsamples by a factor of two, it is better to do the synchronisation at the higher sample-rate, in order to have a more exact synchronisation.

Second, the actual module-names are quite long: sync_rcv is called synch_complex_ics_rcv and rrc_rcv is called rrc_complex_ics_rcv. This is due to the development-process of the software-radio and the wish to keep old things running.

Besides these small details, the client is built more or less in the same way as the server. All these lines go in Radios/ICS_Simple/Client/radio_client.c. Before the start_it-function, we declare the stfa and the rcv_ch:

swr_sdb_id stfa;
struct chain_t *rcv_ch;

In the start_it-function, we declare the needed variables and the reception-chain:

  swr_sdb_id synch, mafi, despread, slicer;
  rcv_ch = swr_chain_create( NEW_SPC_VAR( "stfa_ics", stfa ),
    NEW_SPC_VAR( "synch_complex_ics_rcv", synch ),
    NEW_SPC( "rrc_complex_ics_rcv" ),
    NEW_SPC_VAR( "chest_rcv", mafi ),
    NEW_SPC_VAR( "despread", despread ),
    NEW_SPC_VAR( "slicer", slicer ),
    NEW_SPC( "image_rcv" ),
    CHAIN_END );

This chain is the same as in figure <ref>fig:first_radio</ref> and described above. Some of the modules need some configuration so that the radio works correctly. We have to do these things:

  • Gain: adjust the gain of the RF-cards, so that the cards don't saturate
  • Synchronisation: tell the module the id of the STFA so it can adjust for the desynchronisation
  • Despreading: set the despreading-factor to 2
  • Matched Filter: calculate 8 taps and align them
  • Slicer: set the id of the matched filter so that it can know the amplitude of the signal

All these values are in the configurable part of the modules, so we can set them using the swr_sdb_set_config*-functions:

  swr_sdb_set_config_int( stfa, "attn_tx", 31 );
  swr_sdb_set_config_int( stfa, "attn_rx", 15 );
  swr_sdb_set_config_int( synch, "stfa_id", stfa );
  swr_sdb_set_config_int( despread, "factor00", 2 );
  swr_sdb_set_config_int( mafi, "calc_taps", 8 );
  swr_sdb_set_config_int( mafi, "align", 1 );
  swr_sdb_set_config_int( slicer, "mafi_id", mafi );

Now everything is ready to start the STFA:

  swr_stfa_go( stfa );

We need to do some initialisation, just in case something will go wrong. Insert this line in the beginning of the function um_module_init:

  stfa = 0;

And at the end we need to clean things up, so insert these lines at the end of um_module_exit:

  if ( stfa ){
    PR( "Stopping stfa$\backslash$n" );
    swr_stfa_stop( stfa );
    PR( "Destroying rcv-chain$\backslash$n" );
    swr_chain_destroy( rcv_ch );
  }

Testing the Client

Compile it with make and correct eventual errors. Once everything compiles nicely, you can go in the directory Radios/ICS_Simple and type

make show_mc

This will start the master, then the client and will bring up the visualize-tool so that you can see the modules in action. Once the visualize-tool is started, you can see that there are now two tabs, one for the master and the other for the client. Clicking on these tabs you can switch between the two radios.

Testing the transmission

If everything up to here works as described, congratulations. You just finished your first very simple radio-transmission using the software-radio. While running the master and the client, you can now visualize different modules and change the configuration-parameters, in order to see what happens.

Synchronisation

A small word on synchronisation: the implementation we did in this tutorial is the most simplest possibility. Every frame the synchronisation-module will search for a synchronisation-signal. If it decides that there is no synchronisation, it shifts half a slot and will try again in the next frame.

The worst-case scenario is that the synchronisation-signal is just on the opposite side of the searching-direction, which will make the synchronisation-module searching the whole frame. In real time, one frame corresponds to 30ms and holds 15 slots, so that it will be searched completely in 1sec.

For a radio-application, 1 second is quite a long time. For this reason, a second method exists which is a bit more complicated but finds the synchronisation-signal on the first go. A macro-module called macro_synch_ics attaches a synchronisation-module to each slot of the stfa. Once a whole frame is received, it loops over all synchronisation-modules and choses the one with the strongest synchronisation-signal, discarding all others.

This allows the software-radio to synchronise in much more efficient way. As this method includes callback-functions and handling the macro-module, we decided to go the easy way and just scan the whole frame.

RF-transmission

Now everything should be ready to be able to transmit over the air. Once the simulation works, there are usually no big bugs left that can hinder the test over the air.

As you will have to transmit from one computer to the other, the code needs to be installed on two computers where each computer has the appropriate hardware installed. Once this is done, it is usually more efficient to work on one computer only and to ssh in the other computer and run the software-radio remotely. This gives you the advantage of having all the output on one screen.

To start the master, simply go into the Radios/ICS_Simple/Master-directory and call

make rf_show

which should start the real-time part of the software-radio and show up the transmission-window. On the other computer, go into the Radios/ICS_Simple/Client directory and issue the same command:

make rf_show

If all goes well, you should have now two windows where one shows the master and the other the client. You can now play around with the values to see how the software-radio reacts. Interesting configuration-parameters include the attn_tx on the master-side, the attn_rx on the client side. Both can be found in the stfa, the horizontal white line in the middle of the window.

Other things to experiment with is the calc_taps of the chest_rcv-module or the factor and sequence configuration of the spread and despread-module.

Going Further

Now that you have this simple radio running, it is possible to change the spreading-module with something else, for example a convolution-module or even an ldpc-module. You can also add other chains to the stfa in a similar manner than the ones we did. If you do so, don't forget that you don't need a synchronisation-module anymore on the additional chains. One synchronisation-module per frame is enough.

1) read <ref>subsec:stfa</ref> for more information
2) which is equivalent to a simple repetition code
3) this is the spreading-factor or the spreading-length of the code
4) this is an artefact of the first UMTS-implementation. You can change the slot-length in multiples of 128 symbols
5) The spreading-module has a maximum spreading-length of 32

Last modified:: %2007/%02/%20 %14:%Feb