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$

• 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. Sep 11 '11 at 21:27
• Please refrain from adding same comment in response to every answer. And consider the suggestions first before replying, your answer so far shows you haven't made any effort. Hence (-1) Sep 13 '11 at 17:10
• given that the electronics.stackexchange.com question was closed... should this now get upvoted by us? Sep 22 '11 at 15:12

5 Answers

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 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? 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. 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 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 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? 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 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

adc_raw = however_youre_reading_the_ADC();
adc_q15 = (_iq15)(adc_raw << (15 - 12));   // the tricky bit. read below..
adc_q31 = adc_q15 << (31 - 15);


The key here is the the line 'adc_q15 = ...' - you may be tempted to say instead 'adc_q15 = _IQ15(adc_raw);', but that will change an ADC count of 1 into 0x0000_8000, 2 into 0x0001_0000, etc, which is not what you want! Instead, you have to produce a Q15 value that represents the ADC reading in the range of 0 to 1, with half scale at 0.5, etc; this you do by sliding the value left so that the ADC's MSB lines up just to the right of the binary point. As the binary point in Q15 is to the right of bit 15, and the MSB of the ADC is to the right of bit 12, left shift that amount and voila, a normalized ADC value, you just have to cast it to the _iq15 type and you're halfway there! One more shift and you have the same fraction in Q31 format.

Suffixing the variable names like that is just a convention I've found helpful when I have the same data lying around in a bunch of different formats. There may be a macro to do the Q15 to Q31 conversion, something like adc_q31 = IQ15toIQ31(adc_q15), check your IQmathLib.h header file. It can also be done with macros in two steps, as adc_q31 = IQtoIQ31(IQ15toIQ(adc_q15)), though this uses the 'global Q setting', which again could give you incorrect intermediate results if it's not set correctly. The form given in the code snippet is succinct and relatively clear, at least with the Q values explicitly stated as 15 - 12, and 31 - 15, rather than the somewhat more mysterious 3 and 16.

• 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 Sep 17 '11 at 13:24
• If you have a 16 bit ADC, and you just cast the raw int type to a Q15, you should get fixed point values in the range 0.0 to 1.999969.., which is 65535 (for the full scale ADC input) over 32768 (for the Q15 lsb). To change from Q15 to Q31, shift left 31-15=16 bits. Now, Q31 is only good for -1 to +1, so any Q15 greater than 1 will overflow if you do this, so you either have to scale your fixed point ADC values into 0.0 to 1.0, go with Q30, or just take the overflow. Assuming you want the scaled Q31, you need to divide by 2, as well as shift left 16, which is the same as shifting left just 15. Sep 17 '11 at 20:30
• Thanks for your answer. I implemented this now it is working fine. Sep 21 '11 at 8:02
• In my above comment(Q31 value = (Q31) ((q15) (ADC_value-offset))<<15). iam calculating offset like sum of all the input samples (which is read from ADC 16bit data) and dividing by total no of samples as follows.. pResult = (uint16_t) ((uint32_t)sum / (uint32_t)ulnNoofSamp); consider sum is 787635841 and ulnNoofSamp = 20723 if iam dividing this i am getting 38007 but actually i need to get 38007.80973 because of this iam loosing the precision. how can i scale this Please guide me. Sep 21 '11 at 8:12
• @venkibabu - my hunch is that it might not be possible to get that much precision and that much range simultaneously. Q16s, for instance (which I've worked with a lot), only go +/-32767 and are pretty sketchy at the 3rd place after the decimal, rubbish beyond that. There's only so much that can be done with 32 bits of representation. Sep 21 '11 at 10:46