[linux-dvb] [RFC] [PATCH] Make S/N values to appear at cx24123
xyzzy at speakeasy.org
Sat Apr 15 04:40:08 CEST 2006
oN fRI, 14 Apr 2006, Mauro Carvalho Chehab wrote:
> 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:
It was only a single shift. Anyway, the 64 bit math isn't being done
correctly. Here is a graph were you can see the problem clearly:
BTW, If you look at the graph of the function you're now using, it really
doesn't make a lot of sense. Maybe you should just toss out the old
exponential and make a new one.
Maybe you already know this, but there could be others reading who don't. The
thing to remember is that C "promotes from within." That is to say, the type
of an expression is determined by the types of the terms within the
expression, the types of the terms outside the expression have no effect.
Consider this generic expression, where 'op' could be addition,
multiplication, assignment, etc.
(term1 op1 term2) op2 term3)
In this case the bit-size of the arithmetic performed by op1 is based solely
on the types of term1 and term2. The type of term3 doesn't matter at all.
If you consider what is effectivly in the patch:
u64 = s32*(s32 - s32)/s32 + s32;
u16 = (u32)u64;
The innermost expression is the subtraction, both terms are s32, so it's done
with signed 32-bit arithmetic and produces a s32 result. Then the
multiplication is done as signed 32-bit, since both of its terms are signed
32-bit. This may overflow! The rest of the math is done as signed 32-bit as
well, producing a s32 result. Finally, that is promoted to unsigned 64-bit by
the assignment. In the next line, it's converted to unsigned 32-bit by the
cast, and then to unsigned 16-bit by the assignment.
If you want a 64-bit multiplication, you need to make one of the terms of
the multiplication 64-bit:
u16 = (s64)s32*(s32 - s32)/s32 + s32;
The comments about BER being 24-bit are wrong too. If you look at the code to
get BER, it's clearly a 22-bit value. This means the table going up past 4
million or so is pointless. This is how the table is working:
BER from 0 to about 5000 is linearly scaled to 100% to 99%
BER from about 5000 to the maximum is log scaled to 99% to 40%
I think it might be a good idea to revisit what exactly you want SNR to
return. Do you want SNR in dB scaled by some constant? Or do you want
something that even ranges from 0xffff for good to 0 for bad?
More information about the linux-dvb