从十六进制转储中将Fortran实数数据类型读入Matlab

时间:2016-11-17 02:31:46

标签: matlab fortran binaryfiles file-conversion hexdump

正如标题所说,我正在将大量真实数组从Fortran写入未格式化的文件,然后尝试将该二进制文件读入Matlab。我已成功使我的脚本适用于字符串和整数,但它没有正确读取十六进制转储中的实数。

作为测试用例,我使用的是数字5.49。有趣的是,根据一个40 af ae 14的在线转换器,当我检查我的hexfile时,我的代码部分正在读取14 ae af 40。我试过以float32double的形式阅读它,我已经从中性变为小端到大端。有什么想法吗?

以下是我的代码的一个简单示例:

首先是Fortran编写语句

REAL :: floating = 5.49
open(unit = 2, file = "anxietySource", form = "unformatted", status = "new", action = "readwrite")
write(unit = 2 ) floating 

现在是Matlab阅读声明

fid = fopen('anxietySource', 'rb');
h1 = fread(fid, 1, 'int32'); %this is just reading off the starter bits that tell me how long my write statement is
floating = fread(fid,1,'float32');
display(floating);
fclose(fid);

我的猜测是Fortran REAL类型有一些时髦。也许它不是一个浮点?

1 个答案:

答案 0 :(得分:0)

在达到这一点的位工作上做得很好,你几乎就在那里。 “Big Endien与小......”

https://gcc.gnu.org/onlinedocs/gfortran/CONVERT-specifier.html

http://www.lahey.com/docs/lfenthelp/F95ARINQUIREStmt.htm

https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/270026

还有人工移动https://www.nsc.liu.se/~boein/f77to90/a5.html#section10

MODULE Shifty
PRIVATE

INTERFACE Shift
  MODULE PROCEDURE Shift4 !,Shift8
END INTERFACE

CONTAINS
REAL FUNCTION Shift4(MyFloat)
IMPLICIT NONE
REAL, INTENT(IN) :: MyFloat
INTEGER*4        :: Float1
INTEGER*4        :: Float2
INTEGER*4        :: Float3
INTEGER*4        :: Float4

INTEGER*4        :: MyInt
EQUIVALENCE(MyInt, MyFloat)
INTEGER*4        :: MyIntOut
EQUIVALENCE(MyIntOut, Shift4)

WRITE(*,20) MyInt
20 FORMAT('Incoming Real=',1PE12.5,' ==",Z8.8,'"')

Float1 = IBITS(MyInt, 0, 8)
Float2 = IBITS(MyInt, 8, 8)
Float3 = IBITS(MyInt,16, 8)
Float4 = IBITS(MyInt,24, 8)

WRITE(*,30) 1, Float1      !Check
WRITE(*,30) 2, Float2
WRITE(*,30) 3, Float3
WRITE(*,30) 4, Float4
30 FORMAT('Float',I1,'="',Z2.2,'"')

Float1 = ISHFT(Float1,  24)
Float2 = ISHFT(Float2,  16)
Float3 = ISHFT(Float3,   8)
Float4 = ISHFT(Float4,   0)

MyIntOut = IOR(Float1  , Float2)
MyIntOut = IOR(MyIntOut, Float3)
MyIntOut = IOR(MyIntOut, Float4)

WRITE(*,20) MyInt, MyIntOut
20 FORMAT('Incoming Real="',Z8.8,' Outgoing="',Z8.8,'"')

RETURN
END FUNCTION Shift4

END MODULE Shifty

PROGRAM MAT2F90
USE Shifty
IMPLICIT NONE

TYPE MATLAB_HEADER
  CHARACTER(LEN=120) :: Descriptor  !should be 116 and INT*8 !!
  INTEGER*4          :: Offset
  INTEGER*2          :: Version
  CHARACTER(LEN=2)   :: Endien
END TYPE MATLAB_HEADER

TYPE MATLAB_SUBHEADER
  INTEGER*4          :: Type
  INTEGER*4          :: Bytes
END TYPE MATLAB_SUB_HEADER

TYPE(MATLAB_HEADER)                   :: Head
TYPE(MATLAB_SUB_HEADER),DIMENSION(20) :: Tag
CHARACTER(LEN=12), DIMENSION(18) :: Matlab_Version =  RESHAPE(&
['miINT8      ','miUINT8     ','miINT16     ','miUINT16    ', &
 'miINT32     ','miUINT32    ','miSINGLE    ','Reserved    ', &
 'miDOUBLE    ','Reserved    ','Reserved    ','miINT64     ', &
 'miUINT64    ','miMATRIX    ','miCOMPRESSED','miUTF8      ', &
 'miUTF16     ','miUTF32     '],[18])
LOGICAL :: Swap
...
OPEN(UNIT=22,FILE='<somename>',ACCESS='STREAM',FORM='UNFORMATTED',IOSTAT=Status)
IF(Status =/0 ) ...Do something

READ(20,IOSTAT=Status) Head
IF(Status =/0 ) ...Do something

WRITE(*,*)'Head.Descriptor="',Head.Descriptor,'"'
WRITE(*,*)'Head.Offset    = ',Head.Offset
WRITE(*,*)'Head.Version   = ',Head.Version
WRITE(*,*)'Head.Endien    ="',Head.Endian,'"'
IF(Head.Endian == 'IM') THEN
  SWAP = .FALSE.
ELSEIF(Head.Endian == 'MI') THEN
  SWAP = .TRUE.
ELSE
  WRITE(*,*)'Unknown  Endien="',Head.Endian,'"'
  STOP
ENDIF

READ(20,IOSTAT=Status) Tag(1)
IF(Status =/0 ) ...Do something
WRITE(*,*)'Tag(1).Type = ',Tag(1).Type,' == "',Matlab_Version(Tag(1).Type),'"'
WRITE(*,*)'Tag(1).Bytes= ',Tag(1).Bytes
!read and swap if need be...
!There is padding to an 8type boundary
!Read the next tag and data... etc

第1-5至1-9节https://data.cresis.ku.edu/data/mat_reader/matfile_format.pdf。你可能会注意到我做的那种类型15是'miCOMPRESSED',所以在这一点上需要解压缩器才能理解它。

你需要像以前一样测试它,因为我很容易让订单错误,而且我是通过内存来做的。(更新为我今天这样做,但在一个子程序中,所以它应该作为一个函数工作??)

如果你需要一个'8'版本,我把它设为4 ...然后你只需要调用Shifty()就可以获得与你的数据匹配的那个。