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