Read binary data as three UBYTE (8-bit Unsigned Byte) in MATLAB and use bit shift operators to get two 12 bit streams
Show older comments
I need to read the data as UBYTE (8-bit Unsigned Byte) in MATLAB and then used bit shift operators to get two 12-bit streams with 3600000 samples. I have to do that by a command that: the first two 12 bit values are contained in the first 3 UBYTEs, 8 bits from the first byte with the first 4 bits from the second byte, then the first 4 bits from byte 2 with all 8 bits from byte 3. Then the process repeats with the next 3 bytes (byte 4-6 etc.) and so on. The related commands are as follows.
How can I apply this command in MATLAB?
3 Comments
Walter Roberson
on 15 Dec 2020
Odd. If the stream were 123456 hex then the result would be 0312 and 0645. Not common.
However this does not tell us which is the Most Significant Byte. It looks likely to me that the 03 and 06 would be intended as the MSB. But x64 architecture uses Little Endian order where the first memory byte is the least significant, so you need to be careful about value. The bit operations are not defined in terms of numeric results
Walter Roberson
on 21 Dec 2020
You do not need to read three bytes and do shift arithmetic. I show how you can read ubit4=>ubit16 and then put together the nibbles.
Accepted Answer
More Answers (1)
Walter Roberson
on 16 Dec 2020
0 votes
I believe that you should be able to implement the needed transformation by using fread() with 'ubit12=>uint16' and then using swapbytes() https://www.mathworks.com/help/matlab/ref/swapbytes.html
6 Comments
According to the question as originally posted, which clearer about the bit order, we are looking for 0312 0645. Can we get that?
testnibbles = [0x01 0x02 0x03 0x04 0x05 0x06];
testbytes = testnibbles(1:2:end) * 16 + testnibbles(2:2:end);
dec2hex(testbytes, 2)
filename = tempname;
cleanMe = onCleanup(@() delete(filename));
[fid, msg] = fopen(filename, 'w+');
if fid < 0; error('failed to open file "%s" because "%s"', filename, msg); end
writecount = fwrite(fid, testbytes, 'ubit8');
frewind(fid);
test4LE = fread(fid, [1 inf], 'ubit4=>uint8', 'ieee-le')
dec2hex(test4LE, 2)
Uh-oh, if we read 4 bits at a time in the (default) ieee-le mode, the order of elements is not what we expect
frewind(fid);
test4BE = fread(fid, [1 inf], 'ubit4=>uint8', 'ieee-be')
dec2hex(test4BE, 2)
The order looks good if we read 4 bits at a time with ieee-be
frewind(fid)
test8LE = fread(fid, [1 inf], '*ubit8', 'ieee-le')
dec2hex(test8LE, 2)
frewind(fid)
test8BE = fread(fid, [1 inf], '*ubit8', 'ieee-be')
dec2hex(test8BE, 2)
but reading 8 bits at a time is fine no matter whether we use ieee-le or ieee-be
frewind(fid)
test12LE = fread(fid, [1 inf], 'ubit12=>ubit16', 'ieee-le')
dec2hex(test12LE, 4)
Not so good -- ubit12 with ieee-le has read the LSB of the third byte instead of the MSB of the third byte
frewind(fid)
test12BE = fread(fid, [1 inf], 'ubit12=>ubit16', 'ieee-be')
dec2hex(test12BE, 4)
ubit12 with ieee-be has read the MSB of the third byte as we would hope. But it did not put the nibbles at the place in the byte stream that we were hoping for
test12LEs = swapbytes(test12LE)
dec2hex(test12LEs, 4)
Not what we want because ubit12 ieee-le did not read the bits we wanted
test12BEs = swapbytes(test12BE)
dec2hex(test12BEs, 4)
Not what we were hoping for either, as the nibbles were not packed at the place in the byte stream that we were hoping for. We are hoping for 0312 according to the original post
right_order = uint16(uint16(test4BE(3:3:end)) * 256 + uint16(test4BE(1:3:end)) * 16 + uint16(test4BE(2:3:end)))
dec2hex(right_order, 4)
Putting that all together:
frewind(fid);
BE4 = fread(fid, [1 inf], 'ubit4=>ubit16', 'ieee-be');
right_order = BE4(3:3:end) * 256 + BE4(1:3:end) * 16 + BE4(2:3:end)
dec2hex(right_order, 4)
fclose(fid);
Thus, for the sections that you need 12 bits at a time, fread() them using ubit4 => ubit16 and ieee-be, and then do simple arithmetic calculations according to the positions you want the nibbles to show up in in the result. The right_order can obviously be changed if you need a slightly different order of nibbles, just by changing which group is multiplied by 256 and which group is multiplied by 16.
Eliza
on 19 Dec 2020
Walter Roberson
on 20 Dec 2020
You originally posted C type code for the value reconstruction. For reasons unknown to me, you removed that part. But before you removed it I had already posted showing the nibble order reconstruction implied by the code, 0312 0645. That does not involve multiplying the first byte by 256: it involves multiplying the first nibble of the second byte by 256.
If you multiply the first byte by 256 then the result is going to exceed 1000 unless the first byte is no more than 3, which would require that the first nibble would always have to be 0 in the data. Also since you would have used both of the first two nibbles when you multiplied the byte by 256, the second byte would have to have a value constructed only of the third nibble, and you would only be able to reach near 1000 if the third nibble was multiplied by 16, leading to a reconstruction order of 0x1230 and the data would have had to had nibble 1 be 0 and nibble 2 be no more 3 in value, leading to 0x0230 nibble reconstruction, so one of 00X0, 01X0, 02X0, 03X0 where X is the third nibble... less than 64 valid data combinations.
I think you should reconsider your statement that the first byte needs to be multiplied by 256. Your C code multiplied one the nibbles by 256, not one of the bytes.
Eliza
on 20 Dec 2020
As you seem to think that you need a version with arithmetic operations, here is one. It consists of reading the data as uint8, breaking the bytes into nibbles, and doing simple calculations with nibbles.
You will notice that it produces the same result as using ubit4=>uint16. So you can either read the data with ubit4 and do a very small bit of arithmetic on the nibbles, or you can read the data as ubit8 and do more arithmetic on the bytes
testnibbles = [0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c];
testbytes = testnibbles(1:2:end) * 16 + testnibbles(2:2:end);
dec2hex(testbytes, 2)
filename = tempname;
cleanMe = onCleanup(@() delete(filename));
[fid, msg] = fopen(filename, 'w+');
if fid < 0; error('failed to open file "%s" because "%s"', filename, msg); end
writecount = fwrite(fid, testbytes, 'ubit8');
frewind(fid);
%reading logic begins here
test8BE = fread(fid, [1 inf], 'ubit8=>uint16', 'ieee-be')
dec2hex(test8BE, 2)
nibble1 = bitand(test8BE, uint16(240)) / 16;
nibble2 = bitand(test8BE, uint16(15));
BE4 = reshape([nibble1; nibble2], 1, [])
right_order = BE4(3:3:end) * 256 + BE4(1:3:end) * 16 + BE4(2:3:end)
dec2hex(right_order, 4)
fclose(fid);
Eliza
on 22 Dec 2020
Categories
Find more on Low-Level File I/O in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!