Other and non-digital radio stuff.

Next to the DAB and DRM (and sw) software, there are some other SDR and even non-SDR programs. First of all, there is the inevitable spectrumviewer, in my case there are even two of them. Then there is an FM decoder, one with lots of buttons and displays.

Furthermore, since I am enthousiastic SDRplay user, I wrote some plugins for the SDRuno environment. Finally, as a good example of a non-SDR related program, there is an ALGOL 60 to C translator, old stuff.


With devices that capture segments of several MHz, it is interesting to see the spectra of these segments. Devices like an SDRplay have a maximum width of say 8 MHz, so half of everything that appears in the FM band can be made visible in a single picture. The spectrumviewer is an ideal program for that, it is able to handle input from a variety of input devices, and it has no less that three "scopes". The top one showing the spectrum of the signal, with the second one showing the spectrum as a waterfall. The third one, smaller, allows you to look in greater detail to a segment of the spectrum. The amount of detail is determined by the decimation setting, a range between 5 and 100.

Added is a view on the signal - as presented to the detailed viewer - as appearing in the time domain.


The spectrumviewer has support for common devices such as the SDRplay (both using the 2.13 and the 3.0X library), the AIRspy, RT2832 based DABsticks, the HackRF, the limeSDR and -experimental - the Elad-s1 and the Colibri. Sources can be found in this repository

Sometimes one wants to get a glimpse of a whole band, no details, just an overview. The picture below shows - as an example - what one gets with a simple whip in the range 550 .. 650 MHz on the so-called panorama viewer. Other tools focus on details, this one on the global view


The width can be set. Since the picture is built up from frames - in this case frames of 8 MHz width, it takes some time to build pictures with a larger width, such as the one below, covering the range from 200 .. 1000 MHz. Of course, when mapping a spectrum with a width of - say - 500 MHz on a screen with - say - 1000 pixels, details are lost.

The panoramaviewer can be used with devices like the SDRplay (with support using the 2.13 library as well as the 3.0X library), the airspy, and the RT2832 based DABsticks. Experimental support for the Colibri and the Elad-S1 is also implemented. Sources can be found in this repository


An FM decoder

FM is still alive, maybe it disappears, but contrary to the old AM band, the band is far from empty. (Right now there are radio spots on national broadcast transmitters to urge us to move over to DAB.)


The FM decoder reads in the samples with a rate of 2112 KHz, and decimates that to 192KHz (just an integer factor). The FM processing is done on 192KHz. The display on the right shows the segment of 2112 KHz (the SDRplay device has a filter with 1536 KHz width), the display on the left shows the decoded signal. The pilot - at 19 KHz -, the L-R signal - at 38 KHz - and the RDS - at 57 KHz - can be identified easily in the picture.

The FM decoder supports common devices, such as the SDRplay (both using the 2.13 and the 3.0X library), the AIRspy, the RT2832 based DABstics, the HackRF, the limeSDR, the Adalm Pluto and - experimental - the Elad-S1 and the Colibri. Sources - and installers - can be found in this repository

Plugins for SDRuno

While I try to create software that will run under Windows as well - cross compiling from within Linux - I am not very familiar with Windows. Nevertheless, since I am an enthousiastic user of the SDRplay device, I converted some of the decoders that were written for the sw software to plugin for the SDRuno environment. Plugins are there for weatherfac, FT8 psk, rtty, navtex, cw and drm.


The picture shows a screen with SDRuno and the weatherfax plugin active. Of course one needs to run SDRuno for these plugins. The repositories "https://github.com/JvanKatwijk/SDRunoPlugin_XXX" contain the sources and dll's for these plugins.

The FT8 plugin decodes FT8 messages and shows the decoded messages. If you fill in your home location (station identification or, as I do, a(n official) NLXXX number) the software - when switched on - sends data anbout the caller on the received messages to the PSK recorder


The ALGOL 60 to C translator

Very long time ago, Algol 60 was an important programming language. While not always popular, it was often used for introductory programming courses and for description of algorithms. I wrote my first programs in Algol 60, using punched cards on an ICL 1905 computer (with turn around times of at least a day per run).

In the 70-ties I wrote a compiler for Algol 60, on the PDP-11 and for the PDP-11 instruction set (using threaded code as virtual machine). The compiler was originally written in BCPL, later, when Unix was there, recoded in C. The sources of these versions were - obviously - lost.

Around 2002/2003, I wrote in spare time, a new version of the compiler (taking into account that the 64 K limitation of the PDP-11 memory was gone). The objective was to write something that produced regular C code rather than some P-code like stack machine. Semantics of typical Algol 60 constructs such as call by name, and unspecified procedure parameters could then be explained as regular C code constructs to students (although I had no direct involvement in education at that time).

Almost as a miracle, a few years ago the sources were discovered on some old floppy discs, and with only a few minor changes the compiler could be compiled and ran. Sources can be found in this repository The repository also contains a number of example programs.

Recently an addition was made, the compiler was used in France, and a command line parameter parameter was added to let the compiler accept French keywords, rather than the default British/US style keywords.

This manual is a user's guide and describes - in about 20 examples - in quite some detail the mappings of Algol 60 constructs in the resulting plain C code. Actually, the compiler works pretty well on my x64 based laptop and my RPI 2 and 3. And, yes, the compiler has no problems with the so-called "man-or-boy" problem.

As an example, the following program is typical Algol 60, demonstrating the so-called Jensen's device

	array a[1:4];
	real t; integer i;
	real procedure jensen1 (i,a); integer i; real a;
	   real s;
	   s := 0;
	   for i:=1 step 1 until 4 do s := s + a;
	   jensen1 := s;

	for i := 1 step 1 until 4 do a[i] := i + 1;
	t := jensen1 (i, a[i]);
	outreal	(1,t);
	outstring (1,"\n");

running this program gives the number 14 as result. By name parameters were essentially kind of implicit parameterless procedures (implemented as thunks). For each parameter, the compiler creates two thunks, one for the evaluation of the parameter to an address, one for evaluation of the parameter to a value.

As an example, the procedure jensen1 is translated into

 /* jensen1 declared at line 5 */
_jensen1_46 (char *Li_, int (*Ai_) (char *, int), int (*Vi_) (char *, int),
	     char *La_, double (*Aa_) (char *, double), double (*Va_) (char *,
  struct ___jensen1_46_rec local_data_jensen1;
  struct ___jensen1_46_rec *LP = &local_data_jensen1;
  LP->Li_ = Li_;
  LP->Ai_ = Ai_;
  LP->Vi_ = Vi_;
  LP->La_ = La_;
  LP->Aa_ = Aa_;
  LP->Va_ = Va_;

  {				// code for block at line 8
    (LP)->_s_48 = (double) (0);
    for (((LP)->Ai_) ((LP)->Li_, 1);
	 (((LP)->Vi_) (((LP)->Li_), 0) - (4)) * sign ((double) 1) <= 0;
	 ((LP)->Ai_) ((LP)->Li_, ((LP)->Vi_) (((LP)->Li_), 0) + 1))
      (LP)->_s_48 = ((LP)->_s_48) + (((LP)->Va_) (((LP)->La_), 0));
    (LP)->__res_val = (LP)->_s_48;
    ;				// null statement 
  return LP->__res_val;

the actual parameters i and A [i] in the procedure call

	t := jensen (i, a [i]);

are each translated into two parameterless procedures (thunks), one to handle the parameter as left hand side for an assignment, one to evaluate the parameter to a value.

int A_jff_0A (char *LP, int V) {
  return _i_45 = V;

int _jff_0A (char *LP, int d) {
  return _i_45;

double A_jff_1A (char *LP, double V) {
  return _a_45[_i_45 - 1] = V;

double _jff_1A (char *LP, int d) {
  return _a_45[_i_45 - 1];

Of course, these thunks are trivial since they relate to variables in the outermost block, variables that are implemented as global variables in C.

The main program as generated by the compiler, then is

// The main program
int main () {
  char *LP = (char *) NULL;

  {                             // code for block at line 2
    for (_i_45 = 1; (_i_45 - (4)) * sign ((double) 1) <= 0; _i_45 += 1)
      _a_45[_i_45 - 1] = (double) ((_i_45) + (1));
    _t_45 = _jensen1_46 (LP, A_jff_0A, _jff_0A, LP, A_jff_1A, _jff_1A);
    outreal (1, _t_45);
    outstring (1, "\n");
    ;                           // null statement

Of course, thunks referring to expressions containing references to local variables and function calls are slightly more complex.

As said, the documentation contains a number of Algol 60 examples together with their translations, and the source tree contains a number of these and other example programs.