======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 cha:signal flow. In figure fig:first_radio 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 digraph structs { node [shape=record]; struct1 [label="image_send", width=1.3, pos="0,0"]; struct2 [label="modulator", width=1.3, pos="0,1"]; struct3 [label="spreadind", width=1.3, pos="0,1.5"]; struct4 [label="chest_send";width=1.3]; struct5 [label="sync_send";width=1.3]; struct6 [label="rrc";width=1.3]; struct7 [label=" Slot 0 | Slot 1 | Slot 2";width=3.9]; struct1 -> struct2; struct2 -> struct3; struct3 -> struct4; struct4 -> struct5; struct5 -> struct6; struct6 -> struct7:s0; stfa [label="STFA", shape="plaintext"]; struct21 [label=" Slot 0 | Slot 1 | Slot 2", width="3.9", rect="5,10,8.9,10.3"]; struct22 [label="sync_rsv", width=1.3, pos="0,1"]; struct23 [label="rrc_rsv", width=1.3, pos="0,1.5"]; struct24 [label="chest_rsv";width=1.3]; struct25 [label="despread";width=1.3]; struct26 [label="slicer";width=1.3]; struct27 [label="image_rsv", width=1.3, pos="0,0"]; struct21:s0 -> struct22; struct22 -> struct23; struct23 -> struct24; struct24 -> struct25; struct25 -> struct26; struct26 -> struct27; { rank = same; struct7; struct21; stfa; } } A very simple radio|fig:first_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 cha:modes of operation, 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 subsec:cdb and sdb), 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 subsec:modules and chains) 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 fig:first_radio, we can directly deduce the necessary chain: digraph DokuWikiParser { node [shape=box]; rankdir=LR image_send -> modulator modulator -> spread spread -> chest_send chest_send -> synch_send synch_send -> rrc } 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 subsub:swr_chain_create. 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 STFA((read subsec:stfa for more information)) 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 two((which is equivalent to a simple repetition code)): 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 //factor//((this is the spreading-factor or the spreading-length of the code)) 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 symbols((this is an artefact of the first UMTS-implementation. You can change the slot-length in multiples of 128 symbols)). 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: |module|use|symbols|left| |stfa|guard-period|90|2470| |synch_send|synchronisation|256|2214| |chest_send|training-sequence|136|2078| |spread|spreading-sequence|\frac{1}{n}|\frac{2078}{n}| |mapper|bit-to-symbols|*2|\frac{4156}{n}bits| This means that the image_send-module has a variable-sized output that can vary from 4156 to \frac{4156}{32}=129 bits((The spreading-module has a maximum spreading-length of 32)), 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 fig:first_radio we can see that we have to implement the following chain: digraph DokuWikiParser { node [shape=box]; rankdir=LR stfa -> synch_rcv synch_rcv -> rrc_rcv rrc_rcv -> chest_rcv chest_rcv -> despread despread -> slicer slicer -> image_rcv } 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 fig:first_radio 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.