Linux HAM/Amateur Radio development
 help / color / mirror / Atom feed
From: walter harms <wharms@bfs.de>
To: Guido Trentalancia <iz6rdb@trentalancia.com>
Cc: linux-hams@vger.kernel.org, t.sailer@alumni.ethz.ch
Subject: Re: soundmodem 0.16: fix the AFSK modulator for 300 baud operation (was: RE: 300bps Packet)
Date: Sat, 03 Mar 2012 10:50:28 +0100	[thread overview]
Message-ID: <4F51E964.9080605@bfs.de> (raw)
In-Reply-To: <1330736067.25864.15.camel@vortex>



Am 03.03.2012 01:54, schrieb Guido Trentalancia:
> Hello !
> 
> Although the soundmodem code has been removed from the kernel and moved
> to userspace, there was a report still open about a bug for 300 baud
> AFSK on the linux-hams list, so I am also carbon-copying the list...
> 
> I have created a patch for the AFSK modulator so that it is made to work
> at 300 baud and later on I am possibly going to create a supplemental
> one for the AFSK demodulator (as it appears still a bit buggy in my
> setup).
> 
> This patch modifies the AFSK modulator in version 0.16 of the soundmodem
> application as it appears to be problematic in particular at 300 baud
> (in general, it might be buggy for bitrates lower than 1200 baud,
> although I have not done any testing at other bitrates).
> 
> It is meant to be a temporary patch for further revision or for users
> that cannot use 300 baud AFSK at all as it needs further testing and
> improvement especially because, at least in my setup, it does not
> entirely fix the demodulation at 300 baud AFSK (reception).
> 
> First, the patch modifies the AFSK modulator so that it always uses at
> least a (pre-defined) minimum sampling rate of 11.025kHz (instead of
> always using a supposedly variable sampling rate calculated from the
> bitrate). This should make the code work on most soundcards (at the
> expense of a few extra CPU cycles), including some buggy ones which
> might not deal well with the low sampling rates that are the theoretical
> minimum for low bitrates (such as 300 baud). Also, the modified code
> makes sure that the sampling rate is always the same for both the
> modulator and the demodulator (provided that they operate at the same
> bitrate) and it introduces a different (supposedly better) method of
> determining the optimal sampling rate.
> 
> Then, the patch removes the probably buggy code that always selects a
> bitrate of 1200 baud for the modulator during the initial internal
> configuration, so that the AFSK modem effectively honours the bitrate
> selected by the user in the configuration file.
> 
> Finally, the patch removes the buggy code that changes the AFSK tone
> frequencies if they are greater than four times the bitrate, thus
> honouring the AFSK tone frequencies selected in the configuration file.
> 
> I have also introduced optional windowing functions (other than the
> Hamming one) for experimentation but at the moment they are completely
> untested and they can only be selected during compilation.
> 
> After applying this patch, the AFSK modulator should work normally for
> 300 baud (or in general bitrates different/less than 1200 baud) and the
> user should be able to select any AFSK tone frequencies.
> 
> In other words, this patch should fix the AFSK modulator for the problem
> reported, for example, here:
> 
> - http://he.fi/archive/linux-hams/200608/0005.html
> - http://marc.info/?l=linux-hams&m=129059468102018&w=2
> 
> I shall note that the trick suggested there of using the original
> soundmodem code with tones below 1200 Hz for 300 baud, did not work for
> me.
> 
> As already explained this patch is for testing mainly, so please do not
> apply it directly to new releases. Although the fixes described above for
> the AFSK modulator have also been applied to the AFSK demodulator, the
> latter needs further modifications and the whole patch needs to be tested,
> reviewed and eventually improved so that it is stable on most setups.
> I suppose the RX filters, or at least their parameters, should be
> double-checked and eventually optimized for 300 baud demodulation (at the
> moment I am doing some testing with increased values for RXFILTLEN and/or
> RXFILTOVERBITS but so far I am still missing the optimal results that I
> would like to achieve).
> 
> In the meanwhile, I would be grateful if somebody could test this on
> other setups and then report.
> 
> Signed-off-by: Guido Trentalancia <iz6rdb@trentalancia.com>
> ---
>  afsk/modem.c |  210 +++++++++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 176 insertions(+), 34 deletions(-)
> 
> --- soundmodem-0.16-orig/afsk/modem.c	2012-02-29 20:31:24.356287000 +0100
> +++ soundmodem-0.16/afsk/modem.c	2012-03-03 01:08:17.728744850 +0100
> @@ -32,8 +32,58 @@
>  #include "modem.h"
>  #include "costab.h"
>  
> +/*
> + * IZ6RDB 29/02/2012: always use a minimum samplerate
> + * otherwise some sound cards, might not work well
> + * especially at bitrates lower than 1200 baud (such
> + * as 300 baud for HF).
> + *
> + * The value is defined in Hz and it should never be
> + * less than 9600 Hz to avoid problems, although the
> + * recommended value is 11025 Hz for most soundcards.
> + *
> + * Some cards, might even require that only their
> + * maximum allowed sampling rate of 48kHz is used
> + * (for example, according to online reports some
> + * embedded SiS 701x AC'97 controllers).
> + */
> +#define MINIMUM_SAMPLERATE	11025
> +
> +/*
> + * IZ6RDB 01/03/2012: define different possible
> + * window types for the FIR filters and choose
> + * one of the available types:
> + *
> + * - NONE
> + * - HAMMING (window used up to version 0.16)
> + * - HANNING
> + * - BLACKMAN
> + * - WELCH
> + */
> +#define FIR_WINDOW	HAMMING
> +
> +/*
> + * IZ6RDB 01/03/2012: introduce a parameter
> + * called "bandwidth expansion factor", which
> + * is a real positive number slightly greater
> + * than unity (up to 2.0) that accounts for
> + * guard-bands and non-ideal filtering.
> + *
> + * This value is only used for estimating the
> + * required sampling rate.
> + *
> + * Values are usually between 1.125 and 1.4.
> + *
> + * The recommended value is 1.36.
> + */
> +#define BANDWIDTH_EXPANSION_FACTOR	1.36
> +
>  /* --------------------------------------------------------------------- */
>  
> +#ifndef BANDWIDTH_EXPANSION_FACTOR
> +#define BANDWIDTH_EXPANSION_FACTOR      1.36
> +#endif
> +

I do not see the distance between the #define BANDWIDTH_EXPANSION_FACTOR and the #ifndef BANDWIDTH_EXPANSION_FACTOR
but i would suggest to remove the first one or the check. You are setting it to default values either way
that is confusing.


>  struct modstate {
>  	struct modemchannel *chan;
>  	unsigned int bps, f0, f1, notdiff, maxbitlen;
> @@ -53,6 +103,9 @@ static const struct modemparams modparam
>  static void *modconfig(struct modemchannel *chan, unsigned int *samplerate, const char *params[])
>  {
>  	struct modstate *s;
> +	unsigned int bandwidth, expanded_bandwidth;
> +	unsigned int min_samplerate, optimized_samplerate;
> +	unsigned int f_carrier;
>  	
>  	if (!(s = malloc(sizeof(struct modstate))))
>  		logprintf(MLOG_FATAL, "out of memory\n");

It is a good habbit to do this in two lines:
	
	s = malloc(sizeof(struct modstate));
	if (!s)

> @@ -63,22 +116,45 @@ static void *modconfig(struct modemchann
>  			s->bps = 100;
>  		if (s->bps > 9600)
>  			s->bps= 9600;
> -	} else
> -		s->bps = 1200;
> -	if (params[1]) {
> +	}
> +	if (params[1])
>  		s->f0 = strtoul(params[1], NULL, 0);
> -		if (s->f0 > s->bps * 4)
> -			s->f0 = s->bps * 4;
> -	} else
> -		s->f0 = 1200;
> -	if (params[2]) {
> +	if (params[2])
>  		s->f1 = strtoul(params[2], NULL, 0);
> -		if (s->f1 > s->bps * 4)
> -			s->f1 = s->bps * 4;
> -	} else
> -		s->f1 = 2200;
>  	s->notdiff = params[3] ? !strtoul(params[3], NULL, 0) : 0;
> -	*samplerate = 8 * s->bps;
> +
> +	/*
> +	 * Calculate the bandwidth of the baseband (audio) signal:
> +	 * basically this is the highest frequency of the two
> +	 * possible tones.
> +	 */
> +	bandwidth = (s->f0 > s->f1) ? s->f0 : s->f1;
> +
> +	/*
> +	 * Calculate the expanded bandwidth (with guard-bands)
> +	 * to get a better estimate.
> +	 */
> +	expanded_bandwidth = BANDWIDTH_EXPANSION_FACTOR * bandwidth;
> +
> +	/* Nyquist criteria (minimum sampling rate) */
> +	min_samplerate = 2 * expanded_bandwidth;
> +
> +	/* Calculate the (audio) carrier frequency */
> +	f_carrier = (s->f0 + s->f1)/2;
> +
> +	/* Calculate intermediate operating point sampling rate */
> +	optimized_samplerate = 4 * f_carrier;
> +	if (optimized_samplerate > min_samplerate)
> +		min_samplerate = optimized_samplerate;
> +
> +	/*
> +	 * Make sure that the minimum recommended sampling
> +	 * rate for the soundcard is exceeded.
> +	 */
> +	if (min_samplerate < MINIMUM_SAMPLERATE)
> +		min_samplerate = MINIMUM_SAMPLERATE;
> +
> +	*samplerate = min_samplerate;
>  	return s;
>  }
>  
> @@ -202,7 +278,9 @@ static const struct modemparams demodpar
>  static void *demodconfig(struct modemchannel *chan, unsigned int *samplerate, const char *params[])
>  {
>  	struct demodstate *s;
> -	unsigned int f;
> +	unsigned int bandwidth, expanded_bandwidth;
> +	unsigned int min_samplerate, optimized_samplerate;
> +	unsigned int f_carrier;
>  
>  	if (!(s = malloc(sizeof(struct demodstate))))
>  		logprintf(MLOG_FATAL, "out of memory\n");


	see above


> @@ -213,27 +291,45 @@ static void *demodconfig(struct modemcha
>  			s->bps = 100;
>  		if (s->bps > 9600)
>  			s->bps= 9600;
> -	} else
> -		s->bps = 1200;
> -	if (params[1]) {
> +	}
> +	if (params[1])
>  		s->f0 = strtoul(params[1], NULL, 0);
> -		if (s->f0 > s->bps * 4)
> -			s->f0 = s->bps * 4;
> -	} else
> -		s->f0 = 1200;
> -	if (params[2]) {
> +	if (params[2])
>  		s->f1 = strtoul(params[2], NULL, 0);
> -		if (s->f1 > s->bps * 4)
> -			s->f1 = s->bps * 4;
> -	} else
> -		s->f1 = 2200;
>  	s->notdiff = params[3] ? !strtoul(params[3], NULL, 0) : 0;
> -	f = s->f0;
> -	if (s->f1 > f)
> -		f = s->f1;
> -	f += s->bps/2;
> -	f = (2*f) + (f >> 1);
> -	*samplerate = f;
> +
> +        /*
> +         * Calculate the bandwidth of the baseband (audio) signal:
> +         * basically this is the highest frequency of the two
> +         * possible tones.
> +         */
> +        bandwidth = (s->f0 > s->f1) ? s->f0 : s->f1;
> +
> +	/*
> +	 * Calculate the expanded bandwidth (with guard-bands)
> +	 * to get a better estimate.
> +	 */
> +        expanded_bandwidth = BANDWIDTH_EXPANSION_FACTOR * bandwidth;
> +
> +        /* Nyquist criteria (minimum sampling rate) */
> +        min_samplerate = 2 * expanded_bandwidth;
> +
> +	/* Calculate the (audio) carrier frequency */
> +	f_carrier = (s->f0 + s->f1)/2;
> +
> +	/* Calculate intermediate operating point sampling rate */
> +	optimized_samplerate = 4 * f_carrier;
> +	if (optimized_samplerate > min_samplerate)
> +		min_samplerate = optimized_samplerate;
> +
> +	/*
> +	 * Make sure that the minimum recommended sampling
> +	 * rate for the soundcard is exceeded.
> +	 */
> +	if (min_samplerate < MINIMUM_SAMPLERATE)
> +		min_samplerate = MINIMUM_SAMPLERATE;
> +
> +	*samplerate = min_samplerate;
>  	return s;
>  }
>  
> @@ -364,11 +460,41 @@ static inline double sinc(double x)
>          return sin(arg) / arg;
>  }
>  
> -static inline double hamming(double x)
> +/*
> + * The Hamming window is the original one (used
> + * exclusively up to version 0.16).
> + * Later versions introduced other optional
> + * windows, so that they can be changed before
> + * compilation and tested in order to try
> + * achieving reduced passband ripples at the
> + * expense of slower passband to stopband
> + * roll-off.
> + */
> +static inline double no_window(double x)
> +{
> +	return 1;
> +}
> +
> +static inline double hamming_window(double x)
>  {
>          return 0.54-0.46*cos((2*M_PI)*x);
>  }
>  
> +static inline double hanning_window(double x)
> +{
> +        return 0.5-0.5*cos((2*M_PI)*x);
> +}
> +
> +static inline double blackman_window(double x)
> +{
> +        return 0.42-0.5*cos((2*M_PI)*x)+0.08*cos((4*M_PI)*x);
> +}
> +
> +static inline double welch_window(double x)
> +{
> +	return 1.0-pow((2*x-1),2);
> +}
> +
>  static void demodinit(void *state, unsigned int samplerate, unsigned int *bitrate)
>  {
>  	struct demodstate *s = (struct demodstate *)state;
> @@ -388,7 +514,23 @@ static void demodinit(void *state, unsig
>                  if (w > 1)
>                          w = 0;
>                  else
> -                        w = hamming(w);
> +#ifdef FIR_WINDOW
> +#if (FIR_WINDOW == NONE)
> +			w = no_window(w);
> +#elif (FIR_WINDOW == HAMMING)
> +			w = hamming_window(w);
> +#elif (FIR_WINDOW == HANNING)
> +			w = hanning_window(w);
> +#elif (FIR_WINDOW == BLACKMAN)
> +			w = blackman_window(w);
> +#elif (FIR_WINDOW == WELCH)
> +			w = welch_window(w);
> +#else
> +#error "Unknown FIR Window selected !"
> +#endif
> +#else // default to Hamming window
> +                        w = hamming_window(w);
> +#endif

	you could do that at start an reduce the forest here like:

#ifdef FIR_WINDOW
#if (FIR_WINDOW == NONE)
#   define WINDOW_FKT(x)		no_window(w)
#elif (FIR_WINDOW == HAMMING)

and later:
	w=WINDOW_FKT(w);

in the next step you can add a jump table add make this selectable parameter

>                  f0r[i] = w * cos(ph0 * i);
>                  f0i[i] = w * sin(ph0 * i);

	there is a sincos() function, maybe usefull here ?


>                  f1r[i] = w * cos(ph1 * i);
> 

	hope that helps, just my 2 cents

	re,
 	 wh

> --
> To unsubscribe from this list: send the line "unsubscribe linux-hams" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

  reply	other threads:[~2012-03-03  9:50 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-03  0:54 soundmodem 0.16: fix the AFSK modulator for 300 baud operation (was: RE: 300bps Packet) Guido Trentalancia
2012-03-03  9:50 ` walter harms [this message]
2012-03-03 14:47   ` Guido Trentalancia
2012-03-04 14:33     ` walter harms
2012-03-04 20:16       ` Guido Trentalancia
     [not found]         ` <4F776E14.7090104@trinnet.net>
     [not found]           ` <1333379832.2112.15.camel@vortex>
     [not found]             ` <4F7B199F.3050104@trinnet.net>
     [not found]               ` <1333647291.2605.34.camel@vortex>
     [not found]                 ` <1333741818.4064.20.camel@vortex>
     [not found]                   ` <4F7F7A2C.2030500@trinnet.net>
     [not found]                     ` <1333809855.2433.10.camel@vortex>
2012-04-07 23:14                       ` Soundmodem hangs all USB keyboard or mouse input -- and soundmodem 0.16: fix the AFSK modulator for 300 baud operation David Ranch
2012-04-08 15:23                         ` Guido Trentalancia
2012-04-09 21:37                         ` Curt, WE7U
2012-03-03 18:48   ` soundmodem 0.16: fix the AFSK modulator for 300 baud operation (was: RE: 300bps Packet) Guido Trentalancia

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F51E964.9080605@bfs.de \
    --to=wharms@bfs.de \
    --cc=iz6rdb@trentalancia.com \
    --cc=linux-hams@vger.kernel.org \
    --cc=t.sailer@alumni.ethz.ch \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox