Initial Analysis of Onyx nano DAS Data from Jan 2025 Deployment

P. McGill
19Feb25

Data Import

This short data segment was downloaded in-situ right after the deployment of the DAS instrument on 28Jan25. Find out what information is available about the data file.

datFilePath="/Users/mcgill/Documents/My\ Projects/Geo-Sense/Deployment\ Jan\ 2025/jan28test.hdf5"

Import[datFilePath,"Elements"]

Import[datFilePath,"Summary"]

Import[datFilePath,"Attributes"]

Import[datFilePath,#]&/@{"StructureGraph","StructureGraphLegend"}

Import[datFilePath,"DataFormat"]

Import[datFilePath,"Datasets"]

Look at the sample counts and time stamps .

dasDatSampCnt=Import[datFilePath,{"Data","/Acquisition/Raw[0]/RawDataSampleCount"}]

These “sample counts” are the sample identifier tags assigned by the Sintela instrument.

Length@dasDatSampCnt

dasDatTime=Import[datFilePath,{"Data","/Acquisition/Raw[0]/RawDataTime"}]

The times appear to be Unix time to the nearest microsecond.

FromUnixTime[First@dasDatTime/10^6]

Length@dasDatTime

Import the data samples.

dasDat=Import[datFilePath,{"Data","/Acquisition/Raw[0]/RawData"}];

Dimensions@dasDat

How many minutes of time does this represent at 1000 Hz sampling?

Dimensions[dasDat][[1]]/(60 1000)//N

Verify that this is 162 channels with a 6.33 m gauge length.

162 6.33

Geolocation

Before we examine the data, figure out where the ROV was relative to the DAS cable for this dataset.

Import the cable survey data provided by ROV pilot Ethan Brandt.

cabSrvy=Drop[#,{3}]&/@Import["/Users/mcgill/Documents/My\ Projects/Geo-Sense/Deployment\ Jan\ 2025/Cable\ Survey\ Jan\ 2025/GeoSense\ Survey\ Initial.rln","CSV"];

First@cabSrvy

Length@cabSrvy

Convert the cable survey points from UTM to lat and lon.

cabPts=GeoPosition[GeoGridPosition[#,"UTMZone10"]]&/@cabSrvy;

Import the ship and ROV navigation log downloaded from smb://atlas.shore.mbari.org/ShipData/logger/2025/rcsn.

navLog=Drop[Import["/Users/mcgill/Documents/My\ Projects/Geo-Sense/Deployment\ Jan\ 2025/2025028shipnavlogr.dat","CSV"],28];

First@navLog

Length@navLog

Name the columns that contain the ROV navigation data.

rovTime=15;
rovLat=16;
rovLon=17;

Extract the times of the first and last data points in the DAS data file.

startTime=First@dasDatTime/10^6;

FromUnixTime@startTime

endTime=Last@dasDatTime/10^6;

FromUnixTime@endTime

Extract the ROV positions from the navigation log, selecting only those time that overlap with the DAS data.

rovLog=GeoPosition/@Take[Select[navLog,startTime<=#[[rovTime]]<=endTime&],All,{rovLat,rovLon}];

Find the ROV’s distance travelled and heading during this time.

{UnitConvert[GeoDistance[First@rovLog,Last@rovLog],"Meters"],GeoDirection[First@rovLog,Last@rovLog]}

Plot the ROV’s track with the surveyed cable positions.

cabPlot=GeoListPlot[cabPts,Frame->True,Joined->True,GeoGridLines->Automatic,GeoProjection->"Equirectangular",GeoLabels->True,PlotRangePadding->0.001,ImageSize->Full];

Show[cabPlot,Graphics[{Orange,PointSize->Large,Point[rovLog]}]]

Find the distance between the start of the ROV track and the western (bitter) end of the cable.

UnitConvert[GeoDistance[Last@cabPts,First@rovLog],"Meters"]

Time Series

Plot a sample of the DAS data for channel 80.

ListPlot[dasDat[[1;;1000,80]],Joined->True,Frame->True,FrameLabel->{"Time (ms)","Phase (radians)"},ImageSize->Full]

Plot all the data for channel 80.

ListPlot[dasDat[[All,80]],Frame->True,FrameLabel->{"Time (ms)","Phase (radians)"},ImageSize->Full]

Spectrograms

Plot a spectrogram for all of the channel 80 data.

Spectrogram[dasDat[[All,80]] 100,SampleRate->1000,FrameLabel->{"Time (s)","Frequency (Hz)"},ImageSize->Full]

Note that the Sintela antialiasing filter reduces the signal amplitude before the Nyquist frequency of 500 Hz.

Make a data browser that displays the spectrogram for a channel with adjustable gain.

Manipulate[Spectrogram[dasDat[[All,chan]] gain,SampleRate->1000,FrameLabel->{"Time (s)","Frequency (Hz)"},ImageSize->Full],{chan,1,162,1},{gain,1,100}]

Periodograms

Plot a periodogram for all of the channel 80 data.

Periodogram[dasDat[[All,80]],1024,512,SampleRate->1000,Frame->True,FrameLabel->{"Frequency (Hz)","Power (dB)"},ImageSize->Full,PlotRange->All]

Make a data browser that displays the periodogram for any channel.

Manipulate[Periodogram[dasDat[[All,chan]],1024,512,SampleRate->1000,PlotRange->{All,{-70,40}},Frame->True,FrameLabel->{"Frequency (Hz)","Power (dB)"},ImageSize->Full],{chan,1,162,1}]

Audio

Play the data for channel 32 as a sound.

ListPlay[dasDat[[All,32]]-Mean[dasDat[[All,32]]],SampleRate->1000]

Not much can be heard because the automatic gain adjustment of the audio player causes the high DC offset to reduce the amplitude of smaller AC signals.

Apply a high-pass filter to remove the DC offset.

ListPlay[HighpassFilter[dasDat[[All,32]], 0.2 Pi,21],SampleRate->1000]

Make a data browser that plays any channel as a sound with adjustable highpass-cutoff frequency.

Manipulate[ListPlay[HighpassFilter[dasDat[[All,chan]], cutoff Pi,51],SampleRate->1000],{chan,1,162,1},{cutoff,0,0.99}]

Covariances

There are many sources of stimulus that cause the recorded phase for each DAS channel to change. Some of these sources originate within the DAS system and some are from the environment. Some of these sources cause the signal at one DAS channel to be correlated with other DAS channels and some do not.

TextGrid[{{"","Uncorrelated","Correlated"},{"System","Amplifier\rnoise","Periodic\rclock jitter"},{"Environment","Fish bites,\rLocal currents","Earthquakes,\rWhale calls"}},Frame->All]

Plot the first 1000 samples (1 second) of channels 5 and 6 to get a sense of how correlated they are.

ListPlot[{dasDat[[1;;1000,5]],dasDat[[1;;1000,6]]},Joined->True,Frame->True,FrameLabel->{"Time (ms)","Phase (radians)"},ImageSize->Full]

Plot all of the data for channels 5 and 6, but plot every 1000th sample (i.e. every 1 second) to reduce the number of points that have to be plotted.

ListPlot[{Take[dasDat[[All,5]],{1,-1,1000}],Take[dasDat[[All,6]],{1,-1,1000}]},Frame->True,Joined->True,FrameLabel->{"Time (s)","Strain"},PlotRange->All,ImageSize->Full]

Plot the covariance between every two adjacent channels (i.e. separated by one gauge length) over the length of the cable, for the first 1000 samples (1 second) of data.

min1Cov=Covariance[dasDat[[1;;1000,#]],dasDat[[1;;1000,#+1]]]&/@Range[161];

ListPlot[min1Cov,PlotRange->Full,Joined->True,Frame->True,FrameLabel->{"DAS Channel Pair","Covariance"},ImageSize->Full]

Make the same plot for the first second of the first through fifth minutes of data.

min2Cov=Covariance[dasDat[[60001;;61000,#]],dasDat[[60001;;61000,#+1]]]&/@Range[161];

min3Cov=Covariance[dasDat[[120001;;121000,#]],dasDat[[120001;;121000,#+1]]]&/@Range[161];

min4Cov=Covariance[dasDat[[180001;;181000,#]],dasDat[[180001;;181000,#+1]]]&/@Range[161];

min5Cov=Covariance[dasDat[[240001;;241000,#]],dasDat[[240001;;241000,#+1]]]&/@Range[161];

GraphicsColumn[
ListPlot[#,PlotRange->{Full,{0,0.55}},Joined->True,Frame->True,AspectRatio->1/6]&/@{min1Cov,min2Cov,min3Cov,min4Cov,min5Cov},ImageSize->Full]

There doesn’t seem to be a general trend in the covariance of adjacent channel pairs (e.g. slow fading or increase as the ROV moves along the cable).

Plot the covariance between channels that are 81 gauge lengths apart.

ListPlot[Covariance[dasDat[[1;;1000,#]],dasDat[[1;;1000,#+81]]]&/@Range[81],PlotRange->Full,Joined->True,Frame->True,FrameLabel->{"DAS Channel Pair","Covariance"},ImageSize->Full]

When plotted on the same vertical scale as the previous graphs, we can see that there’s very little covariance at this channel separation.

ListPlot[Covariance[dasDat[[1;;1000,#]],dasDat[[1;;1000,#+81]]]&/@Range[81],PlotRange->{Full,{0,0.55}},Joined->True,Frame->True,FrameLabel->{"DAS Channel Pair","Covariance"},ImageSize->Full]

Phasograms

Find the smallest and largest values in the dataset.

MinMax[dasDat]

Plot the first 100 ms of data for all channels as a waterfall display of phase vs. channel vs. time.

ArrayPlot[dasDat[[1;;100,All]],PlotRange->{-25,25},FrameTicks->Automatic,FrameLabel->{"Time (ms)","DAS Channel"},ImageSize->Full]

There are too many data points to plot this way. We have to find a way to condense the data for display.

For each channel, partition the time-series data into 1000 sample segments (1 second). For each segment, subtract all values from the mean of that segment and then find the RMS value. Plot these RMS values vs. channel vs. time.

ArrayPlot[BlockMap[RootMeanSquare[#-Mean[#]]&,#,1000]&/@Transpose[dasDat],Frame->True,FrameLabel->{"DAS Channel","Time (s)"},FrameTicks->Automatic,ImageSize->Full]

Transpose the data to look more like the waterfall display in the Sintela DAS software.

ArrayPlot[Transpose[BlockMap[RootMeanSquare[#-Mean[#]]&,#,1000]&/@Transpose[dasDat]],Frame->True,FrameLabel->{"Time (s)","DAS Channel"},FrameTicks->Automatic,ImageSize->Full]