Problem with Unpack Block

4 views (last 30 days)
Musa
Musa on 27 Mar 2025
Commented: Musa on 29 Mar 2025
I need help with Simulink UDP Recieve and the Unpack blocks. I am using a C++ code to stream data from two sensors in our lab via UDP into a Simulink UDP block on the same computer. Each frame of my data contains 10 int_32 values. The first int_32 value is either a 0 or a 1 to indicate which of two sensors is the current frame associated with. The rest of the 9 are the payload data from the sensor.
After receiving the frames from the UDP packet, I also use a Display block to monitor the raw byte values. When I put the byte values in the Display block into a vector and call the char() function on the vector, I get the same signal frame that was sent from each sensor. However, the output from the Unpack block is made of some weird numbers. For instance, when I parse the outputs from the Unpack block into two - (1) sensor identity and (2) payload, the identity value switches between 8240 and 8241 instead of 0 and 1. The payload data is also made up of weird numbers not similar to the actual sensor data. A typical frame of raw data from the sensors appears as this: 0 76 -99 9863 -10 8 -1 184 -87 -56. Can anyone help me? NOTE: In the Unpacking block setting, the same problem using Byte alignment of 1 or 4.
  4 Comments
Musa
Musa on 27 Mar 2025
Fabulous! Thank you very much Walter. I'll have to research the "why", but for now, you're the man! Cheers.

Sign in to comment.

Accepted Answer

Gordon
Gordon on 28 Mar 2025
I worked at MathWorks for 22 years and retired last year after working on XpcTarget and then the renamed Simulink Real Time. I have some expertise in this area. Since I'm retired, I'm using a home version of Matlab and Simulink and I don't have current access to Simulink Real Time.
I notice that you have the UDP block configured to output an array of int8 values.
Inspection of the values shown in the display block quickly convinced me that you have formated ascii values.
For instance, If I type the values into an array and then convert that array to char, I see a nice string of values just like the prototype you listed in your post. Your C++ is outputing ascii text.
You don't need the pack block at all. There is a much easier way to get the numbers out.
>> s = [49 32 49 55 32 45 55 54 32 57 56 52 48 32 45 54 32 45 49 32 50 32 49 50 55 32 45 49 50 54 32 45 53 57 56 32 54 32 32 32 45 53 57 49 32 50 56 32 32 32]
s =
Columns 1 through 16
49 32 49 55 32 45 55 54 32 57 56 52 48 32 45 54
Columns 17 through 32
32 45 49 32 50 32 49 50 55 32 45 49 50 54 32 45
Columns 33 through 48
53 57 56 32 54 32 32 32 45 53 57 49 32 50 56 32
Columns 49 through 50
32 32
Take a look at the whole array as text:
>> char(s)
ans =
'1 17 -76 9840 -6 -1 2 127 -126 -598 6 -591 28 '
Use the length of 36 from the UDP block to limit how much is really significant:
>> char(s(1:36))
ans =
'1 17 -76 9840 -6 -1 2 127 -126 -598 '
Change the char array so that it has a zero in s(length+1) to make it a null terminated C string. The values after that are left over from a previous UDP output packet. The length will change each time, so you need to use length in your model.
Now that you know what the representation is, you need to do this in a Simulink model. For this case, it is probably easiest to use a function block to do all the parsing. I'm assuming that you want to separate this into two different streams, one for device 0 and one for device 1.
The function block needs two inputs, one for the data from UDP and another for the length. If necessary, you could also mux those together with the length and data in a single array. It's easy to split those inside a function block.
It's getting late, and I need to do some trial and testing. I'll work on it again in the morning.
  6 Comments
Gordon
Gordon on 28 Mar 2025
Walter,
I verified that it does indeed work inside a Matlab function block. This is a variable with Matlab behavior inside the function block. Only the external behavior going to Simulink needs to be fixed size. That's insured by the line y = y1(2:10) which is always 9 elements long. At least it works when compiled into a model running in Simulink.
Musa,
My prototype of a Matlab function block to retrieve the numerical values from the ascii is just a start. You can add code there to look at the device code and copy the data to two different output signals. Call them dev0data and dev1data for instance. Then if device is 0 copy the data to the dev0data signal. Similarly write to dev1data if device is 1. If both dev0data and dev1data are persistent variables, then the one you just got data for will update without changing the other one, if that's what you want.
You can also use the 'ascii decode' block from the rs232 section to essentially do the same decode without resorting to the Matlab function block. It's very easy to use 2 enabled subsystems, one enabled when device == 0 and the other enabled when device == 1. The subsystems just need an in port connected to an out port and they act like digital latches if the enable block is set to hold when not enabled.
If you are running on a Speedgoat target machine, then the timer is used to call the UDP block which can then return a 0 length packet if you haven't received anything since the last update. The UDP block does not sleep waiting for a packet. You'll need to use the length signal from the UDP block to enable processing.
If you are running in Simulink then the UDP block works like a timer with the timing interval coming from the UDP source data. The UDP block will wait for data, pausing execution of the model. I believe this is the way the host side UDP block works, but I'm not positive about this. I didn't work with the host side UDP block.
Musa
Musa on 29 Mar 2025
Thank you very much Gordon. I'll follow your lead on this since our ultimate aim is to channel the signals from the sensors to the Speedgoat machine for some real-time control. Your insight will be very invaluable in achieveing that aim. We will definitely gain from your experience and wisdom on this matter. Cheers.

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 27 Mar 2025
Edited: Walter Roberson on 27 Mar 2025
The values in the display of Message are consistent with the UDP packet being text data instead of binary data. For example the first two rows of the display are
char([49 32 49 55 32 45 55 54])
ans = '1 17 -76'
This is not the UDP Receive block parsing binary data weirdly: this is the bytestream actually being received from the source is text instead of binary.
  1 Comment
Walter Roberson
Walter Roberson on 27 Mar 2025
The 8241 occurred because uint8([49 32]) when interpreted as int16() treats the last byte as being the most significant byte, so the [0x31 0x20] gets interpreted as 0x2031 which is 8241 decimal.
Again, the problem is that the byte stream arrives encoded as text rather than binary.

Sign in to comment.

Products


Release

R2024a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!