DSPRelated.com
Forums

Datasheet Question

Started by Mauritz Jameson August 26, 2015
glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:

> Randy Yates <yates@digitalsignallabs.com> wrote: > > (snip) >>>> It's a Q2.12 (note I would denote this as an A(1, 12)). The maximum >>>> positive scaled (unscaled) value is 2 - 1/4096 (8191), and the minimum >>>> negative scaled (unscaled) value is -2 (-8192). > >>>> To get the scaled value x from the unscaled value X, >>>> divide by 2^12 = 4096: > >>> But the original question is how to make a decimal fraction >>> out of it. > >> You mean with a computer program (as opposed to, e.g., on your >> calculator)? > > Yes. > >> Wouldn't > >> double DecimalFraction(int16_t x) >> { >> return x / 4096.0; >> } > >> do it (where x is the Q2.12 input value)? > > That converts, at least on most machines, to a binary floating > point value. > > For machines supporting IEEE 754-2008, that could be decimal > float, but usually I expect to convert to fixed decimal. > > Since 12 bits are about four decimal digits, you might convert > to a fixed point decimal value with four digits after the decimal > point. > > If you mulitiply x by 10000, then divide by 4096, you have > the integer value of 1/10000ths (truncated) of the quantity in x. > > For a more common example, multiply x by 100, integer divide by 4096, > and if X is in dollars and binary fractions of dollars, you get the > value as an integer number of cents. Add 2048 before the divide > to get the rounded up value. > > int x,y > x=123456; /* that is 123456/4096ths */ > y=(x*100)/4096; > printf("%d.%02d\n",y/100, y%100); > > Analogous to the Q2.13 form, the y value has two decimal digits > after the decimal point, even when stored as a binary value. > > (PL/I would call it FIXED DECIMAL(5,2), where X might > be FIXED BIN(15,12)). > > -- glen
glen, I think this is WAY over-complicating things and not at all what the OP wanted. I think he said "decimal" but really meant "float." -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
Randy Yates <yates@digitalsignallabs.com> writes:

> Mauritz Jameson <mjames2393@gmail.com> writes: > >> So do everybody agree that the PDF states that the 2 bytes together form a Q2.12 number and *this*: >> >> double x = ((double) ((((int16_t)(MSB << 8)) | LSB) >> 2)) / 4096.0; >> >> is how the two bytes should be interpreted (as a double value) ? >> >> (I guess I'm having a hard time asking the right question) > > I don't think that's right. I would say this: > > double x = ((double) ((((int16_t)(MSB << 6)) | LSB) >> 2)) / 4096.0;
This is not right either - the MSB won't be sign-extended. But I think this would work: double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; Note that the (double) typecast in the original expression from the datasheet is not necessary due to the default double type of the constant 4096.0 and C's promotion rules. -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
Randy Yates <yates@digitalsignallabs.com> writes:

> Mauritz Jameson <mjames2393@gmail.com> writes: > >> So do everybody agree that the PDF states that the 2 bytes together form a Q2.12 number and *this*: >> >> double x = ((double) ((((int16_t)(MSB << 8)) | LSB) >> 2)) / 4096.0; >> >> is how the two bytes should be interpreted (as a double value) ? >> >> (I guess I'm having a hard time asking the right question) > > I don't think that's right.
Ooops - Yes it is - I missed the parenthesis to the right of the "LSB". Sorry for the confusion. I do think the (double) typecast is unnecessary, though, as I explained in a subsequent follow-up. -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
> This is not right either - the MSB won't be sign-extended. But I think > this would work: > > double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; >
Exactly! You have to shift 8 up to ensure sign extension when you later shift down by 2. So I guess you agree with me Randy :-) This is the expression I wrote in one of my earlier posts: double x = ((double) ((((int16_t)(MSB << 8)) | LSB) >> 2)) / 4096.0;
Mauritz Jameson <mjames2393@gmail.com> writes:

>> This is not right either - the MSB won't be sign-extended. But I think >> this would work: >> >> double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; >> > > > Exactly! You have to shift 8 up to ensure sign extension when you > later shift down by 2. So I guess you agree with me Randy :-)
Yes, I do. -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
> > Wow, that is brain-damaged.
Yeah, the description in the PDF is a bit awkward which is why I posted my question in this group (to get some clarification).
Randy Yates <yates@digitalsignallabs.com> wrote:

(snip, I wrote)
>> For machines supporting IEEE 754-2008, that could be decimal >> float, but usually I expect to convert to fixed decimal.
>> Since 12 bits are about four decimal digits, you might convert >> to a fixed point decimal value with four digits after the decimal >> point.
>> If you mulitiply x by 10000, then divide by 4096, you have >> the integer value of 1/10000ths (truncated) of the quantity in x.
>> For a more common example, multiply x by 100, integer divide by 4096, >> and if X is in dollars and binary fractions of dollars, you get the >> value as an integer number of cents. Add 2048 before the divide >> to get the rounded up value.
>> int x,y >> x=123456; /* that is 123456/4096ths */ >> y=(x*100)/4096; >> printf("%d.%02d\n",y/100, y%100);
(snip)
> I think this is WAY over-complicating things and not at all what the OP > wanted. I think he said "decimal" but really meant "float."
That could be, which is why I suggested float decimal. Otherwise, I don't see how to get them confused. But from what he is actually doing, you might be right. -- glen
On 8/27/2015 9:50 PM, Mauritz Jameson wrote:
> >> OK, why the >>2? >> >> Seems to me that loses the two low order bits. >> That, combined with the /4096, means 14 bits after the binary point, >> only 12 of them actually get into x. >> >> -- glen > > > The MSB byte has 8 bits of data where the most significant bit is the sign bit. > > The LSB byte has 6 bits of data where the most significant bit of those 6 bits is placed at bit 7 (counting from 0). > > So the logic behind the C-expression is: > > 1. Cast MSB to a 16-bit signed value and shift it up by 8 > 2. OR the LSB with the result of [1] > 3. Now we have a 14-bit value where the 2 least significant bits are 0 (remember that the LSB only had 6 bits of data) > 4. So shift the result of [2] down by 2 > 5. Typecast the result of [4] to a double > 6. Divide by 4096.0 (since it's a Q2.12 value) > > Does it make sense?
Yes -- Rick
On 8/27/2015 11:59 PM, Randy Yates wrote:
> Mauritz Jameson <mjames2393@gmail.com> writes: > >>> This is not right either - the MSB won't be sign-extended. But I think >>> this would work: >>> >>> double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; >>> >> >> >> Exactly! You have to shift 8 up to ensure sign extension when you >> later shift down by 2. So I guess you agree with me Randy :-) > > Yes, I do.
Not exactly. Randy's code converts MSB to a 16 bit quantity first, then shifts. Mauritiz's code shifts then type casts as a 16 bit quantity. If MSB is an 8 bit quantity shifting before converting type will lose all the data giving a zero value. -- Rick
On 8/27/2015 11:59 PM, Mauritz Jameson wrote:
>> >> Wow, that is brain-damaged. > > Yeah, the description in the PDF is a bit awkward which is why I posted my question in this group (to get some clarification).
I think some people are stuck on the idea that all 16 bits read from the converter are data. The description is not so awkward as far as I can tell. -- Rick