0

I have a program in Simulink to send some values through TCP-IP and to read them in Python 2.7. The data is sent as "single" values. The code in Python reads that as 4 strings as its 32 bits long (string of length 4).

print "x0:", ord(data[0])
print "x1:", ord(data[1])
print "x2:", ord(data[2])
print "x3:", ord(data[3])

The problem is, I get some different values in Python than that being sent.

0.125 is read as x0: 62, x1: 0, x2: 0, x3: 0
13.65 is read as x0:65, x1=90, x2: 96, x3: 0
51.79 is read as x0:66, x1=79, x2: 42, x3: 128
113.4 is read as x0:66, x1=226, x2: 200, x3: 220

So how to get these values... 0.125, 13.65, 51.79, 113.4, ... as proper numbers on the receive side (Python)?

Haroon
  • 3
  • 7
  • Oh yes sorry I corrected the question, so still I dont find the meaning/pattern in the data received. How to get the proper data now? – Haroon Feb 27 '18 at 13:05

1 Answers1

1

Use struct to unpack the 4-byte float that you are getting off the wire.

>>> import struct
>>> patt='!f'    # big-endian single-precision float, 4 bytes
>>> _0_125 = chr(62)+chr(0)+chr(0)+chr(0)
>>> struct.unpack(patt,_0_125)
(0.125,)   
>>> _13_65 = chr(65)+chr(90)+chr(96)+chr(0)
>>> struct.unpack(patt,_13_65)
(13.6484375,) 
>>> _51_79 = chr(66)+chr(79)+chr(42)+chr(128)
>>> struct.unpack(patt,_51_79)
(51.79150390625,)

This gives you a tuple back because there could be more than one data item in the bytestring you pass to unpack.

I've had to recreate the bytestrings from your question using chr(). If you already have a bytestring in x then struct.unpack(patt,x) will do the trick.

The data you see in byte form appears unrelated to the values you are expecting because it is in IEEE754 format. The data is binary and byte boundaries are meaningless:

  • Bit 31: Sign (0 = positive, 1 = negative)
  • Bits 30 to 23: Exponent, biased by 127
  • Bits 22 to 0: Fraction f of the number 1.f (where . means a binary point)
BoarGules
  • 16,440
  • 2
  • 27
  • 44
  • Thank you very much. It works. But what if I have something like "Hello: 2.5" being sent? Will that be a tuple like (H , e , l , l , o , : , 2.5) or what? Sorry its simple and silly to ask but my input cannot be changed now to that so I cannot test. – Haroon Feb 28 '18 at 09:55
  • In this situation you have to know exactly what data you are expecting. All you get is a string of bytes. You have to know in advance what they represent because there is no reliable way to tell by looking at them. For example the 4 bytes that represent the float 13.6484375 could also be the ascii string `"AZ``"` (but only one backquote, it's hard to format that correctly) with a null terminator at the end. You can see this if you do `struct.unpack("!4s",_13_65)`. – BoarGules Feb 28 '18 at 10:37
  • `struct.unpack('!10s','Hello: 2.5')` (looking for a string of length 10) will give you `('Hello: 2.5',)`. On the other hand, `struct.unpack('!fff','Hello: 2.5\00\00')` (looking for 3 floats of 4 bytes) will give you `(234929.6875, 5.7603133571321994e+28, 4.1154635255225e-11)`. Note that I had to pad out the string with nulls to 12 bytes because `unpack()` knows that it needs 4 bytes per float. – BoarGules Feb 28 '18 at 10:57
  • Got it! Thank you very much :) – Haroon Feb 28 '18 at 13:26