Given the calcCRC() C function shown below, what is the equivalent Matlab function?
16-bit CRC-CCITT in C:
/*
* FUNCTION: calcCRC calculates a 2-byte CRC on serial data using
* CRC-CCITT 16-bit standard maintained by the ITU
* ARGUMENTS: queue_ptr is pointer to queue holding are a to be CRCed
* queue_size is offset into buffer where to stop CRC calculation
* RETURNS: 2-byte CRC
*/
unsigned short calcCRC(QUEUE_TYPE *queue_ptr, unsigned int queue_size) {
unsigned int i=0, j=0;
unsigned short crc=0x1D0F; //non-augmented initial value equivalent to augmented initial value 0xFFFF
for (i=0; i<queue_size; i+=1) {
crc ^= peekByte(queue_ptr, i) << 8;
for(j=0;j<8;j+=1) {
if(crc & 0x8000) crc = (crc << 1) ^ 0x1021;
else crc = crc << 1;
}
}
return crc;
}
Below is the Matlab code I have come up with that seems to be equivalent but does not output the same results:
(Incorrect) 16-bit CRC-CCITT in Matlab:
function crc_val = crc_ccitt_matlab (message)
crc = uint16(hex2dec('1D0F'));
for i = 1:length(message)
crc = bitxor(crc,bitshift(message(i),8));
for j = 1:8
if (bitand(crc, hex2dec('8000')) > 0)
crc = bitxor(bitshift(crc, 1), hex2dec('1021'));
else
crc = bitshift(crc, 1);
end
end
end
crc_val = crc;
end
Here is a sample byte array, represented as an integer array:
78 48 32 0 251 0 215 166 201 0 1 255 252 0 1 2 166 255 118 255 19 0 0 0 0 0 0 0 0 0 0 0 0 3 0
The expected output is two bytes base10(44 219) which is base2(00101100 11011011) or base10(11483).
My Matlab function gives base10(85) which is base2(00000000 01010101).
Any ideas on what is causing the output to not be the expected?
You should try bitsll() instead of bitshift(). The former is guaranteed to do what you want, whereas the behavior of the latter depends on properties of crc.
You will also need to and with 0xffff at the end.
Related
Why does logical equality for two vectors of different widths have an output like below?
module eq_test;
logic check;
logic [3:0] cmp_0;
logic cmp_1 = 1'b0;
initial begin
for (int i = 0; i < 16; i++) begin
cmp_0 = i;
check = (cmp_0 == cmp_1);
$display("%b == %b is %b", cmp_0, cmp_1, check);
end
end
endmodule
With Vivado Simulator
0000 == 0 is 1
0001 == 0 is 0
0010 == 0 is 0
0011 == 0 is 0
0100 == 0 is 0
0101 == 0 is 0
0110 == 0 is 0
0111 == 0 is 0
1000 == 0 is 0
1001 == 0 is 0
1010 == 0 is 0
1011 == 0 is 0
1100 == 0 is 0
1101 == 0 is 0
1110 == 0 is 0
1111 == 0 is 0
I can assume that the variable with smaller width cmp_1 is expanded (unsigned expand) to the larger variable width cmp_0, is that so?
Yes, the variable with smaller width is expanded to the larger variable width.
This is described in IEEE Std 1800-2017, section 11.6.1 Rules for expression bit lengths.
The number of bits of an expression (known as the size of the
expression) shall be determined by the operands involved in the
expression and the context in which the expression is given.
In Table 11-21, the == operator has this comment:
Operands are sized to max(L(i),L(j))
where i and j represent expressions of an operand, and L(i) represents the bit length of the operand represented by i.
This is true for all simulators, not just for Vivado.
I have an original image:
I then read it, create a PSF, and blur it in Matlab:
lenawords1=imread('lenawords.bmp');
%create PSF
sigma=6;
PSFgauss=fspecial('gaussian', 8*sigma+1, sigma);
%blur it
lenablur1=imfilter(lenawords1, PSFgauss, 'conv');
lenablurgray1=mat2gray(lenablur1);
PSFgauss1 = PSFgauss/max(PSFgauss(:));
and I saved the blurred image:
imwrite(lenablurgray1, 'lenablur.bmp');
imwrite(PSFgauss1, 'PSFgauss.bmp');
Their values in Matlab and OpenCV match.
Matlab:
disp(lenablurgray1(91:93, 71:75)*256)
142.2222 147.9111 153.6000 159.2889 164.9778
153.6000 164.9778 170.6667 176.3556 176.3556
164.9778 176.3556 182.0444 187.7333 187.7333
disp(PSFgauss1(24:26, 24:26)*256)
248.9867 252.4690 248.9867
252.4690 256.0000 252.4690
248.9867 252.4690 248.9867
OpenCV:
Mat img = imread("lenablur.bmp");
cvtColor(img, img, cv::COLOR_BGR2GRAY);
cv::Mat kernel = imread("PSFgauss.bmp");
cvtColor(kernel, kernel, cv::COLOR_BGR2GRAY);
for (int r = 90; r < 93; r++) {
for (int c = 70; c < 75; c++) {
cout << (int)img.at<uchar>(r, c) << " ";
}
cout << endl;
}
142 147 153 159 164
153 164 ...
164 ...
cout << "PSF" << endl;
for (int r = 23; r < 26; r++) {
for (int c = 23; c < 26; c++) {
cout << (int)kernel.at<uchar>(r, c) << " ";
}
cout << endl;
}
248 251 248
251 255 251
248 251 248
However, the values from filter2D in OpenCV and imfilter in Matlab do not match:
Matlab:
conv1=imfilter(lenablurgray1, PSFgauss1, 'conv');
disp(conv1(91:93, 71:75))
91.8094 96.1109 99.8904 103.1280 105.8210
97.3049 101.7757 105.6828 109.0073 111.7486
102.0122 106.5953 110.5755 113.9353 116.6769
OpenCV:
Mat conv1;
filter2D(img, conv1, img.depth(), kernel, Point(-1, -1), 0,
BORDER_REFLECT);
for (int r = 90; r < 93; r++) {
for (int c = 70; c < 75; c++) {
cout << (int)conv1.at<uchar>(r, c) << " ";
}
cout << endl;
}
255 255 255 255 255
255 255 255 255 255
255 255 255 255 255
Why are the filter2D values wrong?
EDIT2:
cv::Mat kernel = imread("PSFgauss.bmp");
cvtColor(kernel, kernel, cv::COLOR_BGR2GRAY);
kernel.convertTo(kernel, CV_64F);
cv::Scalar kernelsum= cv::sum(kernel);
divide(kernel, kernelsum, kernel);
filter2D(img, conv1, img.depth(), kernel, Point(-1, -1), 0, BORDER_REFLECT);
for (int r = 90; r < 93; r++) {
for (int c = 70; c < 75; c++) {
cout << (int)conv1.at<uchar>(r, c) << " ";
}
gives
103 108 112 116 119
109 ..
115 ..
which matches the Matlab values of conv1 when multiplied by the factor 1.133
disp(conv1(91:93, 71:75) * 1.133)
104.0201 108.8937 113.1758 116.8441 119.8952
110.2464 115.3118 119.7386 123.5053 126.6112
115.5798 120.7725 125.2820 129.0887 132.1950
However, the values differ when I divide img by conv1:
Matlab:
conv2 = lenablurgray1./conv1
disp(conv2(91:93, 71:75))
0.0061 0.0060 0.0060 0.0060 0.0061
0.0062 0.0063 0.0063 0.0063 0.0062
0.0063 0.0065 0.0064 0.0064 0.0063
OpenCV:
Mat conv2;
divide(img, conv1, conv2);
for (int r = 90; r < 93; r++) {
for (int c = 70; c < 75; c++) {
cout << (int)conv2.at<uchar>(r, c) << " ";
}
cout << endl;
}
1 1 1 1 1
1 1 ...
1 ...
why is this?
When you do
lenablur1 = imfilter(lenawords1, PSFgauss, 'conv');
in MATLAB, PSFgauss is normalized. That means that its values sum up to 1:
sum(PSFgauss(:)) == 1.0 % or at least it should be very close
Next, you scale it so its maximum value is 1, so that you can save it as a BMP file. This additionally causes rounding of the values to 256 distinct integers.
Then, in OpenCV, you read in the kernel using imread("PSFgauss.bmp"), and convert back to a grey-value image. This results in a kernel that has integer values in the range [0,255]. In particular, it is not normalized.
What happens then in the convolution is that you multiply each kernel element by an image pixel, and sum up all the values to produce one output value. If the kernel is normalized, this amounts to a weighted averaging. If the kernel is not normalized, the mean image intensity will not be preserved. Since the kernel here has values much larger than it originally had, the output values will be much larger than those of the input image. Because the input image is an 8-bit unsigned integer, and OpenCV uses saturated addition, the operation results in the value 255 for every pixel.
In mathematical notation, in MATLAB you do
g = f * k
(* is convolution, f is the image, k is the kernel). In OpenCV you do
g' = f * Ck
(where C is a constant approximately equal to 255/max(PSFgauss(:), which is the factor by which the kernel was multiplied during the transition from MATLAB to OpenCV).
Thus, dividing by C should bring the kernel back in the state it was when you used it for convolving in MATLAB. But note that the rounding effect you will not be able to remove.
The simplest way of deriving C in OpenCV is to divide kernel by its sum:
kernel.convertTo(kernel, CV_64F);
kernel /= cv::sum(kernel);
I'm trying to figure out the simplest way to write a function to detect the amount of bytes required for a number in Scala.
For instance the number
0 should be 0 bytes
1 should be 1 byte
127 should be 1 byte
128 should be 2 bytes
32767 should be 2 bytes
32768 should be 3 bytes
8388607 should be 3 bytes
8388608 should be 4 bytes
2147483647 should be 4 bytes
2147483648 should be 5 bytes
549755813887 should be 5 bytes
549755813888 should be 6 bytes
9223372036854775807 should be 8 bytes.
-1 should be 1 byte
-127 should be 1 bytes
-128 should be 2 bytes
-32767 should be 2 bytes
-32768 should be 3 bytes
-8388607 should be 3 bytes
-8388608 should be 4 bytes
-2147483647 should be 4 bytes
-2147483648 should be 5 bytes
-549755813887 should be 5 bytes
-549755813888 should be 6 bytes
-9223372036854775807 should be 8 bytes
is there any way to do this besides doing the math figuring out where the number is wrt 2^N?
After all the precisions in the comments, I guess the algorithm for negative numbers would be: whatever the answer for their opposite would be; and Long.MinValue is not an acceptable input value.
Therefore, I suggest:
def bytes(x: Long): Int = {
val posx = x.abs
if (posx == 0L) 0
else (64 - java.lang.Long.numberOfLeadingZeros(posx)) / 8 + 1
}
Tests needed.
As I mentioned, you're basically asking for "what's the smallest power-of-2-number larger than my number", with a bit of adjustment for the extra digit for the sign (positive or negative).
Here's my solution, although the result differs for 0 and -128, because, as Bergi commented on your question, you can't really write 0 with 0 bytes, and -128 fits in 1 byte.
import Math._
def bytes(x: Double): Int = {
val y = if (x >= 0) x + 1 else -x
ceil((log(y)/log(2) + 1)/8).toInt
}
I have the following vector
vec = [ 255 0 255 0 255 0 255 0 255 0 255 0 255 0 255 0]
vec 1x16 double
and using the following command
polyval(vec', 256);
I get
ans = 3.3896e+038
but when I try to get back my original vector
vec2 = decimal2base(ans, 256)
I get
vec2 = 255 0 255 0 255 1 0 0 0 0 0 0 0 0 0 0
and this is clearly not my original vector.
Whats more if again I run polyval in this vector
polyval(vec2', 256);
I get
ans=
3.3896e+038
I am not entirely sure what sort of mistake I am making as I know that my conversion functions are ok, so it must be a number precision thing.
Ah, large numbers. The value 3.3896e+038 is higher than the maximum integer that can be represented by a double without loss of accuracy.
That maximum number is 2^53 or
>> flintmax('double')
ans =
9.0072e+15
So you are losing accuracy and you cannot reverse the computation.
Doing the computations with uint64 values only:
>> pows = uint64(fliplr(0:numel(vec)-1));
>> sum(uint64(vec).*(uint64(256).^pows),'native')
ans =
18446744073709551615
That's about 1.84e+19. Just a little different from what you get if you use doubles. But wait... that number looks familiar:
>> intmax('uint64')
ans =
18446744073709551615
So, you've maxed out unsigned 64-bit integers too:
>> uint64(256).^pows
ans =
Columns 1 through 5
18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615
Columns 6 through 10
18446744073709551615 18446744073709551615 18446744073709551615 72057594037927936 281474976710656
Columns 11 through 15
1099511627776 4294967296 16777216 65536 256
Column 16
When you get above 255^8 or so, you're passing intmax('uint64') and you can't manage numbers this large, at least not with MATLAB's built-in data types.
see if this returns '1':
polyval(vec(6:end),256)==polyval(vec2(6:end),256);
If so, then it's just a property of '255+1' for that special 'vec'.
I have an image with 3 colors in matlab which value 0, 128, and 255. for example:
255 255 255 255 128 255 0 255 255 128 0 255
255 0 255 255 128 255 255 0 255 128 255 255
255 0 255 0 128 255 255 255 255 128 255 0
255 255 0 255 128 255 255 0 255 128 255 255
255 0 0 255 128 0 255 255 0 128 255 0
First, I want to check the pixels of the index (1,1) to (1,5).
If there is pixel value 0 (black), then the pixels of the index (1,1) to (1,5) is changed to 128 (gray), if none, then the pixels are changed to 0 (white).
Second, I want to do these steps again, checking of the index (2,1) to (2,5), (3,1) to (3,5), through to the bottom, then continue to the next, to the index (1,6) to (1,10), (2,6) to (2,10), through to the bottom, then went to the index (1,11) to (1,end), (2,11) to (2,end).
Do you absolutely need to do this sequentially? It sounds like you need to do this for each group of the form (n, (5*m : 5*m +1)). If so, you can do all of the tests simultaneously by reshaping the matrix into a 3d matrix of blocks which are 5 elements wide. Also I am assuming that you meant "if none, then the pixels are changed to 255 (white)", not 0.
Suppose your image is called myImage, then
numBlocks = numel(myImage)/(5*size(myImage,1));
% Generate a 3D matrix each of which is 5 elements long in dimension 2. Note reshape will throw an error if numblocks is fractional
foo = reshape(myImage,size(myImage,1),5,numBlocks);
blackTest = any(foo==0,2);
result = blackTest * 128 + ~blackTest*255; % result for each block
output = reshape(repmat(result,[1 5 1]),size(myImage));
This reorganises your image into a 3d matrix, where each submatrix corresponding to each "layer" of the 3d matrix is 5 elements wide. For the whole 3d matrix it checks whether any of the elements in dimension 2 are zero, leaving a logical matrix foo of length 1 in dimension 2. foo consists of logical ones and zeros, which in MATLAB can also be treated as numerical ones and zeros. So it multiplies foo by 128 (for grey output value) and adds the logical inverse of foo multiplied by 255, to get your white output values. Finally it repeats the matrix back to 5-element-wide blocks and restores it to its original dimensions.
Edit: Note that as mentioned in the code comment, this code won't work if your original image isn't a multiple of 5 pixels wide. To fix this you'd have to create a special case, or use a loop to step through each 5-element-wide block. In fact that might be a better approach all round:
index = 1;
output = zeros(size(myImage));
while index < size(myImage,2)
blockEnd = min(index+4,size(myImage,2));
blackTest = any(myImage(:,index:blockEnd)==0,2);
blackTest = blackTest(:,ones(1,5));
output(1:end,index:blockEnd) = blackTest * 128 + ~blackTest*255;
index = index+5;
end
% generate matrix
rand_data = randi(10,10);
I = zeros(10);
I(rand_data < 6 & rand_data > 3) = 128;
I(rand_data >= 6) = 255;
% here's the code
I = reshape(I',5,[])';
mask = repmat(any(I == 0,2),5,1);
I(mask) = 128;
I(~mask) = 255;
I = reshape(I',10,[])';