Python : How to convert Bytes like object to Array of uint16?

744 Views Asked by At

I have a bytes-like object from a udp stream.

In Matlab I can convert the bytes to a column vector of uint16 by following code:

% Build UDP Connection and collect binary data
udpr = dsp.UDPReceiver('LocalIPPort',5005,'ReceiveBufferSize',3200,'MessageDataType','uint16','MaximumMessageLength',640)
setup(udpr)
data = udpr();

To transform the column vector back to an array with known width (16 columns) I use this code:

rows_result = length(data)/16;
result = zeros(rows_result,16);
pointer=0;
for i=1:rows_result
    for j=1:16
        result(i,j)=data(pointer+j);
    end
    pointer=pointer+16;
end

That way I get a N by 16 Array of uint16 values.

How can I perform something similar in Python?

I use the following code:

import socket
import struct

UDP_IP = "127.0.0.1" 
UDP_PORT = 5005

sock = socket.socket(socket.AF_INET, # Internet
                     socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes

    value_type = type(data)
    value = list(data)
    print(value_type)
    print(value)

The function list() seems to only read the first byte and not the two first bytes I need for the uint16 values.

I tried struct.unpack('H') with no result and I can't find a way to convert my variable "data" the way that is needed.

I also tried int.from_bytes, but I don't know how to tell the function to convert every 2 bytes... and I failed with the array module and array.frombytes()

I would be grateful for help...

best regards Marc

edit 07.12.22: Here is some example data. I create it with numpy. This would be the sender script (sender.py)

import socket
import time
import struct
# generate random integer values
import numpy as np
# seed random number generator
np.random.seed(1)


UDP_IP = "127.0.0.1"
UDP_PORT = 5005

print("UDP target IP: %s" % UDP_IP)
print("UDP target port: %s" % UDP_PORT)


sock = socket.socket(socket.AF_INET, # Internet
                     socket.SOCK_DGRAM) # UDP
#sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))

while True:
    # generate random array of 20x16 values
    input_matrix = np.random.randint(0, 4095, [20,16],dtype=np.uint16)

    print(input_matrix)

    
    MESSAGE = input_matrix
    sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
    time.sleep(3)

For test purpose the Test array size is always the same. Later the number of rows can change.

Here the script for the reciever.py

import socket

UDP_IP = "127.0.0.1"
UDP_PORT = 5005

sock = socket.socket(socket.AF_INET, # Internet
                     socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))


while True:
    data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
    print(data)
1

There are 1 best solutions below

0
Mark Tolonen On

Assuming data is an even number of bytes representing 16-bit data:

>>> import array
>>> data = bytes([1,0,2,0,3,0,4,0,5,0])
>>> data
b'\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00'
>>> a = array.array('H',data)
>>> a
array('H', [1, 2, 3, 4, 5])
>>> a[0]
1
>>> a[4]
5
>>> list(a)
[1, 2, 3, 4, 5]

If the data is big-endian, switch the byte order:

>>> a
array('H', [1, 2, 3, 4, 5])
>>> a.byteswap()
>>> a
array('H', [256, 512, 768, 1024, 1280])