Gain modes

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/osmocom-sdr@lists.osmocom.org/.

Leif Asbrink leif at sm5bsz.com
Thu Oct 18 11:13:58 UTC 2012


Hi All,

The e4000 tuner is flexible in that it allows different 
gain distributions that optimize it for usage in different
environments.

With high gain near the antenna and low gain after the filters
one can get a low noise figure and a good dynamic range for
close range interference. The bad side is that the early
stages can become saturated by signals at large frequency separations.
If the user adds a bandpass filter for a narrow frequency
range, this mode gives the best performance.

With low gain near the antenna and high gain after the filters
one can tolerate stronger signals at large frequency separation
at the expense of a lower dynamic range for close spaced signals.
This is useful when using the tuner without any filters.

Besides the standard gain distribution which is a compromise
I have added two more gain modes in Linrad. The function
set_tuner_gain_mode() accepts values from 0 to 3 where 0 and 1
are identical to the original settings. The AGC mode does not
work quite ok, it was better some months ago, but it does work
with the batch below since it is no longer totally disabled.
Always disabling the AGC in the rtl2832 chip may or may not
be a good idea.

The noise figures and points of saturation are similar at full
gain in all modes. The table shows performance with the tuner
set to 144.2 MHz with Linrad set to receive 144.5 MHz. The columns
with a frequency show the signal level in dBm at each frequency that
can be applied without A/D saturation or significant loss of S/N:

Mode   Gain   NF    143.8     145.5       154.2
 1      42   7.9     -53       -44         -43
 2      25   8.3     -56       -44         -20
 3      25   7.0     -59       -48         -20

Note what happens for 10 MHz separation. Better performance at
wide range leads to worse performance at close range. In mode 2
there is a 3 dB dynamic range loss at close range. 

When the attenuator is set for a NF of about 17 dB (10 dB
below optimum sensitivity for the desired signal, these data
are obtained:

Mode   Gain   NF    143.8     145.5       154.2
 1      24    17     -41       -29         -30
 2      10    20     -41       -30         -8
 3       0    17     -34       -26         -16 

The above was performed applying the pattc below to the
library downloaded a couple of days ago. I do not think
the changes will affect any other software that uses the library.
The set_tuner_gain_mode() function now returns the gain mode
or the highest allowed gain mode if the user tries to set a too
high one. Before, the function always returned zero so there was
no reason to check the return value.

The patch is included below. If the basic principle is accepted
for the osmocom library I guess defines should be moved to
the header file and the global variable put into the dev structure.

Regards

Leif  /  SM5BSZ


diff ../rtl-sdr-ref/src/librtlsdr.c src/librtlsdr.c
93a94,102
> // Sept 24 2012 SM5BSZ. Gain modes.
> // Note that these things are used in tuner_e4k.c also.
> // The routine using them should be moved to tuner_e4k.c 
> extern int e4k_gain_mode;
> #define E4K_GAIN_MODE_OLD 1
> #define E4K_GAIN_MODE_LINEARITY 2
> #define E4K_GAIN_MODE_SENSITIVITY 3
> #define MAX_E4K_GAIN_MODES 3
> 
127c136,140
< 	if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL)
---
> // SM5BSZ Sept24 2012:  Use only (the modified) set_lna_gain if the user
> // asked for linearity or sensitivity.
>         if(e4k_gain_mode <= E4K_GAIN_MODE_OLD)
>           {
> 	  if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL)
129c142
< 	if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL)
---
> 	  if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL)
130a144
> // SM5BSZ: enhanced gain should affect how the AGC turns down the gain 
132c146
< 	if(enhgain >= 0)
---
> 	  if(enhgain >= 0)
136c150,153
< 	return 0;
---
> 	  return 0;
> 	  }
> e4k_set_lna_gain(&devt->e4k_s, gain);
> return 0;
137a155
> 
141a160
> 
785a805,807
> // Sept 2012 SM5BSZ: Add standard gains
>         const int e4k_std_gains[] = { -250, -200, -150, -100, -50, 0, 50, 
>                     100, 150, 200, 250};
802c824,832
< 		ptr = (int *)e4k_gains; len = sizeof(e4k_gains);
---
> // Sept 2012 SM5BSZ: Use standard gains (5 dB step) if gain is mode above 1.
> 	        if(e4k_gain_mode < 2)
>                   {
> 	 	  ptr = (int *)e4k_gains; len = sizeof(e4k_gains);
> 	 	  }
> 	 	else
> 	 	  {
> 	 	  ptr=  (int *)e4k_std_gains; len = sizeof(e4k_std_gains);  
>                   }
879a910,922
> 
> // SM5BSZ Oct 17 2012  Reconfigure the rtl
> if(mode)
>   {
> /* enable SDR mode, disable DAGC (bit 5) */
>   rtlsdr_demod_write_reg(dev, 0, 0x19, 0x05, 1);
>   }
> else
>   {
> /*  enable AGC  */
>   rtlsdr_demod_write_reg(dev, 0, 0x19, 0x25, 1);
>   }
>   
diff ../rtl-sdr-ref/src/tuner_e4k.c src/tuner_e4k.c
41a42,49
> // Sept 24 2012 SM5BSZ. Gain modes.
> // Note that these things are used in librtlsdr.c also.
> int e4k_gain_mode;
> #define E4K_GAIN_MODE_OLD 1
> #define E4K_GAIN_MODE_LINEARITY 2
> #define E4K_GAIN_MODE_SENSITIVITY 3
> #define MAX_E4K_GAIN_MODES 3
> 
659a668,671
> // SM5BSZ Sept 24 2012: Use all gain controls if gain mode
> // is above 1
> if(e4k_gain_mode <= E4K_GAIN_MODE_OLD)
>   {
666a679,935
>   }
> if(e4k_gain_mode == E4K_GAIN_MODE_LINEARITY)
>   {
>   switch (gain)
>     {
>     case -250:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 9);
>     e4k_if_gain_set(e4k, 6, 6);
>     break;
> 
>     case -200:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 9);
>     break;
>     
>     case -150:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 9);
>     break;
> 
>     case -100:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 3);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 9);
>     break;
> 
>     case -50:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 0);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 12);
>     break;
>     
>     case 0:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 4);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 12);
>     break;
> 
>     case 50:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 6);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 12);
>     break;
> 
>     case 100:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 8);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 12);
>     break;
>     
>     
>     case 150:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 10);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 12);
>     break;
> 
>     case 200:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 12);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 12);
>     break;
> 
>     case 250:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 12);
>     e4k_if_gain_set(e4k, 6, 12);
>     break;
>     }    
>   }
> if(e4k_gain_mode == E4K_GAIN_MODE_SENSITIVITY)
>   {
>   switch (gain)
>     {
>     case -250:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 6);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 6);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
> 
>     case -200:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 8);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 6);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
> 
>     case -150:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 10);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 6);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
> 
>     case -100:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 12);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 6);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
> 
>     case -50:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 4);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 6);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
>     
>     case 0:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 2);
>     e4k_if_gain_set(e4k, 5, 3);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
> 
>     case 50:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, -3);
>     e4k_if_gain_set(e4k, 2, 3);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 6);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
> 
>     case 100:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, 6);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 6);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
>     
>     case 150:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, 6);
>     e4k_if_gain_set(e4k, 2, 0);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 2);
>     e4k_if_gain_set(e4k, 5, 9);
>     e4k_if_gain_set(e4k, 6, 3);
>     break;
>     break;
> 
>     case 200:
>     fprintf(stderr,"\nCASE 200");
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, 6);
>     e4k_if_gain_set(e4k, 2, 3);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 1);
>     e4k_if_gain_set(e4k, 5, 9);
>     e4k_if_gain_set(e4k, 6, 6);
>     break;
> 
>     case 250:
>     e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, 14);
>     e4k_mixer_gain_set(e4k, 12);
>     e4k_if_gain_set(e4k, 1, 6);
>     e4k_if_gain_set(e4k, 2, 6);
>     e4k_if_gain_set(e4k, 3, 0);
>     e4k_if_gain_set(e4k, 4, 0);
>     e4k_if_gain_set(e4k, 5, 9);
>     e4k_if_gain_set(e4k, 6, 9);
>     break;
>     }    
>   }
> return gain;
694a964,969
> // Sept 24 2012 SM5BSZ. Add a flag for more gain modes and return it
> // so we know the library has this feature.
>   e4k_gain_mode=manual;
>   if(e4k_gain_mode > MAX_E4K_GAIN_MODES)e4k_gain_mode=MAX_E4K_GAIN_MODES;
>   return e4k_gain_mode;                     
> 
695a971
> 	        e4k_gain_mode=0;
701a978
>                 




More information about the osmocom-sdr mailing list