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.
Related
I am a newbie in Maple. Could you please help me to convert the following short code from Matlab to Maple:
I=0.0;
for i1=1:3
I(i1,i1,i1,i1)=1.0;
end
I've tried to write it like:
unprotect(I);
I:=0.0;
for i1 from 1 to 3 do
for i2 from 1 to 3 do
for i3 from 1 to 3 do
for i4 from 1 to 3 do
if i1=i2 and i2=i3 and i3=i4 then I[i1,i2,i3,i4]:=1.0;
else I[i1,i2,i3,i4]:=0.0;
end if;
od;
od;
od;
od;
But it gives the following error:
Error, illegal use of an object as a name
Error, illegal use of an object as a name
Can anybody tell me what's wrong?
Thank you,
It'd be easier if you didn't insist on using the name I, which in Maple has the special meaning of the sqrt of -1.
restart;
interface(imaginaryunit=j):
local I:=Array((1..3)$4,datatype=float[8]);
for i1 from 1 to 3 do
I[i1,i1,i1,i1]:=1.0;
end do:
The above produces I as a 4-dimensional Array, where each dimension has a width of three elements. And the three "long diagonal" elements are all initialized to 1.0. And the Array can contain hardware double precision floats. And all the other elements are 0.0 by default.
Is that what you were trying to do?
If you don't insist on calling assigning it to the special name I then things are easier. Eg,
restart;
II:=Array((1..3)$4,datatype=float[8]):
for i1 from 1 to 3 do
II[i1,i1,i1,i1]:=1.0;
end do:
You cannot properly override/disable the special meaning of I merely by unprotecting it. (And even if you could, unprotecting and redefining I is an unworkable idea since a significant portion of Maple commands would then no longer compute properly in the given session.)
Recent versions of Maple allows you to create a so-called top-level "local" instance of that name, which can be used separately from the usual global name I. If you insist on that route, and if your Maple version is recent enough to support that, then you'd probably also want to change the
interface setting for the imaginary unit (sqrt of -1) so that things don't get too confusing. That's why I showed it in the first example above.
But I really think that you'd find things easiest if you just used another name, like II or what have you.
You don't need to put the datatype=float[8] restriction on the Array. But if your subsequent code mimics some (originally) Matlab code then maybe floats are all that will be assigned into the Array. And some operations on Arrays can be much faster, with it. See how it goes.
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.
This is a part from a Fortran 90 code.
where (abs(A-B)>e)
no_converge=1
elsewhere
no_converge=0
end where
A and B are arrays of some particular dimensions, and e is a scalar. I have to say that I am not that familiar with either programming languages.
I have used the f2matlab but it does very poor job on this Fortran statement.
I am wondering whether the equivalent for a Matlab is something like this:
if abs(A-B)>e
no_converge=1 ;
else
no_converge=0 ;
end
Is this correct ?
The no_converge is a scalar (integer in Fortran declarations), used at different sections in order to begin some other loops.
I will really appreciate any suggestions here, and please let me know whether more information is needed.
Not correct, no. In the Fortran no_converge ought to be an array of the same size (and shape) as A and B; its elements will be set to 1 where abs(A-B)>e and 0 elsewhere. So in your Matlab code no_converge shouldn't be a scalar but an array. However, without sight of your declarations I'm just making educated guesses. Show us some (more) code.
I don't have Matlab on this computer so can't check, but if memory serves me well you can do something very similar, like this
no_converge(abs(A-B)>e) = 1
no_converge(abs(A-B)<=e) = 0
provided that no_converge is, as in the Fortran case, an array of the same size and shape as A and B.
The WHERE statement in Fortran sort of combines a loop with a conditional, but only for assignments.
no_convergence in the Fortran code must be a vector with (at least) the same extend as A and B. So, the code you provided is certainly incorrect.
I don't know whether you can do something similar in Matlab, but you can always do a explicit loop and test for convergence element-wise.
There WHERE construct in Fortran can be replaced by a MERGE one-liner which f2matlab may be better able to translate:
no_converge = merge(1,0,abs(A-B)>e)
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.
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.