In [1]:
import pyxtf
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline

Read the test file


In [2]:
# Read the test file
# Note that at this point, the header_7125 and header_7125_snippet is not implemented, which is why a warning is shown
# The bathymetry and sonar headers are implemented, however - which can be read while ignoring the unimplemented packets
test_file = r'/media/data/Reson7125.XTF'
(fh, p) = pyxtf.xtf_read(test_file)

In [3]:
# This prints all the ctypes fields present
print(fh)


FileFormat: 123
SystemType: 1
RecordingProgramName: b'Isis'
RecordingProgramVersion: b'7.1.42'
SonarName: b'Reson7125.exe'
SonarType: 46
NoteString: b'Reson 7125'
ThisFileName: b'C:\\TEMP\\XTF\\TESTTRITON1.XTF'
NavUnits: 3
NumberOfSonarChannels: 2
NumberOfBathymetryChannels: 1
NumberOfSnippetChannels: 1
NumberOfForwardLookArrays: 0
NumberOfEchoStrengthChannels: 0
NumberOfInterferometryChannels: 0
Reserved1: 0
Reserved2: 0
ReferencePointHeight: 0.0
ProjectionType: [204, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
SpheriodType: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
NavigationLatency: 0
OriginY: 0.0
OriginX: 0.0
NavOffsetY: 0.0
NavOffsetX: 0.0
NavOffsetZ: 0.0
NavOffsetYaw: 0.0
MRUOffsetY: 0.0
MRUOffsetX: 0.0
MRUOffsetZ: 0.0
MRUOffsetYaw: 0.0
MRUOffsetPitch: 0.0
MRUOffsetRoll: 0.0
ChanInfo: [<pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5acc598>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5acc620>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5acc6a8>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5acc730>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5acc7b8>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5acc840>]
bathy_info: [<pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5d03598>]
sonar_info: [<pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5d03488>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5d03510>]
subbottom_info: [<pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5d032f0>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5d03268>, <pyxtf.xtf_ctypes.XTFChanInfo object at 0x7fbcb5d03378>]


In [4]:
# The ChanInfo field is an array of XTFChanInfo objects
# Note that the ChanInfo field always has a size of 6, even if the number of channels is less. 
# Use the fh.NumXChannels fields to calculate the number (the function xtf_channel_count does this)
n_channels = fh.channel_count(verbose=True)
actual_chan_info = [fh.ChanInfo[i] for i in range(0, n_channels)]
print('Number of data channels: {}\n'.format(n_channels))

# Print the first channel
print(actual_chan_info[0])


XTF Channels: sonar=2, bathy=1, snippet=1, forward=0, echo=0, interferometry=0
Number of data channels: 4

TypeOfChannel: 1
SubChannelNumber: 0
CorrectionFlags: 1
UniPolar: 0
BytesPerSample: 2
Reserved: 512
ChannelName: b'PORT SB1'
VoltScale: 2.5
Frequency: 400.0
HorizBeamAngle: 15.0
TiltAngle: 0.0
BeamWidth: 90.0
OffsetX: 0.0
OffsetY: 0.0
OffsetZ: 0.0
OffsetYaw: 0.0
OffsetPitch: 0.0
OffsetRoll: 0.0
BeamsPerArray: 0
SampleFormat: 0
ReservedArea2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '...', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Inspect the type of packets returned in the packets dictionary


In [5]:
# Print the keys in the packets-dictionary
print([key for key in p])


[<XTFHeaderType.attitude: 3>, <XTFHeaderType.sonar: 0>, <XTFHeaderType.pos_raw_navigation: 107>, <XTFHeaderType.reson_7125: 61>, <XTFHeaderType.reson_7125_snippet: 62>]

In [6]:
# The returned packets is a Dict[XTFHeaderType, List[XTFClass]]
# The values in the dict are lists of pings, of the class in question
sonar_ch = p[pyxtf.XTFHeaderType.sonar]  # type: List[pyxtf.XTFPingHeader]

# Each element in the list is a ping (XTFPingHeader)
# This retrieves the first ping in the file of the sonar type
sonar_ch_ping1 = sonar_ch[0]

# The properties in the header defines the attributes common for all subchannels 
# (e.g sonar often has port/stbd subchannels)
print(sonar_ch_ping1)


MagicNumber: 64206
HeaderType: 0
SubChannelNumber: 0
NumChansToFollow: 2
Reserved1: [0, 0]
NumBytesThisRecord: 3200
Year: 2006
Month: 11
Day: 1
Hour: 4
Minute: 34
Second: 40
HSeconds: 15
JulianDay: 305
EventNumber: 0
PingNumber: 396034
SoundVelocity: 750.0
OceanTide: 0.0
Reserved2: 0
ConductivityFreq: 0.0
TemperatureFreq: 0.0
PressureFreq: 0.0
PressureTemp: 0.0
Conductivity: 0.0
WaterTemperature: 0.0
Pressure: 0.0
ComputedSoundVelocity: 0.0
MagX: 0.0
MagY: 0.0
MagZ: 0.0
AuxVal1: 6.115478992462158
AuxVal2: 0.0
AuxVal3: 0.0
AuxVal4: 0.0
AuxVal5: 0.0
AuxVal6: 0.0
SpeedLog: 0.0
Turbidity: 0.0
ShipSpeed: 7.364889144897461
ShipGyro: 190.2081298828125
ShipYcoordinate: 0.0
ShipXcoordinate: 0.0
ShipAltitude: 0
ShipDepth: 0
FixTimeHour: 4
FixTimeMinute: 34
FixTimeSecond: 40
FixTimeHsecond: 25
SensorSpeed: 7.364889144897461
KP: 0.0
SensorYcoordinate: 37.49592938422553
SensorXcoordinate: -122.48607010940432
SonarStatus: 0
RangeToFish: 0
BearingToFish: 0
CableOut: 0
Layback: 0.0
CableTension: 0.0
SensorDepth: 0.0
SensorPrimaryAltitude: 0.0
SensorAuxAltitude: 6.115478992462158
SensorPitch: -1.6907002925872803
SensorRoll: -1.9637583494186401
SensorHeading: 287.95361328125
Heave: -0.006982054561376572
Yaw: 190.2081298828125
AttitudeTimeTag: 43816578
DOT: 0.0
NavFixMilliseconds: 43816576
ComputerClockHour: 4
ComputerClockMinute: 34
ComputerClockSecond: 40
ComputerClockHsec: 6
FishPositionDeltaX: 0
FishPositionDeltaY: 0
FishPositionErrorCode: 0
OptionalOffset: 0
CableOutHundredths: 0
ReservedSpace2: [0, 0, 0, 0, 0, 0]
data: [array([  24,   26,   29,   29,   27,   25,   20,   19,   20,   18,   18,
         82,  115,  165,  253,  314,  174,   58,  187,  225,  165,  181,
        178,  174,  186,  189,  196,  242,  297,  285,  148,  105,  137,
         97,  129,   96,   54,   54,  218,  190,  166,  176,  130,  196,
        276,  268,  330,  336,  187,  148,  170,  162,   32,  134,  112,
        148,  247,  208,  297,  187,   65,  123,  161,  115,  431,  364,
        179,  144,  175,  315,  364,  339,  341,  337,  317,  278,  251,
        208,  153,   61,  146,  263,  298,  168,  147,  198,  376,  302,
        381,  416,  248,  226,  206,   99,  317,  396,  354,   80,  136,
        156,  178,  179,  143,   50,   96,   46,  113,   37,   43,  240,
        394,  395,  420,  213,  123,  248,  253,  171,  124,  210,  318,
        327,  163,  212,  333,  418,  400,  244,  182,   37,  123,  136,
        249,  135,  100,  131,  178,  367,  291,  261,  298,  239,  376,
        625,  793,  683,  405,  156,  266,  132,  254,  141,   76,   64,
        236,  253,  238,  309,  238,  130,   73,   91,  150,   89,   58,
         57,  103,   72,   57,   98,   93,   76,  239,  314,  224,  365,
        437,  453,  225,  310,  328,  328,  326,  278,  159,   80,  354,
        543,  318,  207,  283,  358,  256,  159,  112,  172,  200,  257,
        605,  783,  731,  589,  342,  382,  569,  682,  550,  319,  243,
        116,  112,  179,  127,  240,  248,  231,  231,  277,  371,  276,
         94,   89,  214,  225,  240,  273,  390,  340,  220,  326,  351,
        286,  156,  391,  507,  582,  357,  266,  132,   74,  203,  180,
        433,  552,  780,  590,  446,  339,  500,  472,  492,  605,  766,
        418,  213,  468,  400,  305,  216,  208,  291,  593,  683,  588,
        297,  209,  261,  214,  111,  158,  175,  156,   61,  183,  418,
        627,  452,  222,  398,  479,   72,  164,  179,  159,  124,  110,
        190,  336,  312,  236,  132,  142,  154,   78,   64,   87,  123,
        338,  334,  423,  491,  410,  325,  153,  170,  178,  259,  206,
        205,   63,  206,  269,  256,  154,  228,  188,  261,  389,  175,
        233,  246,  223,  406,  567,  435,  558,  731,  729,  637,  426,
        437,  409,  463,  492,  409,  279,  287,  443,  594,  596,  288,
        366,  596,  730,  776,  629,  316,  315,  438,  497,  327,  249,
        298,  164,  306,  462,  512,  581,  380,  341,  337,  311,  242,
        203,  524,  595,  508,  446,  216,  235,  413,  299,  603,  528,
        589,  398,  680,  694,  769,  914,  713,  529,  433,  473,  445,
        552,  622,  578,  917, 1038,  778,  418,  623,  881,  774,  603,
       1126, 1177,  991,  360,  379,  516,  634,  703, 1111, 1157,  896,
        922, 1075, 1056,  671,  292,  111,   64,   44,   51,   24,   30,
         16,   23,   20,   22,   21,   16,   16,   15,   18,   21,   21,
         19,   19,   20,   19,   20,   20,   22,   20,   18,   21,   20,
         20,   20,   21,   22,   20,   19,   19,   19,   18,   19,   21,
         21,   22,   18,   18,   19,   19,   21,   19,   18,   20,   19,
         19,   22,   19,   21,   22,   22,   20,   18,   19,   19,   19,
         20,   20,   18,   22,   19,   18,   20,   21,   21,   21,   19,
         19,   18,   18,   20,   21,   19,   19,   17,   18,   20,   21,
         19,   20,   17,   18,   21,   20,   18,   17,   19,   19,   20,
         22,   18,   19,   18,   19,   19,   16,   17,   18,   18,   19,
         18,   17,   17,   18,   17,   18,   18,   19,   19,   17,   19,
         19,   18,   18,   20,   18,   18,   18,   16,   16,   18,   18,
         16,   16,   17,   19,   17,   17,   18,   18,   17,   16,   19,
         18,   18,   18,   16,   16,   16,   19,   18,   16,   16,   17,
         18,   16,   17,   16,   18,   17,   18,   18,   18,   18,   17,
         19,   17,   16,   17,   15,   19,   16,   16,   15,   15,   17,
         17,   19,   17,   18,   19,   17,   17,   16,   15,   16,   15,
         14,   17,   18,   15,   17,   17,   15,   16,   16,   16,   17,
         14,   15,   14,   15,   16,   15,   13,   16,   14,   14,   15,
         14,   14,   16,   15,   14,   14,   14,   13,   16,   16,   13,
         16,   14,   15,   15,   14,   14,   15,   15,   13,   14,   14,
         15,   15,   14,   14,   15,   13,   14,   14,   13,   15,   14,
         13,   14,   12,   10,   13,   14,   13,   13,   12,   14,   13,
         12,   11,   15,   11,   12,   14,   14,   15,   13,   12,   12,
         11,   11,   13,   11,   12,   11,   12,   13,   11,   12,   14,
         13,   13,   13,   13,   11,   12,   11,   11], dtype=uint16), array([  10,   11,   13,   12,   10,   12,   13,   13,   13,   12,   12,
         12,   13,   12,   13,   13,   12,   12,   11,   12,   12,   11,
         12,   11,   12,   13,   13,   14,   13,   13,   14,   16,   14,
         13,   14,   14,   13,   13,   12,   12,   15,   15,   15,   14,
         12,   11,   15,   13,   15,   14,   12,   15,   15,   13,   15,
         12,   15,   16,   14,   14,   14,   18,   17,   15,   16,   15,
         16,   15,   15,   14,   15,   16,   16,   16,   14,   17,   16,
         16,   15,   14,   16,   16,   16,   15,   16,   15,   14,   17,
         16,   15,   16,   14,   16,   16,   14,   15,   16,   16,   14,
         16,   17,   16,   15,   17,   16,   16,   16,   17,   16,   17,
         17,   16,   16,   18,   18,   16,   17,   19,   17,   18,   17,
         15,   20,   20,   18,   17,   16,   18,   18,   16,   19,   17,
         18,   17,   20,   20,   16,   19,   17,   17,   18,   17,   18,
         19,   19,   18,   19,   18,   18,   18,   16,   21,   19,   18,
         17,   17,   18,   20,   21,   19,   19,   20,   18,   30,   32,
         30,   19,   18,   19,   20,   18,   18,   18,   21,   19,   18,
         17,   19,   21,   16,   16,   20,   17,   18,   18,   18,   20,
         19,   19,   20,   21,   20,   19,   20,   21,   21,   19,   19,
         19,   22,   19,   20,   21,   19,   19,   18,   19,   20,   20,
         22,   19,   18,   20,   21,   19,   19,   22,   20,   19,   21,
         20,   21,   21,   20,   19,   18,   18,   19,   17,   18,   21,
         22,   20,   19,   19,   20,   19,   17,   20,   21,   20,   22,
         22,   20,   21,   20,   21,   21,   20,   19,   18,   20,   21,
         21,   21,   20,   22,   21,   21,   27,   27,   23,   20,   17,
         15,   17,   18,   18,   24,   15,   27,   17,   31,   24,   34,
         51,  109,  160,  742, 1014, 1028,  926, 1358, 1358, 1039,  664,
        633,  918, 1048, 1065,  690,  762,  774,  840,  728,  761,  849,
        914,  985, 1278, 1041,  552,  501,  669,  659,  752,  767,  828,
        534,  516,  575,  354,  459,  709,  796,  643,  543,  379,  320,
        374,  560,  699,  524,  522,  543,  578,  682,  663,  554,  597,
        514,  317,  202,  373,  268,  151,  329,  350,  144,  338,  369,
        374,  225,  187,  248,  257,  462,  397,  334,  495,  411,  386,
        311,  235,  182,  164,  251,  480,  599,  625,  364,  152,  379,
        565,  596,  532,  471,  207,  264,  149,  195,  137,  289,  546,
        692,  885,  776,  610,  461,  180,  349,  352,  184,  381,  494,
        348,  554,  885, 1041, 1070,  829,  671,  382,  257,  384,  407,
        501,  592,  580,  430,  233,  176,  280,  412,  454,  871,  618,
        432,  683,  793,  733,  805,  669,  278,  445,  738,  737,  596,
        271,  131,  424,  458,  354,  497,  660,  809,  693,  505,  456,
        358,  475,  430,  607,  694,  687,  205,  201,  438,  535,  530,
        469,  261,  268,  400,  332,  255,  117,  212,  573,  619,  494,
        357,  406,  433,  464,  501,  476,  204,  311,  441,  385,  287,
        180,  215,  332,  374,  256,   61,  187,  434,  423,  204,  368,
        737,  807,  570,  380,  356,  362,  110,  363,  438,  461,  163,
        119,   59,  151,  119,   84,  107,  218,  194,  303,  403,  496,
        296,  109,  248,  363,  165,   43,   46,  196,  270,  185,  108,
        333,  329,  418,  374,  122,  106,  311,  301,  280,  285,  157,
        261,  133,  116,  315,  410,  189,  170,   40,  186,   39,  206,
        304,  475,  536,  513,  526,  376,  386,  250,  121,  228,  185,
        108,  155,  171,  128,  147,  248,  138,   58,  188,  301,  425,
        449,  199,  117,   28,  138,  141,  201,  186,  268,  233,  249,
        105,  235,  266,  252,  143,  450,  439,  245,  182,  250,  149,
        109,  205,  329,  150,  129,  100,   49,  103,  188,  346,  371,
        264,  208,  121,  101,  145,  292,  515,  460,  292,  133,  264,
        143,  145,  208,  134,   53,  235,  155,  262,  401,  360,  159,
         54,  144,  234,  225,  264,  346,  149,   80,   94,  207,  226,
         82,   43,  142,   79,  128,  124,  122,  283,  292,  228,  258,
        181,  199,   88,   47,  166,   69,  237,  248,  313,  252,  200,
        137,  111,   64,   94,  148,  137,   65,  121,  124,  138,  236,
        257,  246,   85,  156,  162,  174,   91,   59,   99,   94,   59,
         37,   97,  129,  105,   46,   63,   87,   80,   33,   35,   35,
         30,   27,   26,   38,   32,   31,   33,   30,   31,   32,   27,
         29,   24,   23,   29,   34,   35,   23,   24], dtype=uint16)]
ping_chan_headers: [<pyxtf.xtf_ctypes.XTFPingChanHeader object at 0x7fbcb5c4f840>, <pyxtf.xtf_ctypes.XTFPingChanHeader object at 0x7fbcb5c4f8c8>]

Inspect the subchannels in the first sonar package (in this case there are two)


In [7]:
# The data and header for each subchannel is contained in the data and ping_chan_headers respectively.
# The data is a list of numpy arrays (one for each subchannel)
sonar_subchan0 = sonar_ch_ping1.data[0]  # type: np.ndarray
sonar_subchan1 = sonar_ch_ping1.data[1]  # type: np.ndarray

print(sonar_subchan0.shape)
print(sonar_subchan1.shape)


(690,)
(690,)

Plot a signal-view of both subchannels of the first ping


In [8]:
fig, (ax1, ax2) = plt.subplots(2,1, figsize=(12,8))
ax1.semilogy(np.arange(0, sonar_subchan0.shape[0]), sonar_subchan0)
ax2.semilogy(np.arange(0, sonar_subchan1.shape[0]), sonar_subchan1)


Out[8]:
[<matplotlib.lines.Line2D at 0x7fbcb5cb0940>]

In [9]:
# Each subchannel has a XTFPingChanHeader, 
# which contains information that can change from ping to ping in each of the subchannels
sonar_ping1_ch_header0 = sonar_ch_ping1.ping_chan_headers[0]
print(sonar_ping1_ch_header0)


ChannelNumber: 0
DownsampleMethod: 2
SlandRange: 15.007499694824219
GroundRange: 0.0
TimeDelay: 0.0
TimeDuration: 0.020010000094771385
SecondsPerPing: 0.0
ProcessingFlags: 0
Frequency: 396
InitialGainCode: 0
GainCode: 0
BandWidth: 0
ContactNumber: 0
ContactClassification: 0
ContactSubNumber: 0
ContactType: 0
NumSamples: 690
MillivoltScale: 0
ContactTimeOffTrack: 0.0
ContactCloseNumber: 0
Reserved2: 0
FixedVSOP: 0.0
Weight: 0
ReservedSpace: [0, 0, 0, 0]

Concatenate the sonar data to produce a dense array/image


In [10]:
# The function concatenate_channels concatenates all the individual pings for a channel, and returns it as a dense numpy array
np_chan1 = pyxtf.concatenate_channel(p[pyxtf.XTFHeaderType.sonar], file_header=fh, channel=0, weighted=True)
np_chan2 = pyxtf.concatenate_channel(p[pyxtf.XTFHeaderType.sonar], file_header=fh, channel=1, weighted=True)


# Clip to range (max cannot be used due to outliers)
# More robust methods are possible (through histograms / statistical outlier removal)
upper_limit = 2 ** 14
np_chan1.clip(0, upper_limit-1, out=np_chan1)
np_chan2.clip(0, upper_limit-1, out=np_chan2)

# The sonar data is logarithmic (dB), add small value to avoid log10(0)
np_chan1 = np.log10(np_chan1 + 0.0001)
np_chan2 = np.log10(np_chan2 + 0.0001)

# Transpose so that the largest axis is horizontal
np_chan1 = np_chan1 if np_chan1.shape[0] < np_chan1.shape[1] else np_chan1.T
np_chan2 = np_chan2 if np_chan2.shape[0] < np_chan2.shape[1] else np_chan2.T

# The following plots the waterfall-view in separate subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12))
ax1.imshow(np_chan1, cmap='gray', vmin=0, vmax=np.log10(upper_limit))
ax2.imshow(np_chan2, cmap='gray', vmin=0, vmax=np.log10(upper_limit))


Out[10]:
<matplotlib.image.AxesImage at 0x7fbcb4875470>

In [ ]: