Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

# -*- coding: utf-8 -*- 

#------------------------------------------------------------------- 

#  Filename: unpack.py 

#  Purpose: Routines for unpacking SEG Y data formats. 

#   Author: Lion Krischer 

#    Email: krischer@geophysik.uni-muenchen.de 

# 

# Copyright (C) 2010 Lion Krischer 

#--------------------------------------------------------------------- 

""" 

Functions that will all take a file pointer and the sample count and return a 

NumPy array with the unpacked values. 

""" 

 

import numpy as np 

import sys 

 

LOG2 = 0.3010299956639812 

# Get the system byteorder. 

BYTEORDER = sys.byteorder 

if BYTEORDER == 'little': 

    BYTEORDER = '<' 

else: 

    BYTEORDER = '>' 

 

 

class WrongDtypeException(Exception): 

    pass 

 

 

def pack_4byte_IBM(file, data, endian='>'): 

    """ 

    Packs 4 byte IBM floating points. This will only work if the host system 

    internally uses little endian byteorders. 

    """ 

    # Check the dtype and raise exception otherwise! 

    if data.dtype != 'float64' and data.dtype != 'float32': 

        raise WrongDtypeException 

    # Calculate the values. The theory is explained in 

    # http://www.codeproject.com/KB/applications/libnumber.aspx 

 

    # Calculate the signs. 

    signs = np.empty(len(data), dtype='uint8') 

    temp_signs = np.sign(data) 

    # Negative numbers are encoded as sign bit 1, positive ones as bit 0. 

    signs[temp_signs == 1] = 0 

    signs[temp_signs == -1] = 128 

 

    # Make absolute values. 

    data = np.abs(data) 

 

    # Store the zeros and add an offset for numerical stability, 

    # they will be set to zero later on again 

    zeros = np.where(data == 0.0) 

    data[zeros] += 1e-32 

 

    # Calculate the exponent for the IBM data format. 

    exponent = ((np.log10(data) / LOG2) * 0.25 + 65).astype('uint32') 

 

    # Now calculate the fraction using single precision. 

    fraction = np.require(data, 'float32') / \ 

                   (16.0 ** (np.require(exponent, 'float32') - 64)) 

 

    # Normalization. 

    while True: 

        # Find numbers smaller than 1/16 but not zero. 

        non_normalized = np.where(np.where(fraction, fraction, 1) < 0.0625)[0] 

        if len(non_normalized) == 0: 

            break 

        fraction[non_normalized] *= 16 

        exponent[non_normalized] -= 1 

 

    # If the fraction is one, change it to 1/16 and increase the exponent by 

    # one. 

    ones = np.where(fraction == 1.0) 

    fraction[ones] = 0.0625 

    exponent[ones] += 1 

 

    # Times 2^24 to be able to get a long. 

    fraction *= 16777216.0 

    # Convert to unsigned long. 

    fraction = np.require(fraction, 'uint64') 

 

    # Use 8 bit integers to be able to store every byte separately. 

    new_data = np.zeros(4 * len(data), 'uint8') 

 

    # The first bit is the sign and the following 7 are the exponent. 

    byte_0 = np.require(signs + exponent, 'uint8') 

    # All following 24 bit are the fraction. 

    byte_1 = np.require(np.right_shift(np.bitwise_and(fraction, 0x00ff0000), 

                                       16), 'uint8') 

    byte_2 = np.require(np.right_shift(np.bitwise_and(fraction, 0x0000ff00), 

                                       8), 'uint8') 

    byte_3 = np.require(np.bitwise_and(fraction, 0x000000ff), 'uint8') 

 

    # Depending on the endianness store the data different. 

    # big endian. 

    if endian == '>': 

        new_data[0::4] = byte_0 

        new_data[1::4] = byte_1 

        new_data[2::4] = byte_2 

        new_data[3::4] = byte_3 

    # little endian> 

    elif endian == '<': 

        new_data[0::4] = byte_3 

        new_data[1::4] = byte_2 

        new_data[2::4] = byte_1 

        new_data[3::4] = byte_0 

    # Should not happen. 

    else: 

        raise Exception 

    # Write the zeros again. 

    new_data.dtype = 'uint32' 

    new_data[zeros] = 0 

    # Write to file. 

    file.write(new_data.tostring()) 

 

 

def pack_4byte_Integer(file, data, endian='>'): 

    """ 

    Packs 4 byte integers. 

    """ 

    # Check the dtype and raise exception otherwise! 

    if data.dtype != 'int32': 

        raise WrongDtypeException 

    # Swap the byteorder if necessary. 

    if BYTEORDER != endian: 

        data = data.byteswap() 

    # Write the file. 

    file.write(data.tostring()) 

 

 

def pack_2byte_Integer(file, data, endian='>'): 

    """ 

    Packs 2 byte integers. 

    """ 

    # Check the dtype and raise exception otherwise! 

    if data.dtype != 'int16': 

        raise WrongDtypeException 

    # Swap the byteorder if necessary. 

    if BYTEORDER != endian: 

        data = data.byteswap() 

    # Write the file. 

    file.write(data.tostring()) 

 

 

def pack_4byte_Fixed_point(file, data, endian='>'): 

    raise NotImplementedError 

 

 

def pack_4byte_IEEE(file, data, endian='>'): 

    """ 

    Packs 4 byte IEEE floating points. 

    """ 

    # Check the dtype and raise exception otherwise! 

    if data.dtype != 'float32': 

        raise WrongDtypeException 

    # Swap the byteorder if necessary. 

    if BYTEORDER != endian: 

        data = data.byteswap() 

    # Write the file. 

    file.write(data.tostring()) 

 

 

def pack_1byte_Integer(file, data, endian='>'): 

    raise NotImplementedError