Expression in Debugger shows correct value of calculation, but value is rounded when assigning to variable - type-conversion

I read 16 Bit two's complement sensor data byte after byte via I2C with a STM32, so I have to stick the High- and Low-Byte back together and convert this number to a float to get the real value.
My expression in C for this is
// Convert temperature value (256 LSBs/°C with +25°C Offset)
float temp = (tmpData[1] << 8 | tmpData[0])/256.0 + 25.0;
When I use the debugger of the STM32CubeIDE to check the calculation, the expression shows the correct conversion of the data (see screenshot). But the value assigned to the temp variable is always 25! It seems to me like the first term of the expression is always assumed to be 0 or something? I already tried a direct cast of the term in brackets to float, but that does not change anything.
Can anybody point me to the problem? Why is the debugger showing the correct value, but the code is assigning a wrong one?
The expressions in the screenshots below are captured by howering the mouse over the corresponding part of the above code line in debug mode.
Fig. 1: Complete expression of calculation (gives result as expected)
Fig. 2: tmpData content (original two Bytes)
Fig. 3: Result of byte shifting and sticking
Fig. 4: temp result (always 25, even when expression above showes the expected value)
temp is only a volatile for the moment, because I don't use that value yet and the compiler optimizes it out.

many issues in this single line of code.
tmpData[1] << 8 has to be (((uint16_t)tmpData[1]) << 8). If you shift byte 8 times the result will be zero (standard says undefined). You probably got the warning about it.
256.0 & 25.0 are double values and the result will also be double then converted to the float. You shuold use 256.0f and 25.0f.
you can see the difference here: https://godbolt.org/z/Cm-S8T

OK, new morning, new intuition...
The problem wasn't with this code line from the question, but (typ. Murphy) with the stuff I did not post. The I2C is read via DMA to the array and at the point I wanted to do the conversion the peripheral was not done yet. That's why the array elements were always empty when the code accessed them, but at the time I checked the values in the debugger the I2C peripheral had finished the transmission and I saw the expected values.
So the solution is to check if the peripheral is still busy...

Related

uint64 is not exact for vectors in Matlab

I have discovered an inconsistency for uint64 when using vectors in Matlab. It seems as an array of uint64 is not exact for all 64 bits. This did not give the output I expected,
p=uint64([0;0]);
p(1)=13286492335502040542
p =
13286492335502041088
0
However
q = uint64(13286492335502040542)
q =
13286492335502040542
does. It is also working with
p(1)=uint64(13286492335502040542)
p =
13286492335502040542
0
Working with unsigned integers one expect a special behaviour and usually also perfect precision. This seems weird and even a bit uncanny. I do not see this problem with smaller numbers. Maybe anyone knows more? I do not expect this to be an unknown problem, so I guess there must be some explanation to it. I would be good to know why this happen and when, to be able to avoid it. As usual this kind of issues is mentioned nowhere in the documentation.
Matlab 2014a, windows 7.
EDIT
It is worth mentioning that I can see the same behaviour when defining arrays directly.
p=uint64([13286492335502040542;13286492335502040543])
p =
13286492335502041088
13286492335502041088
This is the root to why I ask this question. I have hard to see workaround for this case.
While it might be surprising, this is a floating point precision issue. :-)
The thing is, all numeric literals are by default of type double in MATLAB; that's why:
13286492335502040542 == 13286492335502041088
will return true; the floating point representation in double precision of 13286492335502040542 is 13286492335502041088. Since p has the class uint64, all assignments done to it will cast the right-hand-side to its class.
On another hand, the uint64(13286492335502040542) "call" will be optimized by the MATLAB interpreter to avoid the overhead of calling the uint64 function for the double argument, and will convert the literal directly to its unsigned integer representation (which is exact).
On a third hand [sic], the function call optimization doesn't apply to
p = uint64([13286492335502040542;13286492335502040543])
because the argument of uint64 is not a literal, but the result of an expression, i.e. the result of the vertcat operator applied to two double operands. In this case the MATLAB interpreter is not smart enough to figure out that the two function calls should "commute" (concatenation of uint should be the same as uint of concatenation), so it evaluates the concatenation (which gives an array of equal double because FP precision), then converts the two similar double values to uint64.
TLDR: the difference between
p = uint64(13286492335502040542);
and
u = 13286492335502040542; p = uint64(u);
is a side effect of function call optimization.
Matlab, unless told otherwise reads numbers as double, then casts to the relevant datatype. The Matlab double datatype allows for 51 bits for the floating point fraction, giving the possibility to store 52 bit integers without loss of prepossession (mantissa). Notice that 13286492335502041088 is just 13286492335502040543 with the last 12 bits set to zero.
the solution as you said, is to convert the literals directly uint64(13286492335502040543).
p=uint64([13286492335502040542;13286492335502040543]) does not work because it creates a double array and then converts it to uint64
This issue is mentioned in the uint64 documentation, under 'More About', although it doesn't mention that laterals are read as doubles unless otherwise specified.
I agree this seems weird and I don't have an explanation. I do have a workaround:
p=[uint64(13286492335502040542);uint64(13286492335502040543)]
i.e., cast the separate values to uint64s.

Matlab not taking last number in array?

I've got a Subscripted assignment dimension mismatch problem.
I've already localized the issue, and know exactly what is going on, I just don't know why.
Here's the problematic piece of code:
mFrames(:,i) = vSignal(round(start:1:frameLength*samplingRate));
start=start+frameShift*samplingRate;
frameLength = frameLength+frameShift;
I've already checked what's going on in debugmode; usually my resulting column length of mFrames is 128, this stays the same until i=1004. Then, my column length changes to 127.
I've checked the values involved while in debug mode, and it simply does not make sense what is going on. At i==1004 start=32097 and frameLength*samplingRate=32224.
That's a difference of 127 meaning 128 points, that should work.
BUT when i assign a vector A=round(start:1:frameLength*samplingRate)
OR B=start:1:frameLength*samplingRate
In both cases I get a vector going from 32097 to 32223. This ALTHOUGH when I give in frameLength*samplingRate matlab is giving me 32224.
In other words, matlab is telling me it's using one number, but when I test I find it's using a different one.
Any help appreciated.
I suspect your 32224 is not actually 32224. MATLAB's default format only displays so many decimal places, so when dealing with floating point numbers, what is printed on screen is not necessarily the "exact" value.
Let's go back a step and look at how the synatx x = start:step:end works.
1:1:10 should give us numbers in steps of 1 from 1 to 10. Fair enough, that makes sense. What if we set the end value to something that's slightly above 10?
e.g.:
1:1:10.1
Well, it still gives us 1:1:10, (or 1:10, 1 being the default step) because we can't have values higher than the end-point, so 11 isn't a correct step.
So what about this:
1:1:9.99
Spoiler: it's the same as 1:9
And this?
1:1:9.9999999
Yep, still 1:9
But if we do this:
a = 9.9999999;
Then with default format, the value of a will be shown on the command line and in your list of workspace variables as 10.0000.
Now, if frameLength and samplingRate are both stored as floating point numbers, it's possible that the number you see as 32224 is not 32224 but very slightly below that. You can check this by changing your default format - e.g. format long at the command line - to show more decimal places.
The simplest solution is probably to do something like:
B=start:1:round(frameLength*samplingRate)
Or try to store the relevant values as integers (e.g., uint32).

Make Matlab issue a warning when converting a double to a uint8 and vice versa?

Typically in Matlab colours are represented by three element vectors of RGB intensity values, with precision uint8 (range 0 - 255) or double (range 0 - 1). Matlabs functions such as imshow work with either representation making both easy to use in a program.
It is equally easy however to introduce a bug when assigning colour values from a matrix of one type, to that of another (because the value is converted silently, but not re-scaled to the new range). Having just spent a number of hours finding such a bug, I would like to make sure it is never introduced again.
How do I make Matlab display a warning when type conversion takes place?
Ideally it would only be when the conversion is between double and uint8. It should also be difficult to deactivate (i.e. the option is not reset when loading a workspace, or when matlab crashes).
A possible solution is to define your own uint8 function that casts to uint8 and issues a warning if some value has been truncated.
You should place this function in a folder where it shadows the builtin uint8 funciton. For example, your user folder is a good choice, as it usually appears the first in path.
Or, as noted by Sam Roberts, if you want this function to be called only when converting from double into uint8 (not when converting from any other type into uint8), put it in a folder named #double within your path.
function y = uint8(x)
y = builtin('uint8', x);
if any(x(:)>255) || any(x(:)<0)
warning('MATLAB:castTruncation', 'Values truncated during conversion to uint8')
end
The warning is on by default. You can switch it on or off with the commands warning('on','MATLAB:castTruncation') and warning('off','MATLAB:castTruncation') (thanks to CitizenInsane for the suggestion).

Data reading in Fortran

EDIT: I am Making this just a question about the Fortran and will start a new question about converting to MATLAB.
ORIGINAL:
I am working on a project and am trying to port some old Fortran code into Matlab. I have almost no Fortran experience so I am not quite sure what is going on in the following code. The Fortran code is simply for interpreting data from a binary file and I have made some decent progress at porting stuff into MATLAB but have got stuck at the following part:
IMPLICIT NONE
DOUBLE PRECISION SCALE
CHARACTER*72 BLINE
CHARACTER*72 DATA_FILE_FULL_NAME
CHARACTER*6 DATA_FILE_NAME
CHARACTER*4 CH4, CH4F
REAL*4 RL4
EQUIVALENCE (RL4,CH4)
CHARACTER*2 C2
LOGICAL LFLAG
c2='69'
LFLAG=.TRUE.
DATA_FILE_FULL_NAME='./'//DATA_FILE_NAME//'.DAT'
OPEN(UNIT=20, FILE=DATA_FILE_FULL_NAME, ACCESS='DIRECT',
. RECL=72, status='OLD')
READ(20,REC=1) BLINE
CH4f=BLINE(7:10)
call flip(4,lflag,ch4f,ch4)
SCALE=RL4
RETURN
END
c ..................................................
subroutine flip(n,lflag,ch1,ch2)
c ..................................................
integer*4 n, i
character*(*) ch1, ch2
logical lflag
if(lflag) then
do i=1,n
ch2(i:i)=ch1(n-i+1:n-i+1)
enddo
else
ch2=ch1
endif
return
end
What I am stuck with is getting the correct value for SCALE because I am not exactly sure what is happening with the RL4. Can someone explain to me why RL4 changes value and what process changes it so that I can put this process into MATLAB?
The code probably does change of Endianness - the byte swap. The equivalence means that the equivalenced variables share the memory and you can treat the 4 bytes read from the file as a number after the byte swap.
The four bytes are therefore interpreted as a four byte real RL4 and converted to a double precision value scale after that.
The byte swap is done only when the logical lflag is true. That will probably be when the byte order of the file is not the same as the machine native byte order.
In Matlab you can probably use http://www.mathworks.com/help/matlab/ref/swapbytes.html .
Just read the 4 byte floating point number and swap the bytes if necessary.

error in lip detection algorithm of my matlab code

I am getting error in my Matlab code. I am using R2009b version
Frame index must be a numeric value greater than zero and less
than or equal to the number of frames in the file.
Error in ==> mmreader.read at 74
videoFrames = read(getImpl(obj), index);
Error in ==> testing at 10
Ii=read(mov,k*10);
Just a hunch, but I'm guessing that your frame index is not:
a numeric value greater than zero and less than or equal to the number
of frames in the file.
MATLAB is telling you that the error is happening in mmreader.read, and it is happening when you call mmreader.read at this point in your file testing:
Ii=read(mov,k*10);
If your movie reader object mov contains less than k*10 frames, or if k is zero or a negative number, you are asking MATLAB to do something impossible.
These sort of errors can be easily tracked down by typing dbstop if error at the command line, which means that when there is an error you enter debug mode. At this point you can then check what the value of k is, and also the number of available frames in mov.