Single-precision float to byte array in MATLAB - matlab

Say I have the following single-precision floating point number in Matlab
a = single(-2.345)
I would like to represent the number as an array of 4 bytes, following IEEE 754. The correct representation should be
b = [123, 20, 22, 192]
Currently, I am using fread and fwrite to do the conversion, as in
fid = fopen('test.dat','wb')
fwrite(fid,a,'float')
fclose(fid)
fid = fopen('test.dat','rb');
b = fread(fid)'
which well enough, but I suspect there is a much easier and faster way to do the conversion without reading/writing from a file.
There have been a few posts about converting a byte array to a float (such as here), but I'm unsure how to proceed to go in the opposite direction. Any suggestions?

You can use the typecast function to cast between datatypes without changing the underlying data, i.e. reinterpret data using another type. In your case, you will want to cast from single to uint8 (byte) datatype. This is done by
a = single(-2.345);
typecast(a,'uint8')
ans =
123 20 22 192
as required.

Related

How to represent double type number in binary form?

How can I represent double type number in binary form, for example:
dec = 3.14159
to an array consists of its IEEE 754 Double precision binary representation as binaryconvert.com does it
bin = 0100000000001001001000011111100111110000000110111000011001101110
in Matlab? I know there is a similar question, but not for Matlab.
You can do the following:
hexdec = num2hex(dec);
bin = hexToBinaryVector(hexdec);
Example:
hexToBinaryVector(num2hex(pi))
ans =
1100000000001001001000011111101101010100010001000010110100011000
This can be done with typecast(...,'uint8') to get invididual bytes; then fliplr to change byte endianness (at least that's needed on my machine); then converting each byte to binary with dec2base(...,2,8); and finally reshape'ing to a single row:
bin = reshape(dec2base(fliplr(typecast(dec,'uint8')),2,8).',1,[]);

reading int16 data in matlab

I read this set of hex values from an accelerometer datalogging:
35AC,2889,1899,0C4A,058B,FD46,F620,F001,EE44,EF08,EF46,F750,007F,0814,1369,21F3,34F0,45CE,5992,6D05,7C12,7FEF,7FF8,7FF8,7FF8,7FF8,7FD9,7F27,74A7,67D8,5826,468F,3621,2573,1326,0441,F88F,F1BF,F082,EADB,EAEE,EE04,F190,F89E,01F5,0B0C,155A,2721,3A20,48DC,5985,676A,721E,7C20,7FF8,7FEE,7F1B,
It should somehow draw a sinusoide curve, but I could not find the right import method for signed int16 and the curve jumps from 0 to 65535.
Could you please help me?
I have tried sscanf(...,'%4x')
The sscanf format for a signed hex int16 is just '%4i'. Unfortunately it expects that hex values will begin with 0x, which yours clearly don't. One possibility is for you to scan it in as you are, and then manually convert it to a signed int16. One possible way of doing this would be the following:
input = sscanf(...,'%4x');
input16 = typecast(uint16(input),'int16');
The values are being read in as a uint32 and automatically converted to double by the sscanf function. So we convert it to a uint16, then typecast it to a 16-bit int (note that just using int16(input) doesn't work, as it doesn't convert values over INT16_MAX to negative values).
string = '35AC,2889,1899,0C4A,058B,FD46,F620,F001,EE44,EF08,EF46,F750,007F,0814,1369,21F3,34F0,45CE,5992,6D05,7C12,7FEF,7FF8,7FF8,7FF8,7FF8,7FD9,7F27,74A7,67D8,5826,468F,3621,2573,1326,0441,F88F,F1BF,F082,EADB,EAEE,EE04,F190,F89E,01F5,0B0C,155A,2721,3A20,48DC,5985,676A,721E,7C20,7FF8,7FEE,7F1B';
%// Your data as a string
string = [string ',']; %// add ending comma to reshape into groups of five chars
strings = reshape(string,5,[]).';
strings = strings(:,1:4); %'// each row is 4 chars representing a hex number
numbers = hex2dec(strings); %// convert each row to a number
ind = numbers>=32768;
numbers(ind) = numbers(ind)-65535; %// get rid of jumps
plot(numbers)
thank a lot
Both previous answer were there too.
sscanf alternative assumed to be faster.

Increase Hex2dec or dec2hex output range in Matlab

I have a strange problem with hex2dec function in Matlab.
I realized in 16bytes data, it omits 2 LSB bytes.
hex2dec('123123123123123A');
dec2hex(ans)
Warning: At least one of the input numbers is larger than the largest integer-valued floating-point
number (2^52). Results may be unpredictable.
ans =
1231231231231200
I am using this in Simulink. Therefore I cannot process 16byte data. Simulink interpret this as a 14byte + '00'.
You need to use uint64 to store that value:
A='123123123123123A';
B=bitshift(uint64(hex2dec(A(1:end-8))),32)+uint64(hex2dec(A(end-7:end)))
which returns
B =
1310867527582290490
An alternative way in MATLAB using typecast:
>> A = '123123123123123A';
>> B = typecast(uint32(hex2dec([A(9:end);A(1:8)])), 'uint64')
B =
1310867527582290490
And the reverse in the opposite direction:
>> AA = dec2hex(typecast(B,'uint32'));
>> AA = [AA(2,:) AA(1,:)]
AA =
123123123123123A
The idea is to treat the 64-integer as two 32-bit integers.
That said, Simulink does not support int64 and uint64 types as others have already noted..

easiest way to serialize multi-dimensional array in MATLAB for database insertion?

I can't seem to find any standard functions for serializing data. I have a large 128x51 array that I need need to store in a single database field. Without some kind of serializing, things will be problematic.
Whats the best way to solve this? I don't use matlab quite that much so I'm not familiar with standard procedures...
One possibility is to use the TYPECAST function to convert numeric values into UINT8 bytes (only works for full, non-complex numeric values).
Note that the matrix has to be reshaped into a vector prior to serialization, thus its size will also have to be separately stored (or even serialized using the same process):
%# sample matrix
M = rand(3,4);
%# convert
b_sz = typecast(size(M),'uint8'); %# serialized matrix size
b = typecast(M(:),'uint8'); %# serialized vector
Now you can store b and b_sz into the database as sequences of bytes (integers in the range [0,255])
>> whos b b_sz
Name Size Bytes Class Attributes
b 96x1 96 uint8
b_sz 16x1 16 uint8
Next, when you retrieve those values from DB, you can convert them back to double values using the inverse procedure, and reshape the matrix to its original size:
MM = reshape(typecast(b,'double'), typecast(b_sz,'double'));
%# compare against original matrix
isequal(M,MM)
Optionally, if your database does not support array types, you can just convert the byte sequence as string, and store it in a VARCHAR type of field:
%# as string
str = sprintf('%d ',b);
%# recover bytes from string
b = uint8(str2num(str));
I'm not sure if I'm grasping your question correctly, but have you tried looking at the reshape function? It reshapes the input matrix A into an m by n matrix:
B = reshape(A,m,n);
if you set m to 1, and n to (128*51), you are 'serializing' the data.
MATLAB Documentation

32 bit hex to 32 bit floating point (IEEE 754) conversion in matlab

How can I change the 32 bit hex-value to a floating point value according to the IEEE 754?
EDIT:
...
data = fread(fid,1,'float32');
disp(data);
...
I get this answer:
4.2950e+009
1.6274e+009
...
But how do I get 32 bit floating point (IEEE 754) numbers?
Based on one of your comments it appears that your hexadecimal values are stored as strings of characters in a file. You first want to read these characters from the file in groups of 8. Depending on the specific format of your file (e.g. each set of 8 characters is on its own line, or they're separated by commas, etc.), you could use functions like FSCANF or TEXTSCAN to do this. For example, if your data file looks like this:
409BFFFF
3B3C0000
85E60000
Then you can read the data into a character array like so:
fid = fopen(fileName,'r'); %# Open the file
data = textscan(fid,'%s'); %# Read the data
charArray = char(data{1}); %# Create a character array
fclose(fid); %# Close the file
Now you need to convert these 32-bit hexadecimal strings to single-precision representations. The easiest way by far is to use the function HEX2DEC to convert the strings to integers (stored as double-precision values), convert them to unsigned 32-bit integers using the function UINT32, then cast the 32-bit integers to single-precision representations using the function TYPECAST. Applying this to the sample data I have above gives these results:
>> values = typecast(uint32(hex2dec(charArray)),'single');
>> fprintf('% 1.42f\n',values); %# Display the values
4.874999523162841800000000000000000000000000
0.002868652343750000000000000000000000000000
-0.000000000000000000000000000000000021629096
You can confirm that these results are correct using this online hexadecimal-to-floating-point converter.
In case anyone is interested, you can do the above type conversion yourself using the function HEX2DEC to first convert the string to an integer representation, then the function BITGET to extract and process the bits for the sign, exponent, and fraction of the single-precision number. For example:
>> a = '409BFFFF'; %# A sample hexadecimal value
>> b = hex2dec(a); %# Convert to an integer
>> sign = bitget(b,32); %# Compute the sign
>> exponent = bitget(b,24:31)*2.^(0:7).'; %'# Compute the exponent
>> fraction = bitget(b,1:23)*2.^(-23:-1).'; %'# Compute the fraction
>> value = (-1)^sign*(1+fraction)*2^(exponent-127); %# Compute the value
>> fprintf('%1.7f\n',value) %# Display the value
4.8749995