Data reading in Fortran - matlab

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.

Related

Subscripted assignment dimension mismatch. error in matlab

for i=1:30
Name(i,1)=sprintf('String_%i',i);
end
I'm just confused what is not working here, this script seems very straightforward, wnat to build a list of strings with numbering from 1 to 30. getting error
Subscripted assignment dimension mismatch.
Matlab do not really have strings, they have char arrays. As in almost any programming language Matlab cannot define a variable without knowing how much memory to allocate. The java solution would look like this:
String str[] = {"I","am","a","string"};
Similar to the c++ solution:
std::string str[] = {"I","am","another","string"};
The c solution looks different, but is generally the same solution as in c++:
const char* str[] = {"I","am","a","c-type","string"};
However, despite the appearances these are all fundamentally the same in the sense to that they all knows how much data to allocate even though they would not be initiated. In particular you can for example write:
String str[3];
// Initialize element with an any length string.
The reason is that the memory stored in each element is stored by its reference in java and by a pointer in c and c++. So depending on operating system, each element is either 4 (32-bit) or 8 (64-bit) bytes.
However, in Matlab matrices data is stored by value. This makes it impossible to store a N char arrays in a 1xN or Nx1 matrix. Each element in the matrix is only allowed to be of the same size as a char and be of type char. This means that if you work with strings you need to use the data structure cell (as also suggested by Benoit_11) which stores a reference to any Matlab object in each element.
k = 1:30;
Name = cell(length(k),1);
for i=k
Name{i,1}=sprintf('String_%i',i);
end
Hope that the explanation makes sense to you. I assumed that according to your attempt you have at least some programming experience from at least one other language than matlab.

Data interpretation between Matlab and Fortran

I have some Fortran code that interprets a binary file. Thanks to another question I asked I understand how the fortran code works but I need help changing it to MATLAB code. Here is the Fortran code:
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
INTEGER*2 I2
if(i2.eq.13881) LFLAG=.FALSE.
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
So basically (and I believe I understand this correctly) the Fortran code is checking the endianess and flipping it if the machine and the data don't match. Additionally, the data is stored in memory in a place reserved for both CH4 and RL4 so by calling RL4 after defining CH4 the data is simply being cast to the REAL*4 type instead of the CHARACTER*4 type. Now I need to figure out how to port this into Matlab. I already have the capability to read in the raw data, but when I try various forms of interpreting it I always get the wrong answer. So far I have tried:
fid=fopen(LMK_file,'r');
BLINE=fread(fid, 72,'char=>char');
CH4=BLINE(7:10);
SCALE=single(CH4(1)+CH4(2)+CH4(3)+CH4(4));
SCALE=int8(CH4(1)+256*int8(CH4(2))+256^2*int8(CH4(3))+256^3*int8(CH4(4));
in MATLAB but both give me the same wrong answer (which makes sense since its doing pretty much the same thing).
Any suggestions?
For anyone else who is looking for the answer to this question this is what I came up with thanks to the help in the comments.
fid=fopen(LMK_file,'r'); %open the file for reading
IGNORE=fread(fid,6,'*char'); %ignore the first 6 bytes. This could also be performed using fseek
SCALE=fread(fid,1,'*float32','b'); %reading in the scale value as a floating point 32 bit number.
where the b indicates the Big endianess of the file. By using the '*float32' option, fread automatically interprets the next 4 characters as a 32 bit floating point number.
This returns the correct value of scale from the given file.

Block Truncation Coding MATLAB

I am trying to implement block truncation coding (BTC) on an image in matlab. In order to do BTW you have to calculate the mean and standard deviation of each 4x4 block of pixels. However, I need to store the mean as a variable number of bits as in the number of bits that the mean will be stored in is passed into the function that calculates the mean. I'm not sure how to do this part, can anyone help?
An easy and clean approach to variable bit lengths-encoding would require the use of the fixed-point toolbox. E.g. as follows
function o = encode1(val, numBits)
o = fi(val, 0, numBits, 0)
If you are rather bound to pure Matlab you could just and them away and 'simulate' the precision loss if you only want to benchmark your encoding.
function o = encode2(val, numBits)
o = bitand(uint8(val), 256 - 2^(8-numBits));
On the other hand, if you're planning to actually encode into a file and not just simulate the encoding, you would need to establish a bit-stream which is not byte-aligned. This can be a bit tiring to do. Trading off efficiency for ease of implementation, you could use dec2bin to work with a string of '0' and '1' characters. Again, toolboxes can be of help here, e.g. the communication systems toolbox provides the de2bi function.

Save 4D matrix to a file with high precision (%1.40f) in Matlab

I need to write 4D matrix (M-(16x,101x,101x,6x) to a file with high precision ('precision'-'%1.40f') in MATLAB.
I've found save('filename.mat', 'M' ); for multidimensional matrix but precision cannot be set (only -double). On the other hand I've found dlmwrite('filename.txt', M, 'delimiter', '\t', 'precision', '%1.40f'); to set the precision but only limited to 2-D array.
Can somebody suggest a way to tackle with my problem?
What is the point in storing 40 digits of fractional part if double precision number in MATLAB keeps only 16 of them?
Try this code:
t=pi
whos
fprintf('%1.40f\n',t)
The output is
Name Size Bytes Class Attributes
t 1x1 8 double
3.1415926535897931000000000000000000000000
The command save('filename.mat', 'M' ); will store numbers in their binary representation (8 bytes per double-precision number). This is unbeatable in terms of space-saving comparing with plain-text representation.
As for the 4D shape the way j_kubik suggested seems simple enough.
I always thought that save will store exactly the same numbers you already have, with the precision that is already used to store them in matlab - you are not losing anything. The only problems might be disk space consumption (too precise numbers?) and closed format of .mat files (cannot be read by outside programs). If I wanted to just store the data and read them with matlab later on, I would definitely go with save.
save can also print ascii data, but it is (as dlmwrite) limited to 2D arrays, so using dlmwrite will be better in your case.
Another solution:
tmpM = [size(M), 0, reshape(M, [], 1)];
dlmwrite('filename.txt', tmpM, 'delimiter', '\t', 'precision', '%1.40f');
reading will be a bit more difficult, but only a bit ;)
Then you can just write your own function to write stuff to a file using fopen & fprintf (just as dlmwrite does) - there you can control every aspect of your file format (including precision).
Something I would have done if I really cared about precision, file-size and execution time (this is probably not the way for you) would be to write a mex function that takes a matrix parameter and stores it in a binary file by just copying raw data buffer from matlab. It would also need some indication of array dimensions, and would probably be the quickest (not sure if save doesn't already do something similar).

Reading 64-bit integer from binary file in Matlab does not give the correct result

Edit: Problem was that even specifying the precision of the inputs matlab still converts them to doubles unless you specify otherwise. My mistake.
Reading a simple 64 bit integer into matlab appears to be giving a different value than if I do the conversion in python or windows calculator.
I have a small file, 8 bytes long whose contents are
0x99, 0x1e, 0x6b, 0x40, 0x27, 0xe3, 0x01, 0x56
I use the following in matlab:
fid = fopen('test.data')
input = fread(fid, 1, 'int64')
I get
input = 6197484319962505200
However, using either python or the windows calculator I get a different decimal representation for 0x5601e327406b1e99. Both predict I should get
input = 6197484319962504857 (which is different by 343). Its obviously not an endianness issue as then it would be WAY off.
I originally was led to test this because reading doubles from a large binary file was giving odd results. I then tried just reading them in as integers and comparing by hand.
My question is, am I doing something wrong, is there something I am overlooking, or is matlab making an error here? I am using win64 matlab R2010a.
The problem seems to be that fread is actually reading it in as a double:
>> class(input)
ans =
double
Because the number is so large, that's presumably the closest double value.
It works for me if I manually specify that the matlab variable should be int64, in addition to specifying the type in the source file (see the documentation for fread):
>> input = fread(fid, 1, '*int64')
input =
6197484319962504857