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 件のコメント

Walter Roberson
Walter Roberson 2025 年 3 月 27 日
8240 is hex 0x2030 and 8241 is hex 0x2031 .
Hex 0x20 is character "space" (decimal 32)
Hex 0x30 is character '0'
Hex 0x31 is character '1'
Musa
Musa 2025 年 3 月 27 日
Thank you very much Walter. That was very enlightening. I hope someone can now help me explain why the Unpack block is outputting this 'coded' string instead of the value entered in its dialog box. Is there a way to now convert the value '8240' to ' 0'? Is there another conversion factor I can use to go from '8240' to ' 0'? Thanks for your kind help.
Walter Roberson
Walter Roberson 2025 年 3 月 27 日
result = inputvalue - 8240
Musa
Musa 2025 年 3 月 27 日
Fabulous! Thank you very much Walter. I'll have to research the "why", but for now, you're the man! Cheers.

サインインしてコメントする。

 採用された回答

Gordon
Gordon 2025 年 3 月 28 日

0 投票

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 件のコメント

Gordon
Gordon 2025 年 3 月 28 日
A simple Matlab function block with contents:
************
function [device, y] = fcn(u)
u1 = char(u);
y1 = sscanf( u1, "%d");
% y1(1) is the device number
% y1(2:10) is the data for this device as floating ints
% y1(11:end) can be ignored, stale data from a previous time
% step as in your example data.
% You may want to check that sscanf found at least 10 values
% [y1,N] = sscanf( u, "%d" );
device = y1(1);
y = y1(2:10);
**************************8
Feed the function block directly with the message signal from the UDP block. Don't use the unpack block!
Look at the two outputs with display blocks.
Musa
Musa 2025 年 3 月 28 日
Thank you very much Gordon. I appreciate the time you spent on this. Yes, the data is streamed as character data because the Windows UDP SDK specifies that as the only option (I guess - as I am a first-time user of that). Meanwhile, the function you gave above works to some extent in that it runs. The only next thing is that I want to parse out the outputs so there is one output for each sensor - depending on the value of 'device'. I attach here the code (function1.m) that I was using when using the Unpack block and this works with no problems - except for the 8240 - and it was slow as well. Meanwhile, I really like your idea of doing away with the Unpack block; but I am having problems parsing out the two signals in the Matlab function. For some reason Matlab function blocks are somehow hostile to using vectorized assignments. The code I developed that kept failing is attached here as function2.m. Do you have any advise on how to make this to work and more efficiently as well? I appreciate your help a lot. Cheers. Musa.
Walter Roberson
Walter Roberson 2025 年 3 月 28 日
y1 = sscanf( u1, "%d");
I wonder whether that works in the context of Simulink? It returns a potentially variable number of outputs, but y1 has not been declared with a coder.varsize() ?
Musa
Musa 2025 年 3 月 28 日
Right now I'm trying to fix the variable size issue by seeing how I can use a fix-length buffer in the C++ code by padding all unused space at the end with 0 values. That way I will be sending a fixed length buffer to Simulink and later plan to extract only the first set of values that are relevant to the original sensor signals. I'll see if that will help. Thanks. Musa.
Gordon
Gordon 2025 年 3 月 28 日
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 2025 年 3 月 29 日
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.

サインインしてコメントする。

その他の回答 (1 件)

Walter Roberson
Walter Roberson 2025 年 3 月 27 日
編集済み: Walter Roberson 2025 年 3 月 27 日

0 投票

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 件のコメント

Walter Roberson
Walter Roberson 2025 年 3 月 27 日
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.

サインインしてコメントする。

カテゴリ

製品

リリース

R2024a

質問済み:

2025 年 3 月 27 日

コメント済み:

2025 年 3 月 29 日

Community Treasure Hunt

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

Start Hunting!

Translated by