# FIXED POINT conversion Problem (DSP)

Actually after reading the data from ADC is an $Q15$ format (ie. ADC supports 0-3.3v, ADC is an unipolar type). then the $Q15$ data is converted to $q31$ format ($Q31$ value = $q15_{data}$ <<16). this $Q31$ value is fed in to FIR filter (FIR filter is an $Q31$ format) then filter output is fed in to the fftr(real fft).

Iam facing the problem like if my input is more than 600mv the value of the $Q31$ (after filter stage) is exceeding the $2^{31}$($q31$) limit. Kindly give some suggestion how to solve this problem.

My ADC output is 16bit (ADC MAX vge is 0-3v unipolar type). then this value i am converting to $Q31$ as follows uint_16 ADC_value;\ADC value $Q31$ value = (Q31) ((q15) (ADC_value-offset))<<16; \ here offset is (unipolar to bipolar conversion ie. AVG of ADC_value )16 bit to $Q15$ conversion

if my input voltage is more than 600mv $Q31$ value is not correct.

Kindly suggest me how to convert $Q15$ to $Q31$

• – Paul R Sep 8 '11 at 10:06
• Please only post once on Stack Exchange. If you need to make changes just make an edit to your first question instead of making new questions. If the question needs to go to another site it can be migrated. – Kellenjb Sep 11 '11 at 21:27
• given that the electronics.stackexchange.com question was closed... should this now get upvoted by us? – Trevor Boyd Smith Sep 22 '11 at 15:12

If you are pretty sure that the problem is not with the ADC, meaning that the input to the FIR is as expected then the problem might be the following:

Your input is in Q31 and as I understand from your post that coefficients are also represented in Q31. If your output is also represented in Q31 you will have problems if your code looks something like this

// compute one output sample of FIR
int outputQ31 = 0;
int iC;
for(iC = 0; iC < N; iC++)
{
outputQ31 += input[iC] * coefficiets[iC];
}


Here two 32 bit integers in Q31 are multiplied and saved in an int. The result of the multiplication is a 64 bit number in Q62 that doesn't fit in an int. You will need to shift it down like this:

int outputQ31 = 0;
int iC;
for(iC = 0; iC < N; iC++)
{
outputQ31 += (input[iC] * coefficiets[iC]) >> 31;
}


Do you have that shift in your code?

Another issue is that you might was to do a rounding instead of a truncation.

Another issue is that you might want to save the result in a 64 bit accumulator such that you only do the rounding/truncation in the end (be careful that the result doesn't wrap around!).

• My ADC output is 16bit(ADC MAX vge is 0-3v unipolar type). then this value i am converting to Q31 as follows uint_16 ADC_value;\ADC value Q31 value = (Q31) ((q15) (ADC_value-offset))<<16; \ here offset is (unipolar to bipolar conversion ie. AVG of ADC_value )16 bit to Q15 conversion if my input voltage is more than 600mv Q31 value is not correct. Kindly suggest me how to convert Q15 to Q31 – venkibabu Sep 17 '11 at 13:24
• How would your code work without a 64-bit accumulator? Does rounding vs truncation really make any difference at 32-bit? Wouldn't that just be in the noise floor anyway? – endolith Jun 26 '14 at 17:46
• You mean in the case of 32 bit input to a FIR filter with coefficients represented with 32 bit precision? I'm not sure it matters much in practice but there might be some places where it matters. If the accumulator is 32 bits wide then there is a truncation after each multiplication. If the accumulator is 64 bits there is only one in the end. – niaren Jun 27 '14 at 20:13

If your filter is saturating/overflowing if the input data is getting above 600mV then you will need to reduce the value that is being fed into the filter or scale the filter coefficients so that the gain in the filter stage is not going to cause the values to overflow.

You do not say but if the DSP operates on 32 bit data It would be easy to reduce the input data to the filter by a factor of 8 (only shift up by 13 bits) so that the 2^31 value will not be exceeded until the input reaches 4.8V. If the DSP operates on the full 32 bit data then there will be no loss of resolution in the input signal.

Scaling the filter coefficients may not be quite so easy.

• My ADC output is 16bit(ADC MAX vge is 0-3v unipolar type). then this value i am converting to Q31 as follows uint_16 ADC_value;\ADC value Q31 value = (Q31) ((q15) (ADC_value-offset))<<16; \ here offset is (unipolar to bipolar conversion ie. AVG of ADC_value )16 bit to Q15 conversion if my input voltage is more than 600mv Q31 value is not correct. Kindly suggest me how to convert Q15 to Q31 – venkibabu Sep 17 '11 at 13:24

Have you checked whether your Q15 doesn't clip in the first place? If that's clean, you may have the wrong data types for some variables. To be safe all variables (Q31, Q15, offset, 2^16) should signed 32-bit integers. What lanuage do you use?

• My ADC output is 16bit(ADC MAX vge is 0-3v unipolar type). then this value i am converting to Q31 as follows uint_16 ADC_value;\ADC value Q31 value = (Q31) ((q15) (ADC_value-offset))<<16; \ here offset is (unipolar to bipolar conversion ie. AVG of ADC_value )16 bit to Q15 conversion if my input voltage is more than 600mv Q31 value is not correct. Kindly suggest me how to convert Q15 to Q31 – venkibabu Sep 17 '11 at 13:24

Either I haven't understood the question or it lacks details. Let me try to understand: You have an ADC giving a 16 bit output (which YOU are INTERPRETING as Q15). YOU then convert it to Q31 format, shifting left by 16 bits. The converted value is fed to FIR filter, from which the output goes to FFT.

What do you mean by exceeding 2^31 limit. Is it overflowing? Saturating? I'd assume so anyway.

My gut feeling is that your filter coefficients are not scaled enough and hence the filter output is incorrect when the filter input value increases to a certain level.

What is the order of your FIR filter?

I'd start by making sure that the input to my filter is absolutely correct - easy to check. Then debug each stage of your filter. Are you sure your filter implementation is correct? If the order of filter is high, chances are that MAC operations are leading to an overflow.

So, in summary: Look out for coefficient scaling, ensure filter input is correct and check if filter implementation is correct by feeding in a known vector.

• Adding same comment to every response will not help. You didn't answer any of my questions. Filter order? Scaling? Saturation? – anasimtiaz Sep 13 '11 at 17:09
• My ADC output is 16bit(ADC MAX vge is 0-3v unipolar type). then this value i am converting to Q31 as follows uint_16 ADC_value;\ADC value Q31 value = (Q31) ((q15) (ADC_value-offset))<<16; \ here offset is (unipolar to bipolar conversion ie. AVG of ADC_value )16 bit to Q15 conversion if my input voltage is more than 600mv Q31 value is not correct. Kindly suggest me how to convert Q15 to Q31 – venkibabu Sep 17 '11 at 13:24

It shouldn't overflow like that. If you look at the ADC value as a raw count of 0 to 4095, which is just 12 bits, and you shift it over 16 bits, it shouldn't take more than 28 bits to hold the result.

I would bet that what's happening is that you are treating the value as an integer, rather than a fraction. Numbers are very slippery things with the ezDSP compiler, it's easy to accidentally do this. Remember that Q numbers represent fractional values using the number of bits after the Q for fractions. So the value of unity in Q15 is 0x0000_8000, while in Q31 it is 0x4000_0000. The value of 4095 in Q15 is 0x07ff_8000, not 0x0000_0FFF; if you shift the latter value left 16 places, you have no problem, but shift the other one the same and you lose bits. So what you need to do is represent the ADC reading as a fraction in the range of 0 to 1, rather than as a raw integer.

If you innocently try to read the ADC value and massage it into a Q30 all in one expression, the compiler is apt to do some intermediate casts that will surprise you. It may be ugly, but with the ezDSP and in particular with ADC code on the ezDSP, I've found it best to break such conversions into small steps. Something like so ..

int adc_raw;    // a plain int representation
_iq15 adc_q15;    // Q15 holder for the same data
_iq31 adc_q31;    // Q31 holder for same