0

I am using a 3rd-party fixed-point antilog() function to calculate magnitude from decibel out_mag = 10^( in_db/20 ). The antilog() takes Q6.25 format as input, and provides Q16.15 at output.

The problem is that antilog() quickly overflows for some higher dB valus, like 100 dB: 10^( 100/20 ) = 100000. The highest value Q16.15 format can have is 2^16-1=65535, so 100000 doesn't fit.

Is there a trick to avoid the overflow? Prescale input value somehow?

Danijel
  • 8,198
  • 18
  • 69
  • 133
  • How about just clamping when converting to Q6.25? – unwind Feb 01 '17 at 10:54
  • Could you elaborate? – Danijel Feb 01 '17 at 12:16
  • How about prescaling the input value, i.e. out_mag_p = 10^(in_db/20/p) and then your final magnitude value becomes: out_mag = out_mag_p^p – Mouse On Mars Feb 01 '17 at 15:01
  • Well what on Earth do you want to do with a 100000 value if you can't store it? It's not a question for us, it's a question for you, you chose a format that doesn't allow for such large values, why, and then why do you want to store a value so large the format you chose can't take it? – Michel Rouzic Feb 04 '17 at 11:22
  • Thanks @MichaelC. That's a good idea, but I think I found a better solution (see my answer). – Danijel Feb 06 '17 at 06:47
  • @MichelRouzic Thanks. I didn't choose the formats, they are dictated by the target DSP processor and the 3rd party library. – Danijel Feb 06 '17 at 06:50
  • Okay in that case just subtract some dB to your input value (let's say 20) so you get a result 10 times lower, for instance. If you use division then you have to use an exponent, which is slow. – Michel Rouzic Feb 06 '17 at 11:02

1 Answers1

0

I managed to find a solution. It's a bit tricky.

First, a struct that will hold the output result is needed:

typedef struct
{
    q15   v; // Value (within the [MIN, MAX] range for Q16.15).
    int32 s; // Scalefactor.
} q15_t;

The idea is to provide result as Output with Scalefactor, where

Output = 10^y
Scale  = 2^scalefactor

Final output is Output shifted left scalefactor times.

Here is the math.

Input Q31 format is dB value scaled to [-1,1] with scale being 2^scalefactor. We need to calculate:

Out = 10^(2^scalefactor * in/20.0)

    = 10^(p+y)                  // rewriting as sum
    = 10^p          * 10^y      // to enable exponent multiplication
    = 2^scalefactor * 10^y      // making it power of 2 to be able to just shift

This way we are not limited with Q16.15 max value.

We already know 2^scalefactor, but need to find y:

2^scalefactor * in = p + y

10^p = 2^scalefactor   =>   p = scalefactor*log(2)   // rewrite as power of 2
2^scalefactor * in = scalefactor*log(2) + y          // replace p
y = 2^scalefactor*in - scalefactor*log(2)            // and find y

Calculate y, and feed it into antilog.

If input is 100 dB, then the output magnitude should be 100.000, which doesn't fit into Q16.15 format. Using the above solution, Output = 50.000 (this fits into Q16.15!) and scalefactor = 1, meaning, the final output is 50.000 shifted to left 1 place. This gives 100.000 as the final result. Depending on your implementation, you might get the same result as 25.000 with scalefactor = 2, etc. The idea is there.

Danijel
  • 8,198
  • 18
  • 69
  • 133