6

I am working on a DSP processor to implement a BFSK frequency hopping mechanism using C on a Linux system. On the receiver part of the program, I am getting an input of a set of samples which I de-modulate using Goertzel algorithm to determine whether the received bit was a 0 or 1.

Right now, I am able to detect the bits individually. But I have to return the data for processing in the form of a float array. So, I need to pack every set of 32 bits received to form a float value. Right I am doing something like :

uint32_t i,j,curBit,curBlk;
unint32_t *outData; //this is intiallized to address of some pre-defined location in DSP memory
float *output;
for(i=0; i<num_os_bits; i++) //Loop for number of data bits
{ 

//Demodulate the data and set curBit=0x0000 or 0x8000

curBlk=curBlk>>1;
curBlk=curBlk|curBit;

bitsCounter+=1;
    if(i!=0 && (bitsCounter%32)==0) //32-bits processed, save the data in array
    {
        *(outData+j)=curBlk;
        j+=1;
        curBlk=0;
    }
}

output=(float *)outData;

Now, the values of the output array are just the values of outData array with 0s after the decimal point. example: if output[i]=12345 the `outData[i]=12345.0000'.

But while testing the program I am generating the sample test data of bits using an array of float float data[] ={123.12456,45.789,297.0956};

So after the demodulation I am expecting the float array output to have a same values as data array. Is there some other method to convert 32-bits of data to a float. Should I store the received bits to a char array and then convert it to float.

Matteo
  • 14,696
  • 9
  • 68
  • 106
anshu
  • 665
  • 4
  • 9
  • 22
  • Method should be correct - bit is bit, nomatter how you use it. Check actual bits before and after transformation, there should be something on this part. – keltar Jul 23 '12 at 11:44
  • @keltar, I have matched the bits that I use in the transmitter part and the demodulated sequence of bits. They are matching with each other. Hence my doubt with the conversion into the float array. – anshu Jul 23 '12 at 11:50
  • It completely doesn't matter what type your array have (well, technically - as long as it's one of unsigned integer types). What type of CPU is it? (wondering about right shift - big endinan?). What kind of 'incorrect' values are you getting? Whatever the problem, i don't think it's in the code posted above - could you make compact working sample representing your problem? – keltar Jul 23 '12 at 11:58
  • The output in float form that I am getting is `output={17142.000000,16951.000000,17300.000000}`, which is the same as the `unsigned int array outData={17142,16951,17300}`. However the output that I am expecting is `data[] ={123.12456,45.789,297.0956}` as the bit sequence that I use as an input into the program for testing is generated from `data[]` array, and the bit sequence that I get after basuc de-modulation step is the same as the test sequence. – anshu Jul 23 '12 at 12:56
  • 3
    If you are trying to get the same numeric value (or close) for float and int, you will need very different bit patterns -- look up the IEEE 754 standard. If you want 32 bits of precision, you'll need to use doubles, not floats. – mpez0 Jul 23 '12 at 15:32
  • Agh... So you getting these floats from int bits, with same values as int was? What the hell of hardware is that? What's float bit layout on this hardware? What's initial float layout and how are you processing it? If you sure about your transformations (whatever it is - i have no ideas), why not just reinterpret initial float to uint32, then back to float? And yes, i'm no longer sure we're talking about the same things... – keltar Jul 24 '12 at 04:58
  • You need to clarify your question. You have mentioned `outData[i]=12345.0000` in the text but `outData` is a `unit32_t` (or would be but for the typo in the code!). – Clifford Jul 24 '12 at 13:22

2 Answers2

6

Not sure if I get your point - you sequentialy obtain bits and if you got 32 bit you want to make a float from them?

what about:

union conv32
{
    uint32_t u32; // here_write_bits
    float    f32; // here_read_float
};

Which can be used like this in-line:

float f = ((union conv32){.u32 = my_uint}).f32;

Or with a helper variable:

union conv32 x = {.u32 = my_uint};
float f = x.f32;
MightyPork
  • 18,270
  • 10
  • 79
  • 133
René Kolařík
  • 1,244
  • 1
  • 10
  • 18
  • 1
    Hi, I tried this: `typedef union { uint32_t here_write_bits; float here_read_float; } test; test t1; t1.here_write_bits=curBlk; \\curBlk holds the 32-bits data in unsigned form printf("int value 1=%d\n",curBlk); printf("int value from union=%d\n", t1.here_write_bits); printf("float value from union=%f\n\n", t1.here_read_float); The output that I am getting is : int value 1=17142 int value from union=17142 float value from union=0.000000 And this is true for multiple inputs that I tried. The float component of the union always remains 0. – anshu Jul 23 '12 at 13:08
  • 1
    note that although that union solution works everywhere tried it is not supported by the C language as defined, so some day you may find a compiler where it doesnt work and it isnt a compiler bug. – old_timer Jul 24 '12 at 01:33
  • Same problem as with Clifford's answer: using a `union` invokes undefined behavior. – cmaster - reinstate monica Jul 14 '15 at 12:20
  • This works fine, and does not violate strict aliasing. – MightyPork Mar 24 '16 at 17:18
  • UB or not, this is the method used by [musl](http://git.musl-libc.org/cgit/musl/tree/include/math.h#n43). If it is good enough for them, then it is probably good enough for most people. – Björn Lindqvist Jan 22 '18 at 18:02
5

You need to copy the bit pattern verbatim without invoking any implicit conversions. The simplest way to do that is to take the address of the data and reinterpret it as a pointer to the intermediate "carrier" type before dereferencing it.

Consider this:

float source_float = 1234.5678f ;
uint32_t transport_bits = *((uint32_t*)&source_float);
float destination_float = *((float*)&transport_bits);

The intermediate result in transport_bits is target dependent, in my test on x86, it is 0x449a522b, this being the bit representation of single precision float on that platform (floating point representation and endianness dependent).

Either way the result in destination_float is identical to source_float having been transported via the uint32_t transport_bits.

However this does require that the floating point representation of the originator is identical to that of the receiver which may not be a given. It is all a bit non-portable, The fact that your code does not work suggests perhaps that the representation does indeed differ between sender and receiver. Not only must the FP representation be identical but also the endianness. If they differ your code may have to do one or both of reorder the bits and calculate the floating point equivalent by extraction of exponent and mantissa. All so you nee to be sure that the transmission order of the bits is is the same order in which you are reassembling them. There are a number of opportunities to get this wrong.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • 3
    Unfortunately, this invokes undefined behavior with strict aliasing rules. There are only two standard compliant ways to do this: 1. filling a `char` array and casting its pointer to a `float*` (strict aliasing rules have an explicit exception for `char` types), or 2. using `memcpy()`. – cmaster - reinstate monica Jul 14 '15 at 12:18