It looks like you're doing this in a very round-about manner. You said,
The matlab function in sumlink is supposed to read the received ASCII characters and add them to a variable until it reaches the end character '>'.
It looks like you are thinking the "signed numbers" are coming in as a string that you'll read one digit at a time, where the entire string is delimited by a start and stop magic number (the '<' and '>' symbols).
A couple of things I would point out:
- First and foremost, typically a signed integer is just sent as a byte or (more typically) a series of bytes. For example, a 16-bit signed integer (short signed integer) is composed of two 8-bit bytes. To convert to the signed 16-bit integer, just use the Matlab function int16. You're doing it the especially long and painful way of sending a string, with delimiters, then reading that string in one digit at a time, converting the characters to numbers, then multiplying the current number by 10 every time you want to concatenate a new digit.
- Probably where you're running into more trouble code-wise is that you're not using the Matlab
persistent
function correctly. From the documentation
If the persistent variable does not exist the first time you issue the persistent statement, it is initialized to the empty matrix.
This is the check you should be making. If the variable you want to be persistent is empty, then initialize it to zero. You are currently declaring it persistent and then immediately setting it to zero every function call!
Your code is:
persistent receivedNumber;
receivedNumber = 0;
when it should be:
persistent receivedNumber;
if isempty(receivedNumber)
receivedNumber = 0;
end
This way, receivedNumber
only gets set to zero IF IT IS EMPTY (meaning it was just created). In all other cases it should be retaining the value it had and thus would be NOT empty. For the record, you need to do the same thing for negative
; they're both being implemented incorrectly.
Now, about your other question,
Can anybody tells if there are any other approaches to read multiple signed digits in simulink?
Yes, there are a couple things you could do. First, you could just concatenate the string and convert to double when you're done. That would look something like the following:
if(status ==1)
switch(data)
case EON
output = str2double(receivedNumber);
case SON
receivedNumber = char;
otherwise
receivedNumber(end+1) = data;
end
end
This code creates output
by converting the running receivedNumber
to a 'double' format when you hit the end of number delimiter. On receiving the start of number delimiter, output is reinitialized to an empty character array. Any other input appends whatever the current character is to the string.
In going through the code looking for your output variable, I noticed that you have Left
and Right
, which output your current receivedNumber
. I'd point out that, generally speaking, receivedNumber
is an intermediate result. I would create a persistent variable called output
instead, assign Left
and Right
to the output, and then only update output
when you have a full number to report.
You could further "bulletproof" the function by checking that the output of the str2double
command is, in fact, a number, and that you didn't pick up a mis-transmitted byte somewhere along the way that would look something like -1Q65
.
Right now you don't have any error checking in your inputs; if you get a mis-transmitted byte that is not a valid digit then you just skip handling it and then treat the next valid digit as correct. This is probably not what you should be doing; if, for example, you should have gotten -1065
and got -1Q65
instead, your code would output:
0;
1;
1;
16;
165;
-165;
The first zero is the output when you get '<', then you output 1 when you receive it, then you output 1 again because you don't handle Q
, then you output 16, then 165, then you apply the negative sign when you hit the end delimiter >
. The way I would suggest doing it instead would be:
persistent output;
persistent receivedNumber;
if isempty(output)
output = 0;
receivedNumber = char;
end
if status == 1
switch(data)
case '<'
receivedNumber = char;
case '>'
tempResult = str2double(receivedNumber);
if ~isnan(tempResult)
output = tempResult;
end
otherwise
receivedNumber(end+1) = data;
end
end
Now your output is all zeros until the number is done being parsed, then it's the output number. The more important thing here is that, when you start receiving the next number, the output continues to be the previous number until the current number is done being parsed. If there is a misformed byte somewhere, the str2double
conversion will output a NaN
(Not A Number), and the ~isnan()
(not isnan; Matlab uses ~
instead of !
) check catches the mis-created number and the result is discarded.
Consider your previous code getting -1065
, -1Q65
, and then -1064
. There's almost no difference there, so I wouldn't expect much response from your PID controller, but the way you're handling your feedback will give you nothing but headaches. You would get:
0;
1;
10;
106;
1065;
-1065;
0;
1;
1;
16;
165;
-165;
0;
1;
10;
106;
1064;
-1064;
There are 18 numbers there, only three of them have the correct sign, and only two of them are actually correct. Granted you were given a faulty input, but what should your system do in that circumstance? Error out, discard the input, or pass the faulty input as truth?
Whatever your decision on how an error should be handled, for control purposes, you should only be releasing complete and valid data.
:EDIT:
I just re-read my answer, and thought I'd reiterate that the persistent function isn't being used correctly. All of my examples of what your output would be are assuming you fix that. Otherwise, you code would output only whatever the current digit is.