Re: [RFC] [PATCH] Make S/N values to appear at cx24123 frontend

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Trent,

I think this is the final version of this patch, based on what we have
currently.

I've decided to use u64, instead of all those shifts. This way, we can
improve the precision for lower BER rates. Here, it worked like a charm:

cx24123: cx24123_read_ber:  BER = 6380
cx24123: cx24123_read_snr:  read S/N index = 63948


Em Sex, 2006-04-14 às 07:09 -0300, Mauro Carvalho Chehab escreveu:
> Em Sex, 2006-04-14 às 01:33 -0700, Trent Piepho escreveu:
> 
> > So anyway, here is my version of linear interpolation.  It has a simpler
> > formula in the code, and much better rounding behavior, as you can see in the
> > plot here:  http://www.speakeasy.org/~xyzzy/ber-snr.png
> Sounds good. I'll replace the corresponding parts at my code. May I
> include your Signed-off-by at the patch?

Cheers, 
Mauro.

------------------
This patch fixes SNR detection on cx24123

From: Mauro Carvalho Chehab

Current code is broken, since, before calling SNR, BER code should be
called. After the patch, cx24123 will:
1) Show SNR only if signal is locked;
2) SNR estimation based on BER rate;
3) The estimation uses linear interpolation on segmented intervals to
improve performance

Signed-off-by: Mauro Carvalho Chehab


diff -r 436e56df57d3 linux/drivers/media/dvb/frontends/cx24123.c
--- a/linux/drivers/media/dvb/frontends/cx24123.c	Thu Apr 13 18:50:22 2006 -0300
+++ b/linux/drivers/media/dvb/frontends/cx24123.c	Fri Apr 14 13:41:29 2006 -0300
@@ -47,7 +47,6 @@ struct cx24123_state
 	struct dvb_frontend frontend;
 
 	u32 lastber;
-	u16 snr;
 	u8  lnbreg;
 
 	/* Some PLL specifics for tuning */
@@ -885,25 +884,10 @@ static int cx24123_read_ber(struct dvb_f
 		(cx24123_readreg(state, 0x1d) << 8 |
 		cx24123_readreg(state, 0x1e));
 
-	/* Do the signal quality processing here, it's derived from the BER. */
-	/* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
-	if (state->lastber < 5000)
-		state->snr = 655*100;
-	else if ( (state->lastber >=   5000) && (state->lastber <  55000) )
-		state->snr = 655*90;
-	else if ( (state->lastber >=  55000) && (state->lastber < 150000) )
-		state->snr = 655*80;
-	else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
-		state->snr = 655*70;
-	else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
-		state->snr = 655*65;
-	else
-		state->snr = 0;
-
-	dprintk("%s:  BER = %d, S/N index = %d\n",__FUNCTION__,state->lastber, state->snr);
-
 	*ber = state->lastber;
 
+	dprintk("%s:  BER = %d\n",__FUNCTION__,*ber);
+
 	return 0;
 }
 
@@ -917,13 +901,59 @@ static int cx24123_read_signal_strength(
 	return 0;
 }
 
+static int ber_table[][2] = {
+			{ 1.00 * 65535, 0 },
+/* The first segment were commented just to allow a better dynamic range
+ * Of course, SNR estimation error is high for BER between 0 and 4798
+ */
+//			{ 0.999 * 65535, 4798 },
+			{ 0.99 * 65535, 5380 },
+			{ 0.98 * 65535, 6032 },
+			{ 0.95 * 65535, 8502 },
+			{ 0.90 * 65535, 15066 },
+			{ 0.85 * 65535, 26696 },
+			{ 0.80 * 65535, 47306 },
+			{ 0.75 * 65535, 83826 },
+			{ 0.70 * 65535, 148539 },
+			{ 0.65 * 65535, 263210 },
+			{ 0.60 * 65535, 466406 },
+			{ 0.40 * 65535, 4598482 },
+			{ 0.30 * 65535, 14439082 } };
+
 static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-	*snr = state->snr;
+
+	int ber, i=0;
+	int sync = cx24123_readreg(state, 0x14) & 0x80;
+
+	/* If no sync, SNR makes no sense at all */
+	if (!sync) {
+		*snr=0;
+		return 0;
+	}
+
+	cx24123_read_ber(fe,&ber);
+
+	/* Do the signal quality processing here, it's derived from the BER.
+	 * Scale the BER from a 24bit to a SNR 16 bit where higher = better
+	 * It uses linear interpolation between each segment of an exponencial
+	 * curve given by ber_table aproximated values.
+	 */
+
+	*snr = 0;
+	for (i=1;i<ARRAY_SIZE(ber_table);i++) {
+		if (ber <= ber_table[i][1]) {
+			int dx = ber_table[i][1] - ber_table[i-1][1];
+			int dy = ber_table[i][0] - ber_table[i-1][0];
+			u64 calc = dy*(ber - ber_table[i-1][1])/dx +
+							ber_table[i-1][0];
+			*snr= (u32)calc;
+			break;
+		}
+	}
 
 	dprintk("%s:  read S/N index = %d\n",__FUNCTION__,*snr);
-
 	return 0;
 }
 
@@ -1053,7 +1083,6 @@ struct dvb_frontend* cx24123_attach(cons
 	state->i2c = i2c;
 	memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
 	state->lastber = 0;
-	state->snr = 0;
 	state->lnbreg = 0;
 	state->VCAarg = 0;
 	state->VGAarg = 0;
_______________________________________________

linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux