# best way to converting data from uint16_t to q15 for least saturation error

Q15 standard is fixed point fraction from -1 to 1 represented by 15 bit, and uint16 is numbers from 0 to 2¹⁶.

I have data range from 0 to 2¹², I can directly cast them to Q15 and all the data will preserve exactly. But I'm don't know will this cause saturation problem? Since multiplication of two fractional number will create smaller number.

In the manner I've casted, the data will be allocated in sticked to positive region of float space tangented to zero:

Another way is to do :

2^12=data_max
2^15=type_max
(data-(data_max/2))*(2*type_max/data_max)


This transform uses the all range of type, but why this must be good, or bad? I want to use arm_fir_q15 from CMSIS DSP library and it accepts q15 fromat, I think the transformation is useless and will not make sense.

Also I've read Q although I can't understand why adding k in multiplication can round the bumber!

• I am curious how you're able to do the superscript numbers without going into inline math mode. Commented Aug 10, 2022 at 22:14
• @robertbristow-johnson I can't remember. :) Commented Aug 11, 2022 at 5:05
• @robertbristow-johnson external pasta or 42<sup>69</sup> Commented Aug 11, 2022 at 19:55

There's not really a problem here. When you multiply two Q15 numbers, you just multiply them as if they were 15-bit integers, and then remember that their value was "integer value / 2¹⁵", so that their product is:

(integer value A·integer value B)/(2¹⁵·2¹⁵)

So, you just divide by 2³⁰ at the end. Bitwise, that's just a rightshift!

It isn't clear what your input data represents, or what you're intending to do with it (except that you're planning on using a FIR filter). So this answer is going to be somewhat general.

First, you've made a small error -- a 12-bit number can represent a number in the range $$0 \cdots 2^{12} - 1$$, i.e. 0 to 4095. If you count those up, you'll see that there are 4096 different choices, and that's all you can represent with 12 bits. Similarly, a q15 bit number can represent a number in the range $$-1 \cdots 1 - 2^{-15}$$ in steps of $$2^{-15}$$. Again if you counted these up you'd find that there are $$2^{16}$$ distinct choices.

Second, the right answer is up to you, and depends on your data and what you're going to do with it.

If your 12-bit data represents some unsigned quantity, then you probably don't want to offset it (i.e., by subtracting $$2^{11}$$ from it). You usually want the number to represent the reality, and you don't want to do extra work. So if your 12-bit data comes from an ADC, and that ADC is measuring a positive quantity such as a voltage from 0 to 40.95V, then why touch anything?

Whether you should prescale the data depends on whether you're designing the FIR filter. A FIR filter implements the convolution $$y_k = \sum_{n = k-N+1}^k a_n x_k,$$ where $$k$$ is the current time, $$a_n$$ are the filter coefficients, and $$x_k$$ is the input variable. If you define your input vector as just being your 12-bit input numbers that you've cast to q15, then those values will be in the range $$0 \le x_k \le \frac{2^{12} - 1}{2^{15}}$$. If you did something like make the input numbers "fit" q15 by shifting them up by 3 then everything in $$x$$ will be eight times bigger.

To get the same answer in each of the above cases, all you do is scale your filter coefficients by a factor of eight. The important part of this is to actually understand how your library code works and how to design a FIR filter so that the computation neither overflows nor loses precision, and you get an answer with the correct scaling.

• THX for extensive explanation, Thats a measured data but signal is sound and because of limitaion in electrical aquisition, is level shifted. Though I think this is not importantn for filters. Just because Q format is limited to -1 to 1. I though maybe it's important to expant our data in in the whole region and using full dynamic range? If that doesn't matter why they've limited region, why they've just did't implement UQ in CMSIS DSP? Commented Mar 13, 2022 at 7:49
• Signal processing just very naturally deals with signed numbers -- hence, there's very little need for unsigned. If your actual voltage input is "signed" and the ADC is offset, I'd recommend going ahead and subtracting 2048 from the number -- you don't lose any information, and you may reduce pops on startup or changing filters. Given that it's audio, you'll probably have a high-pass stage in there, so you don't absolutely have to -- it'll just probably be cleaner. Commented Mar 13, 2022 at 16:45
• Saddly it couldn't be cleaner since The DAC have the positive voltage limitaion also an it can't out th negative numbers, then I have to add 2048 after processing! Commented Mar 14, 2022 at 6:19
• In signal processing terms that's still cleaner! Commented Mar 15, 2022 at 5:26
• You mean to waste computation just for DSP community to think that my code is clean? Commented Mar 15, 2022 at 5:34