├── Processing and analysis of vessel mounted and lowered ADCP data.md
├── README.md
├── animation_small.gif
├── code_to_analyse_and_plot_adcp_data_for_paper1.m
├── f6.png
├── gaussian_eddy_test.m
├── ladcp_map_sections_3d_2014_with_vmadcp.png
├── objective_mapping_all_adcp_data_julaugsep.png
├── objmap_function_files.zip
├── si_arctic_df_rbfs_utm_and_coastal6.m
├── sta032_ladcp.PNG
├── variogram_results.png
└── vmdas.PNG
/Processing and analysis of vessel mounted and lowered ADCP data.md:
--------------------------------------------------------------------------------
1 | # Processing and analysis of vessel mounted and lowered ADCP datasets
2 |
3 | This document will guide you through the steps necessary to process and analyse both vessel mounted (VM-ADCP) and lowered acoustic doppler current profilers (L-ADCP). Both are complex data sources that contain a lot of noise and potential biases, but dont despair, with todays programms and code packages anyone can work with this data and produce meaningfull results.
4 |
5 | We used the following data sources:
6 |
7 | from the field:
8 | - VM-ADCP: RDI Workhorse 75 kHz and 150 kHz (http://www.teledynemarine.com/workhorse-mariner-adcp?BrandID=16)
9 | - L-ADCP: RDI Workhorse Sentinel 300kHz (http://www.teledynemarine.com/workhorse-sentinel-adcp?BrandID=16)
10 | - Sea Bird 911plus CTD profiles (http://www.seabird.com/sbe911plus-ctd)
11 |
12 | from the web:
13 | - International Bathymetric Chart of the Arctic Ocean IBCAO (https://www.ngdc.noaa.gov/mgg/bathymetry/arctic/arctic.html)
14 | - Global coastline dataset (https://www.ngdc.noaa.gov/mgg/shorelines/data/gshhs/)
15 |
16 | We used the following software:
17 |
18 | Data collection:
19 | - VMDAS ADCP data collection software (http://www.teledynemarine.com/rdi/support#)
20 | - BB Talk terminal software (should also work with other terminal programmes, http://www.teledynemarine.com/rdi/support#)
21 | - Sea Bird CDT data collection suite (Seaterm, Seasave, SBE Data processing, http://www.seabird.com/sbe911plus-ctd)
22 |
23 | Post processing:
24 | - Oracle VM VirtualBox 5.0 running a UNIX machine with the CODAS ADCP processing suite (https://currents.soest.hawaii.edu/docs/adcp_doc/codas_doc/)
25 |
26 | Analysis:
27 | - Matlab 2016a, incl. the mapping and statistics toolbox and the following additional packages
28 | - m_map (https://www.eoas.ubc.ca/~rich/map.html)
29 | - seawater liberary (http://www.cmar.csiro.au/datacentre/ext_docs/seawater.htm)
30 | - objective mapping (http://mooring.ucsd.edu/software/matlab/doc/toolbox/datafun/objmap.html)
31 | - L-ADCP processing suite LDEO (http://www.ldeo.columbia.edu/~ant/LADCP)
32 |
33 | Here is a visualization of VM-ADCP and L-ADCP current profiles:
34 |
35 | 
36 |
37 | # Fieldwork
38 |
39 | This section explains how ADCP data was gathered during each expedition.
40 |
41 | ## VM-ADCP
42 |
43 | The VM-ADCP is usualy mounted in the ships hull or a retractable keel, and connected to an onboard PC. To record data one of two proramms is usually used: The Windows programm VMDAS (Vesse mounted data aquisition system) from RDI instruments or the open source suite UHDAS from the University of Hawaii.
44 |
45 | Make sure that the PC is running with the exact UTC time. If you can, synchronize the PC clock with a GPS device, the NMEA navigation data stream or the internet. Having the correct timestamps in the ADCP data is important for the post-processing (combining the L-ADCP, VM-ADCP and CTD data).
46 |
47 |
48 |
49 | Here we used VMDAS to collect VM-ADCP data. After starting up the PC and ensuring the PC is properly connected to the ADCP and the ships navigation channels, one can open the VMDAS and select the button: File--> Collect Data. This will open some empty diagrams. The next step is to edit the data options under: Options --> Edit data options. In the first section "Communications" the ADCP and NMEA (navigation) data channels need to be set to the right ports, but the ships technician likely did this already. In the next section "ADCP setup" you need to select the bin number and size. This depends on the frequency of the ADCP. We used 100 bins with a binsize of 8 m and 8 ms paceing between the bins. The ADCP also requires a specific set up file, which states details of the ADCPs mounting and ping-ing patters. This is usually avialable from the ships technician or stored on the data collection PC. Here is an example from RV Helmer Hanssen:
50 |
51 | ```
52 | -----------------------------------------------------------------------------\
53 | ; ADCP Command File for use with VmDas software.
54 | ;
55 | ; ADCP type: 75 Khz Ocean Surveyor
56 | ; Setup name: default
57 | ; Setup type: Low resolution, long range profile(narrowband)
58 | ;
59 | ; NOTE: Any line beginning with a semicolon in the first
60 | ; column is treated as a comment and is ignored by
61 | ; the VmDas software.
62 | ;
63 | ; NOTE: This file is best viewed with a fixed-point font (e.g. courier).
64 | ; Modified Last: 12August2003
65 | ;----------------------------------------------------------------------------/
66 |
67 | ; Restore factory default settings in the ADCP
68 | cr1
69 |
70 | ; set the data collection baud rate to 38400 bps,
71 | ; no parity, one stop bit, 8 data bits
72 | ; NOTE: VmDas sends baud rate change command after all other commands in
73 | ; this file, so that it is not made permanent by a CK command.
74 | cb611
75 |
76 | ;
77 | ;
78 | ; CX Trigger input, default is CX0,0 no trigging
79 | ;
80 | ; CX1,0 waits for a positive trigging signal
81 | CX1,0
82 | ;
83 | ;
84 |
85 | ; Set for narrowband single-ping profile mode (NP), hundred (NN) 8 meter bins (NS),
86 | ; 8 meter blanking distance (NF)
87 | WP0
88 | NN100
89 | NP00001
90 | NS0800
91 | NF0800
92 |
93 | ; Disable single-ping bottom track (BP),
94 | ; Set maximum bottom search depth to 1000 meters (BX)
95 | BP000
96 | BX10000
97 |
98 | ; output velocity, correlation, echo intensity, percent good
99 | ND111110000
100 |
101 | ; One second between bottom and water pings
102 | TP000000
103 |
104 | ; Zero seconds between ensembles
105 | ; Since VmDas uses manual pinging, TE is ignored by the ADCP.
106 | ; You must set the time between ensemble in the VmDas Communication options
107 | TE00000000
108 |
109 | ; Not set to calculate speed-of-sound, no depth sensor, external synchro heading
110 | ; sensor, no pitch or roll being used, no salinity sensor, use internal transducer
111 | ; temperature sensor
112 | EZ0000001
113 | ;
114 | ; Sets the speed of sound to 1500m/s
115 | ;
116 | EC1500
117 | ; Output beam data (rotations are done in software)
118 | EX00000
119 |
120 | ; Set transducer misalignment (hundredths of degrees)
121 | EA04530
122 |
123 | ; Set transducer depth (decimeters)
124 | ED0042
125 |
126 | ; Set Salinity (ppt)
127 | ES35
128 |
129 | ; save this setup to non-volatile memory in the ADCP
130 | CK
131 | ```
132 | The next section "Recording" includes setting the naming and storage options for the data. The section "NAV" lets you select the correct NMEA channels to co-record with the ADCP data. Storing the correct NMEA data is important for the post-processing, since we want to remove biases that stem from the ships movement. The other sections are less important and you can now press the OK button and start recording ADCP data by pressing the play button in the upper left corner.
133 |
134 | During the expedition make sure that the ADCP does not interfere with other acoustic sensors, and adjust the pining intervals if necessary.
135 |
136 | At the end of the expedition, open the data collection folder and copy the entire folder onto you post processing PC. We need especially the ENR, N1R and N2R files.
137 |
138 | ## L-ADCP
139 |
140 | The lowered ADCP should be firmly installed onto the CTD frame. Insert a battery with sufficient voltage (>30V) in the ADCP and connect the ADCP to a Windows PC via a serial port.
141 |
142 | Make sure that the PC is running with the exact UTC time. If you can, synchronize the PC clock with a GPS device, the NMEA navigation data stream or the internet. Having the correct timestamps in the ADCP data is important for the post-processing (combining the L-ADCP, VM-ADCP and CTD data).
143 |
144 | Following are instructions for launch and recovery.
145 |
146 | Launch:
147 |
148 | - Open the BB talk program, select the port the ADCP is connected to and open a terminal window
149 | - wake up the ADCP by pressing on the keyboard
150 | - Erase old data on the instrument: type `RE ErAsE` and confirm by pressing (Do this if you are sure the data was saved before!)
151 | - From menu: Transfer --> PC time to ADCP
152 | - Start the ADCP by transferring the following ADCP settings file onto the ADCP: Press . Choose `ladcp_setting.txt` and wait until script ends
153 | - Disconnect cables and launch CTD
154 |
155 | create `ladcp_setting.txt` by saving the following code:
156 | ```
157 | $P *************************************************************************
158 | $P ******* LADCP Deployment with one ADCP. Looking down **********
159 | $P *************************************************************************
160 | ; Send ADCP a BREAK
161 | $B
162 | ; Wait for command prompt (sent after each command)
163 | $W62
164 | ; Display real time clock setting
165 | tt?
166 | $W62
167 | ; Set to factory defaults
168 | CR1
169 | $W62
170 | ; use WM15 for firmware 16.3
171 | ; activates LADCP mode (BT from WT pings)
172 | WM15
173 | ; Flow control (Record data internally):
174 | ; - automatic ensemble cycling (next ens when ready)
175 | ; - automatic ping cycling (ping when ready)
176 | ; - binary data output
177 | ; - disable serial output
178 | ; - enable data recorder
179 | CF11101
180 | $W62
181 | ; coordinate transformation:
182 | ; - radial beam coordinates (2 bits)
183 | ; - use pitch/roll (not used for beam coords?)
184 | ; - no 3-beam solutions
185 | ; - no bin mapping
186 | EX00100
187 | $W62
188 | ; Sensor source:
189 | ; - manual speed of sound (EC)''
190 | ; - manual depth of transducer (ED = 0 [dm])
191 | ; - measured heading (EH)
192 | ; - measured pitch (EP)
193 | ; - measured roll (ER)
194 | ; - manual salinity (ES = 35 [psu])
195 | ; - measured temperature (ET)
196 | EZ0011101
197 | $W62
198 | ; Set transducer depth to zero
199 | ED0000
200 | $W62
201 | ; Set salinity to 35ppt
202 | ES35
203 | $W62
204 | ;
205 | ; - configure no. of bins, length, blank
206 | ; number of bins
207 | WN015
208 | $W62
209 | ; bin length [cm]
210 | WS0800
211 | $W62
212 | ; blank after transmit [cm]
213 | WF0000
214 | $W62
215 | ; ambiguity velocity [cm]
216 | WV250
217 | $W62
218 | ; amplitude and correlation thresholds for bottom detection
219 | LZ30,220
220 | $W62
221 | ; Set ADCP to narrow bandwidth and extend range by 10%
222 | LW1
223 | $W62
224 | ; Name data file
225 | RN MLADCP
226 | $W62
227 | ;
228 | ; Set one ensemble/sec
229 | TE00000100
230 | $W62
231 | ; Set one second between pings
232 | TP000100
233 | $W62
234 | ; Set LADCP to output Velocity, Correlations, Amplitude, and Percent Good
235 | LD111100000
236 | $W62
237 | ; Set one ping per ensemble. Use WP if LADCP option is not enabled.
238 | LP1
239 | $W62
240 | $W62
241 | ; keep params as user defaults (across power failures)
242 | CK
243 | $W62
244 | ; echo configuration
245 | T?
246 | $W62
247 | W?
248 | $W62
249 | ; start Pinging
250 | CS
251 | ; Delay 3 seconds
252 | $D3
253 | $p *************************************************************************
254 | $P Please disconnect the ADCP from the computer.
255 | $P *************************************************************************
256 | ; Close the log file
257 | $L
258 | ```
259 |
260 | Recovery:
261 | - Connect cables
262 | - On BBTALK click the terminal window
263 | - press to wake up the ADCP
264 | - In the menu: File --> Recover Recorder --> Select All Files --> OK
265 | - Download selected file following the GUI instructions
266 | - rename the file including the station number, ex: `sta0032_MLADC000.000`
267 | - Put the ADCP to sleep: Type `CZ` and pres
268 |
269 | # Post-Processing
270 |
271 | ## VM-ADCP
272 |
273 | Post-processing of this data is necessary to remove biases from the ships movements and misalignment (Angle offset) as well as erroneous backscatter from the seafloor, nets and CTDs, ringing and bubble clouds. We used the CODAS software environment for this purpose.
274 |
275 | In the first step, we installed the virtual computer with the CODAS processing software (https://currents.soest.hawaii.edu/docs/adcp_doc/codas_setup/virtual_computer/index.html). Then we copied the folder containing all VM-ADCP files into the shared folder (named after the cruise ID, we used `codas_shared/siarctic2017/enr` here).
276 |
277 | Then start the virtual computer, open a terminal inside the folder and enter the following commands. Follow the CODAS GUI instructions when they pop up.
278 |
279 | ```
280 | mkdir /media/sf_codas_shared/siarctic2017/enr/config
281 | mkdir /media/sf_codas_shared/siarctic2017/enr/uhdas_data
282 |
283 | cd /media/sf_codas_shared/siarctic2017/enr/config/
284 | reform_vmdas.py
285 | python vmdas2uhdas.py
286 |
287 | proc_starter.py reform_defs.py
288 |
289 | cd /media/sf_codas_shared/siarctic2017/enr
290 | adcptree.py os75 --datatype uhdas --cruisename siarctic2017
291 | cd os75
292 | ```
293 | Now create a file called `_py.cnt` inside the folder `/media/sf_codas_shared/siarctic2017/enr/os75`
294 | and copy those lines into the file. Change the values where necessary.
295 |
296 | ```
297 | ## python processing
298 |
299 | --yearbase 2017 ## required, for decimal day conversion
300 | ## (year of first data)
301 | --cruisename siarctic2017 ## *must* match prefix in config dir
302 | --dbname zzz ## database name; in adcpdb. eg. a0918
303 | ##
304 | --datatype uhdas ## datafile type
305 | --sonar os75nb ## specify instrument letters, frequency,
306 | ## (and ping type for ocean surveyors)
307 | --ens_len 300 ## averages of 300sec duration
308 | ##
309 | --update_gbin ## required for this kind of processing
310 | --configtype python ## file used in config/ dirctory is python
311 | ##
312 |
313 | --max_search_depth 1500 ## try to identify the bottom and eliminate
314 | ## data below the bottom IF topo says
315 | ## the bottom is shallower than 1000m
316 | ```
317 |
318 | Then run the routine:
319 | ```
320 | quick_adcp.py --cntfile q_py.cnt --auto
321 | ```
322 | Now check the misalignment amplitude and angle(phase) from the file `cal/watertrk/adcpcal.out` by running:
323 | ```
324 | tail -20 cal/watertrk/adcpcal.out
325 | ```
326 | To correct for the misalignment, process the data again with the `--rotate_amplitude` and `--rotate_angle 1.80` that you obtained from the previous command.
327 | ```
328 | quick_adcp.py --steps2rerun rotate:apply_edit:navsteps:calib --rotate_amplitude 1.0303 --rotate_angle 1.80 --auto
329 | ```
330 | Now you are ready to check and eventually edit the ADCP data manually using a great tool called `autoedit`.
331 | ```
332 | cd edit
333 | gautoedit.py
334 | ```
335 | In this GUI, you can remove bad data that the algorithms could not filter out themselves. Check the entire dataset and press apply for each edit. Once you are done press quit and apply your edits by running this in the terminal:
336 | ```
337 | cd ..
338 | quick_adcp.py --steps2rerun apply_edit:navsteps:calib --auto
339 | ```
340 | Now you are finally ready to export your data into a netCDF file (found here `contour/os75/`) by running:
341 | ```
342 | adcp_nc.py adcpdb contour/os75 siarctic2017 os75
343 | ```
344 |
345 | ## L-ADCP
346 |
347 | The L-ADCP data was processed using the Matlab based library inversion software LDEO (Version 4.2, Visbeck, 2002, http://www.ldeo.columbia.edu/~ant/LADCP). To process L-ADCP data, one needs the processed CTD and VM-ADCP data. The CTD data need to be in the `.cnv` format and contain each measurements latitude, longitude and time in seconds. The CTD cnv files are usually created using the seabird software "SBEDataProcessing" and should look like this:
348 |
349 | ```
350 | * Sea-Bird SBE 9 Data File:
351 | * FileName = C:\Seabird\SeasaveV7\STA0095.hex
352 | * Software Version Seasave V 7.26.6.26
353 | * Temperature SN = 4497
354 | * Conductivity SN = 2666
355 | * Number of Bytes Per Scan = 34
356 | * Number of Voltage Words = 5
357 | * Number of Scans Averaged by the Deck Unit = 1
358 | * System UpLoad Time = Aug 23 2017 13:53:55
359 | * NMEA Latitude = 79 39.47 N
360 | * NMEA Longitude = 006 47.77 E
361 | * NMEA UTC (Time) = Aug 23 2017 13:53:54
362 | * Store Lat/Lon Data = Append to Every Scan
363 | * SBE 11plus V 5.0
364 |
365 | # A LOT OF METADATA
366 |
367 | ** Ship: F/F "Helmer Hanssen"
368 | ** Station: 0095
369 | ** Echodepth: 983
370 | ** Log: 8362.060
371 | ** Wind-Dir/Force: 205 17
372 | ** Air-Temp (dry): 3.5
373 | ** Weather Sky: 8 8
374 | ** Sea Ice: 2 0
375 | * System UTC = Aug 23 2017 13:53:55
376 | # nquan = 16
377 | # nvalues = 56918
378 | # units = specified
379 | # name 0 = timeS: Time, Elapsed [seconds]
380 | # name 1 = latitude: Latitude [deg]
381 | # name 2 = longitude: Longitude [deg]
382 | # name 3 = depSM: Depth [salt water, m]
383 | # name 4 = potemp090C: Potential Temperature [ITS-90, deg C]
384 | # name 5 = sal00: Salinity, Practical [PSU]
385 | # name 6 = sigma-é00: Density [sigma-theta, kg/m^3]
386 | # name 7 = svCM: Sound Velocity [Chen-Millero, m/s]
387 | # name 8 = prDM: Pressure, Digiquartz [db]
388 | # name 9 = sbeox0Mg/L: Oxygen, SBE 43 [mg/l]
389 | # name 10 = flSP: Fluorescence, Seapoint
390 | # name 11 = seaTurbMtr: Turbidity, Seapoint [FTU]
391 | # name 12 = n2satMg/L: Nitrogen Saturation [mg/l]
392 | # name 13 = sbeox0PS: Oxygen, SBE 43 [% saturation]
393 | # name 14 = sigma-é00: Density [sigma-theta, kg/m^3]
394 | # name 15 = flag: 0.000e+00
395 |
396 | # A LOT OF METADATA
397 |
398 | # file_type = ascii
399 | *END*
400 | 0.000 79.65782 6.79616 3.527 3.0108 32.7933 26.1229 1459.65 3.565 10.6711 2.1978e-01 0.183 16.80369 99.108 26.1229 0.000e+00
401 | 0.042 79.65782 6.79616 3.527 3.0109 32.7935 26.1230 1459.65 3.565 10.6710 2.1978e-01 0.183 16.80363 99.108 26.1230 0.000e+00
402 | 0.083 79.65782 6.79616 3.527 3.0109 32.7933 26.1228 1459.65 3.565 10.6711 1.8315e-01 0.183 16.80365 99.108 26.1228 0.000e+00
403 | 0.125 79.65782 6.79616 3.515 3.0110 32.7933 26.1228 1459.65 3.552 10.6793 2.1978e-01 0.153 16.80359 99.185 26.1228 0.000e+00
404 | 0.167 79.65782 6.79616 3.527 3.0110 32.7934 26.1229 1459.65 3.565 10.6721 2.1978e-01 0.153 16.80357 99.119 26.1229 0.000e+00
405 | 0.208 79.65782 6.79616 3.527 3.0112 32.7937 26.1231 1459.65 3.565 10.6720 2.1978e-01 0.153 16.80347 99.118 26.1231 0.000e+00
406 | 0.250 79.65782 6.79616 3.579 3.0114 32.7935 26.1229 1459.65 3.617 10.6720 2.1978e-01 0.183 16.80344 99.118 26.1229 0.000e+00
407 | 0.292 79.65782 6.79616 3.527 3.0114 32.7934 26.1229 1459.65 3.565 10.6802 2.1978e-01 0.244 16.80345 99.195 26.1229 0.000e+00
408 |
409 | # A LOT MORE DATA
410 | ```
411 |
412 | To start the processing, generate a working directory and store the CTD cnv files in and extra folder `workingfolder/CTD`. Now also create the folders `workingfolder/checkpoints`, `workingfolder/proc`, `workingfolder/processed` and `workingfolder/raw`. Store the L-ADCP data (files such as `sta0032_MLADC000.000`) in `workingfolder/raw`.
413 |
414 | To constrain the current profile solution we use the VM-ADCP in the upper layers and bottom echoes for the lower layers. Therefore load the VM-ADCP data netcdf file and save them in a format readable for the LDEA software, into the "proc" folder:
415 |
416 | ```Matlab
417 | addpath(genpath('C:\Users\a5278\Documents\MATLAB\matlab_functions'))
418 |
419 | filename='C:\Users\a5278\Documents\codas_shared\siarctic2017\enr\os75\contour\os75.nc';
420 |
421 | info=ncinfo(filename)
422 |
423 | for i=1:size(info.Variables,2)
424 | variables_to_load{i}=info.Variables(i).Name;
425 | end
426 | clear data_struct
427 |
428 | % loop over the variables
429 | for j=1:numel(variables_to_load)
430 | % extract the jth variable (type = string)
431 | var = variables_to_load{j};
432 |
433 | % use dynamic field name to add this to the structure
434 | data_struct.(var) = ncread(filename,var);
435 |
436 | % convert from single to double, if that matters to you (it does to me)
437 | if isa(data_struct.(var),'single')
438 | data_struct.(var) = double(data_struct.(var));
439 | end
440 | end
441 |
442 | data_struct.u(data_struct.u>10)=NaN;
443 | data_struct.v(data_struct.v>10)=NaN;
444 | data_struct.lat(data_struct.lat>100)=NaN;
445 | data_struct.lon(data_struct.lon>400)=NaN;
446 | data_struct.depth(data_struct.depth>15000)=NaN;
447 |
448 | % correct time offest
449 |
450 | data_struct.time=data_struct.time+1;
451 |
452 | date=datenum(2017,0,data_struct.time);
453 | dv=datevec(date);
454 |
455 | tim_sadcp=julian(dv(:,1),dv(:,2),dv(:,3),dv(:,4)+ dv(:,5)./60 + 1/60*dv(:,6)/60 );
456 |
457 | [year,month,day,hour,minu,sec,dayweek,dategreg] = julian2greg(tim_sadcp);
458 |
459 | lat_sadcp=data_struct.lat;
460 | lon_sadcp=data_struct.lon;
461 | u_sadcp=data_struct.u;
462 | v_sadcp=data_struct.v;
463 | z_sadcp=data_struct.depth(:,1);
464 |
465 | cd('C:\Users\a5278\Documents\MATLAB\LADCP_data\LADCP_2017\proc')
466 |
467 | save('sadcp.mat','lat_sadcp','lon_sadcp','u_sadcp','v_sadcp','z_sadcp','tim_sadcp')
468 |
469 | rmpath(genpath('C:\Users\a5278\Documents\MATLAB\matlab_functions'))
470 | ```
471 |
472 | Inside the "proc" folder you now need to creat a `set_cast_params.m` file (following the LDEA documentation). It tells the LDEO software where to find its inputs. Here is an example:
473 | ```Matlab
474 | f.checkpoints = sprintf('C:/Users/a5278/Documents/MATLAB/LADCP_data/LADCP_2017/checkpoints/%03d',stn);
475 | f.res = sprintf('C:/Users/a5278/Documents/MATLAB/LADCP_data/LADCP_2017/processed/%03d',stn);
476 | f.ladcpdo = sprintf('C:/Users/a5278/Documents/MATLAB/LADCP_data/LADCP_2017/raw/sta%03d_MLADC000.000',stn);
477 | p.drot = magdev(70,5);
478 |
479 | p.cruise_id ='SI_ARCTIC_2017';
480 | p.ladcp_station = stn;
481 | p.whoami = 'S. Menze';
482 | p.name = sprintf('%s # %d downlooker',p.cruise_id,p.ladcp_station);
483 | p.saveplot = [1:4 11 13:14];
484 |
485 | f.ctd = sprintf('C:/Users/a5278/Documents/MATLAB/LADCP_data/LADCP_2017/CTD/Sta%04d.cnv',stn);
486 | f.ctd_header_lines = 250;
487 | f.ctd_fields_per_line = 16;
488 | f.ctd_pressure_field = 9;
489 | f.ctd_temperature_field = 5;
490 | f.ctd_salinity_field = 6;
491 | f.ctd_time_field = 1;
492 | f.ctd_time_base = 0;
493 |
494 | f.nav = f.ctd;
495 | f.nav_header_lines = 250;
496 | f.nav_fields_per_line = 16;
497 | f.nav_lat_field=2;
498 | f.nav_lon_field=3;
499 | f.nav_time_base=0;
500 |
501 | f.sadcp = 'sadcp.mat';
502 | ```
503 |
504 | Now you are ready to process your L-ADCP files with the command `process_cast( #insert_stationnumber )`. The processed data and figures are stored in the `workingfolder/processed` folder. Here is a screenshot of the process. More detailed information and instructions can be found in the LDEO manual.
505 |
506 | 
507 |
508 | # Analysis
509 |
510 | VM-ADCP data (and often also L_ADCP data) varies with both time and space, making it a challenging data-set to interpret. In this study we used three different approaches to this problem:
511 | - spatial interpolation to map stable circulation patterns (Objective mapping)
512 | - binning in spatial and temporal boxes to compare spatial and temporal variability
513 | - discussion of individual VM- and L-ADCP sections
514 |
515 | All analysis described here was done in Matlab 2016a.
516 |
517 | **How to read in VM-ADCP netCDF files:**
518 |
519 | I loaded all VM-ADCP into a Matlab structure array using the following code:
520 | ```Matlab
521 | % load additinal function such as "julian" to convert dates
522 | addpath(genpath('C:\Users\a5278\Documents\MATLAB\matlab_functions'))
523 |
524 | adcp.depth=10:10:1000;
525 |
526 | %% first cruise
527 | filename='C:\Users\a5278\Documents\MATLAB\carbon_bridge_data\adcp_aug_2014\os75bb.nc';
528 | info=ncinfo(filename)
529 |
530 | for i=1:size(info.Variables,2)
531 | variables_to_load{i}=info.Variables(i).Name;
532 | end
533 |
534 | % loop over the variables
535 | for j=1:numel(variables_to_load)
536 | % extract the jth variable (type = string)
537 | var = variables_to_load{j};
538 | % use dynamic field name to add this to the structure
539 | data_struct.(var) = ncread(filename,var);
540 | % convert from single to double, if that matters to you (it does to me)
541 | if isa(data_struct.(var),'single')
542 | data_struct.(var) = double(data_struct.(var));
543 | end
544 | end
545 |
546 | data_struct.u(data_struct.u>10)=NaN;
547 | data_struct.v(data_struct.v>10)=NaN;
548 | data_struct.lat(data_struct.lat>100)=NaN;
549 | data_struct.lon(data_struct.lon>400)=NaN;
550 | data_struct.depth(data_struct.depth>15000)=NaN;
551 |
552 | % correct time offset
553 | data_struct.time=data_struct.time+1;
554 |
555 | date=datenum(2014,0,data_struct.time);
556 | dv=datevec(date);
557 | tim_sadcp=julian(dv);
558 | [year,month,day,hour,minu,sec,dayweek,dategreg] = julian2greg(tim_sadcp);
559 |
560 | % generate structure array
561 | adcp.lat=[];
562 | adcp.lon=[];
563 | adcp.u_mean=[];
564 | adcp.v_mean=[];
565 | adcp.v=[];
566 | adcp.u=[];
567 | adcp.time=[];
568 | % adcp.depth=[];
569 | adcp.dist=[];
570 | adcp.course=[];
571 |
572 | adcp.lat=[adcp.lat;data_struct.lat];
573 | adcp.lon=[adcp.lon;data_struct.lon];
574 |
575 | ix_val=~isnan(data_struct.u(1:50,:));
576 | ix=sum(ix_val,1)<10;
577 | a=nanmean(data_struct.u);
578 | a(ix)=NaN;
579 | adcp.u_mean=[adcp.u_mean,a];
580 |
581 | ix_val=~isnan(data_struct.v(1:50,:));
582 | ix=sum(ix_val,1)<10;
583 | a=nanmean(data_struct.v);
584 | a(ix)=NaN;
585 | adcp.v_mean=[adcp.v_mean,a];
586 |
587 | for i=1:size(data_struct.u,2)
588 | u(:,i)=interp1(data_struct.depth(:,i),data_struct.u(:,i),adcp.depth);
589 | v(:,i)=interp1(data_struct.depth(:,i),data_struct.v(:,i),adcp.depth);
590 | end
591 | adcp.u=[adcp.u,u];
592 | adcp.v=[adcp.v,v];
593 |
594 | adcp.time=[adcp.time;date];
595 | % adcp.depth=data_struct.depth(:,10);
596 |
597 | [course,dist]=legs(data_struct.lat',data_struct.lon');
598 | adcp.dist=[adcp.dist;[0;dist]]; adcp.course=[adcp.course;[0;course]];
599 |
600 | clearvars -except adcp
601 |
602 | %% additional cruises
603 |
604 | filename='C:\Users\a5278\Documents\MATLAB\SADCP_nc_files\SI_ARCTIC_VMADCP_os75_2014.nc';
605 |
606 | info=ncinfo(filename)
607 |
608 | for i=1:size(info.Variables,2)
609 | variables_to_load{i}=info.Variables(i).Name;
610 | end
611 |
612 | % loop over the variables
613 | for j=1:numel(variables_to_load)
614 | % extract the jth variable (type = string)
615 | var = variables_to_load{j};
616 | % use dynamic field name to add this to the structure
617 | data_struct.(var) = ncread(filename,var);
618 | % convert from single to double, if that matters to you (it does to me)
619 | if isa(data_struct.(var),'single')
620 | data_struct.(var) = double(data_struct.(var));
621 | end
622 | end
623 |
624 | data_struct.u(data_struct.u>10)=NaN;
625 | data_struct.v(data_struct.v>10)=NaN;
626 | data_struct.lat(data_struct.lat>100)=NaN;
627 | data_struct.lon(data_struct.lon>400)=NaN;
628 | data_struct.depth(data_struct.depth>15000)=NaN;
629 |
630 | % correct time offset
631 | data_struct.time=data_struct.time+1;
632 |
633 | date=datenum(2014,0,data_struct.time);
634 | dv=datevec(date);
635 | tim_sadcp=julian(dv);
636 | [year,month,day,hour,minu,sec,dayweek,dategreg] = julian2greg(tim_sadcp);
637 |
638 | adcp.lat=[adcp.lat;data_struct.lat];
639 | adcp.lon=[adcp.lon;data_struct.lon];
640 |
641 | ix_val=~isnan(data_struct.u(1:50,:));
642 | ix=sum(ix_val,1)<10;
643 | a=nanmean(data_struct.u);
644 | a(ix)=NaN;
645 | adcp.u_mean=[adcp.u_mean,a];
646 |
647 | ix_val=~isnan(data_struct.v(1:50,:));
648 | ix=sum(ix_val,1)<10;
649 | a=nanmean(data_struct.v);
650 | a(ix)=NaN;
651 | adcp.v_mean=[adcp.v_mean,a];
652 |
653 | for i=1:size(data_struct.u,2)
654 | u(:,i)=interp1(data_struct.depth(:,i),data_struct.u(:,i),adcp.depth);
655 | v(:,i)=interp1(data_struct.depth(:,i),data_struct.v(:,i),adcp.depth);
656 | end
657 | adcp.u=[adcp.u,u];
658 | adcp.v=[adcp.v,v];
659 |
660 | adcp.time=[adcp.time;date];
661 |
662 | [course,dist]=legs(data_struct.lat',data_struct.lon');
663 | adcp.dist=[adcp.dist;[0;dist]]; adcp.course=[adcp.course;[0;course]];
664 |
665 | clearvars -except adcp
666 |
667 | %% delete empty entries
668 |
669 | for i=1:size(adcp.u,2)
670 |
671 | if sum(isnan(adcp.u(:,i)))==numel(adcp.u(:,i))
672 |
673 | ix_delete(i)=true;
674 | else
675 | ix_delete(i)=false;
676 |
677 | end
678 | end
679 |
680 | adcp.u(:,ix_delete)=[];
681 | adcp.v(:,ix_delete)=[];
682 | adcp.lat(ix_delete)=[];
683 | adcp.lon(ix_delete)=[];
684 | adcp.u_mean(ix_delete)=[];
685 | adcp.v_mean(ix_delete)=[];
686 | adcp.time(ix_delete)=[];
687 | adcp.dist(ix_delete)=[];
688 | adcp.course(ix_delete)=[];
689 | ```
690 |
691 | ## De-tiding using the AOTIM tidal model
692 | Tidal currents were subtracted from the VM-ADCP and L-ADCP data set with the AOTIM-5 tidal model (Padman & Erofeeva, 2004). Tides on the shelf surrounding Svalbard can be as strong as 30 m s^-1. Although the tidal model produces reliable tidal estimates, the effect of shelf waves cannot be removed from the ADCP dataset by using the tidal model (Skarðhamar, Skagseth, & Albretsen, 2015).
693 |
694 | The AOTIM model can called directly from Matlab once added to the path:
695 | ```Matlab
696 | %% De-tidng the data
697 |
698 | addpath(genpath('C:\Users\a5278\Documents\MATLAB\tidal_model\tmd_toolbox'))
699 | Model='C:\Users\a5278\Documents\MATLAB\tidal_model\aotim5_tmd\Model_AOTIM5';
700 |
701 | [tide.u,a]=tmd_tide_pred(Model,adcp.time,adcp.lat,adcp.lon,'u',[]);
702 | [tide.v,a]=tmd_tide_pred(Model,adcp.time,adcp.lat,adcp.lon,'v',[]);
703 |
704 | % subtract tides from current data
705 | for i=1:numel(adcp.depth)
706 | adcp.u_detide(i,:)=adcp.u(i,:)-tide.u./100;
707 | adcp.v_detide(i,:)=adcp.v(i,:)-tide.v./100;
708 | end
709 | ```
710 | ## Calculating the along and off slope current components (Rotation of the ADCP data)
711 |
712 | For both the VM-ADCP and L-ADCP current profiles, the along and across slope current component was calculated by rotating the current vectors with slope aspect on their respective location. Slope aspect was calculated from the IBCAO bathymetry (Jakobsson et al., 2012), which was smoothed beforehand with a 2-D lowpass filter set to 18 km length. Here is the code to rotated the VM-ADCP data:
713 |
714 | ```Matlab
715 | %% rotate vm adcp
716 |
717 | latlim = [77 85];
718 | lonlim = [0 50];
719 | ibcaofile='C:\Users\a5278\Documents\MATLAB\matlab_functions\ibcao\IBCAO_V3_30arcsec_SM.grd';
720 |
721 | in=ncinfo(ibcaofile);
722 |
723 | x=ncread(ibcaofile,'x');
724 | y=ncread(ibcaofile,'y');
725 | [ibcao.lon,ibcao.lat]=meshgrid(x,y);
726 | ilat=ibcao.lat';
727 | ilon=ibcao.lon';
728 | idepth=ncread(ibcaofile,'z');
729 |
730 | [ibcao.lon,ibcao.lat]=meshgrid(x(x>lonlim(1)&xlatlim(1)&ylonlim(1)&ilonlatlim(1)&ilat> adcp
768 |
769 | adcp =
770 |
771 | depth: [1x100 double]
772 | lat: [31480x1 double]
773 | lon: [31480x1 double]
774 | u_mean: [1x31480 double]
775 | v_mean: [1x31480 double]
776 | v: [100x31480 double]
777 | u: [100x31480 double]
778 | time: [31480x1 double]
779 | dist: [31480x1 double]
780 | course: [31480x1 double]
781 | u_detide: [100x31480 double]
782 | v_detide: [100x31480 double]
783 | bottomdepth: [31480x1 double]
784 | across: [100x31480 double]
785 | along: [100x31480 double]
786 | across_detide: [100x31480 double]
787 | along_detide: [100x31480 double]
788 | u_mean_detide: [1x31480 double]
789 | v_mean_detide: [1x31480 double]
790 |
791 | ```
792 |
793 | ## Objective mapping
794 |
795 | In this section I will describe how to use objective mapping to generate an interpolated current map in Matlab. Objective mapping (Davis 1985) is a interpolation method used to generate a smooth and regular data grid from scattered datapoints, and is similar to other interpolation techniques such as kriging. The methods assumes that the data fields autocorrelation/semi-variance has a Gaussian shape `C(x,y) = E*D(x,y)+(1-E)*exp(-(x/LX)^2-(y/LY)^2)` and is the same over the entire field. In addition we need to know the noise or error of the data field, so the fitting does not produce wrong results due to outliers in the data. In Matlab objective mapping was implemented by a team from the Scripps oceanographic institute ( http://mooring.ucsd.edu/ ). We based this interpolation on all available VM-ADCP observation, consisting of 11 surveys in August-September 2014-2017. We assume that the temporal variation introduced by combing different surveys together is smoothed out by the interpolation method. Combing the VM-ADCP data of multiple surveys greatly improves the spatial coverage and resolution of the dataset.
796 |
797 | To find the radius of self similarity (standard deviation of the Gaussian variance function (LX and LY)) and relative error (E) of the VM-ADCP dataset, we calculated the average cross-semi-variance of the depth averaged current vectors u and v in the VM-ADCP data set:
798 |
799 | `variogram(datapoint,distance_from_datapoint)= 1/(number_of_datapoints_in_distance_from_datapoint) * sum( (u(datapoint) - u(datapoints_in_distance_from_datapoint)).^2 .* (v(datapoint) - v(datapoints_in_distance_from_datapoint)).^2 );`
800 |
801 | We then averaged over all data points to estimate the median and mean variogram, that depicts the semi-variance of the u and v current vectors as a function of distance (Figure below, left panel). In addition we fitted the Gaussian function `range_of_variance*(1-exp(-distance^2/standard_deviation^2))` to each data points variogram. The resulting distribution of standard deviations (the radius of self similarity) is displayed in the right panel of the figure below. The median radius of self similarity is estimated to be 30 km, and also displayed as dashed line in the left panel. We used this as standard deviation for the objective mapping algorithm and allowed the interpolation a relative error of 0.4.
802 |
803 | 
804 |
805 | Using these results we can feed our scattered VM-ADCP data to the objective mapping algorithm:
806 | ```Matlab
807 | % create target grid you wish to interpolated on
808 | latlim = [77.9 82.3];
809 | lonlim = [2 25];
810 | [g_lat,g_lon]=meshgrid(latlim(1):.1:latlim(2),lonlim(1):.3:lonlim(2));
811 |
812 | % depth average VM-ADCP data
813 | ix_d=adcp.depth>0 & adcp.depth<500;
814 | u=nanmean(adcp.u_detide(ix_d,:));
815 | v=nanmean(adcp.v_detide(ix_d,:));
816 |
817 | % set interpolation parameters and choose VM-ADCP data that in a selected time range
818 | errorthreshold=.4;
819 | corr_length=km2deg(30);
820 | dv=datevec(adcp.time);
821 | ix_adcp=adcp.dist>0.5 & ~isnan(u)' & ~isnan(v)' & dv(:,2)>6 & dv(:,2)<10;
822 |
823 | % run the objective mapping algorithm
824 | [xi,yi,ui,emu] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),u(ix_adcp),g_lat,g_lon,[corr_length,corr_length],errorthreshold);
825 | [xi,yi,vi,emv] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),v(ix_adcp),g_lat,g_lon,[corr_length,corr_length],errorthreshold);
826 | ```
827 |
828 | ## Creating current maps
829 | To show the current field, it us very useful to map a matrix of current vectors onto bathymetry. For this purpose we use the IBCAO bathymetry database (https://www.ngdc.noaa.gov/mgg/bathymetry/arctic/arctic.html) and NOAA Global coastline dataset: https://www.ngdc.noaa.gov/mgg/shorelines/data/gshhs/ .
830 |
831 | In Matlab the bathymetry data can be loaded into a strcture array:
832 | ```Matlab
833 | figure(2)
834 | clf
835 | hold on
836 | set(gcf,'color',[1 1 1])
837 |
838 |
839 | m_proj('lambert','long',lonlim,'lat',latlim);
840 | m_gshhs_h('patch',[.8 .8 .8]);
841 | m_grid('xlabeldir','end','fontsize',10);
842 |
843 |
844 | % orig1=[80]
845 | % orig2=[5]
846 | % [latout,lonout] = reckon(orig1,orig2,km2deg(30),90);
847 |
848 |
849 | [C,h]=m_contour(ibcao.lon,ibcao.lat,ibcao.depth,[-4000,-3000,-2000,-1000,-800,-600,-400,-200],'color',[.5 .5 .5]);
850 | clabel(C,h,'color',[.5 .5 .5]);
851 |
852 |
853 | factor= deg2km(distance(80,10,81,10))/deg2km(distance(80,10,80,11))
854 |
855 | latlim = [77.9 82.3];
856 | lonlim = [2 25];
857 | [g_lat,g_lon]=meshgrid(latlim(1):.08:latlim(2),lonlim(1):.2:lonlim(2));
858 | errorthreshold=.4;
859 | corr_length=km2deg(25);
860 | dv=datevec(adcp.time);
861 | ix_adcp=adcp.dist>0.5 & ~isnan(adcp.u_mean_detide)' & ~isnan(adcp.v_mean_detide)' & dv(:,2)>6 & dv(:,2)<10;
862 | [xi,yi,ui,emu] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),adcp.u_mean_detide(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
863 | [xi,yi,vi,emv] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),adcp.v_mean_detide(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
864 |
865 | % ui=ui-gu;
866 | % vi=vi-gv;
867 |
868 | bottomdepth = ltln2val(Z, refvec, xi, yi);
869 | ix=emu20 & adcp.depth<100;
920 | u=nanmean(adcp.u_detide(ix_d,:));
921 | v=nanmean(adcp.v_detide(ix_d,:));
922 |
923 | ix_adcp=adcp.dist>0.5 & ~isnan(u)' & ~isnan(v)' & dv(:,2)>6 & dv(:,2)<10;
924 | [xi,yi,ui,emu] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),u(ix_adcp),g_lat,g_lon,[corr_length,corr_length],errorthreshold);
925 | [xi,yi,vi,emv] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),v(ix_adcp),g_lat,g_lon,[corr_length,corr_length],errorthreshold);
926 |
927 | [Z_u_100, refvec_u] = geoloc2grid( xi, yi, ui,.1);
928 | [Z_v_100, refvec_v] = geoloc2grid( xi, yi, vi,.1);
929 | [Z_eu_100, refvec_u] = geoloc2grid( xi, yi, emu,.1);
930 | [Z_ev_100, refvec_v] = geoloc2grid( xi, yi, emv,.1);
931 |
932 | ix_d=adcp.depth>300 & adcp.depth<400;
933 | u=nanmean(adcp.u_detide(ix_d,:));
934 | v=nanmean(adcp.v_detide(ix_d,:));
935 |
936 | ix_adcp=adcp.dist>0.5 & ~isnan(u)' & ~isnan(v)' & dv(:,2)>6 & dv(:,2)<10;
937 | [xi,yi,ui,emu] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),u(ix_adcp),g_lat,g_lon,[corr_length,corr_length],errorthreshold);
938 | [xi,yi,vi,emv] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),v(ix_adcp),g_lat,g_lon,[corr_length,corr_length],errorthreshold);
939 |
940 | [Z_u_300, refvec_u] = geoloc2grid( xi, yi, ui,.1);
941 | [Z_v_300, refvec_v] = geoloc2grid( xi, yi, vi,.1);
942 | [Z_eu_300, refvec_u] = geoloc2grid( xi, yi, emu,.1);
943 | [Z_ev_300, refvec_v] = geoloc2grid( xi, yi, emv,.1);
944 |
945 |
946 | % filename='wormflow1.gif';
947 |
948 | animationdir='imagefolder/wormflow5'
949 | mkdir(animationdir)
950 |
951 | latlim = [77.9 82.3];
952 | lonlim = [2 25];
953 |
954 |
955 | n_iterations=100;
956 | lifetime=15;
957 | wormlength=10;
958 | coe=0.1;
959 |
960 | worm_age=1;
961 |
962 | n_create=600;
963 |
964 | clear worm100_lat worm100_lon worm300_lat worm300_lon
965 | for i_iteration=1:n_iterations
966 |
967 | %%% new worms
968 | if i_iteration==1
969 | n=n_create;
970 | t_lat=rand([1,n])*(latlim(2)-latlim(1)) + latlim(1);
971 | t_lon=rand([1,n])*(lonlim(2)-lonlim(1)) + lonlim(1);
972 |
973 | bottomdepth = ltln2val(Z, refvec, t_lat,t_lon);
974 | emu_t = ltln2val(Z_eu_100, refvec_u, t_lat,t_lon);
975 | emv_t = ltln2val(Z_ev_100, refvec_u, t_lat,t_lon);
976 |
977 | ix=bottomdepth<0 & emu_tlifetime;
1072 | worm100_lat(:,ix) = [];
1073 | worm100_lon(:,ix) = [];
1074 | worm100_age(ix) = [];
1075 |
1076 | worm100_age=worm100_age+1;
1077 |
1078 |
1079 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080 |
1081 |
1082 | %%% new worms
1083 | if i_iteration==1
1084 | n=n_create;
1085 | t_lat=rand([1,n])*(latlim(2)-latlim(1)) + latlim(1);
1086 | t_lon=rand([1,n])*(lonlim(2)-lonlim(1)) + lonlim(1);
1087 |
1088 | bottomdepth = ltln2val(Z, refvec, t_lat,t_lon);
1089 | emu_t = ltln2val(Z_eu_300, refvec_u, t_lat,t_lon);
1090 | emv_t = ltln2val(Z_ev_300, refvec_u, t_lat,t_lon);
1091 |
1092 | ix=bottomdepth<0 & emu_tlifetime;
1187 | worm300_lat(:,ix) = [];
1188 | worm300_lon(:,ix) = [];
1189 | worm300_age(ix) = [];
1190 |
1191 | worm300_age=worm300_age+1;
1192 |
1193 | %%%% plot
1194 | figure(3)
1195 | clf
1196 | hold on
1197 | set(gcf,'color',[1 1 1])
1198 | m_proj('lambert','long',lonlim,'lat',latlim);
1199 | % m_contourf(ibcao.lon,ibcao.lat,ibcao.depth,[-5000:200:0],'color',[.5 .5 .5]);
1200 | % colormap(cmocean('deep'))
1201 | [C,h]=m_contour(ibcao.lon,ibcao.lat,ibcao.depth,[-5000:200:0],'color',[.5 .5 .5]);
1202 | % clabel(C,h,[-4000,-2000,-1000:50:-100],'color',[.5 .5 .5]);
1203 | m_gshhs_h('patch',[.9 .9 .9]);
1204 | m_grid('xlabeldir','end','fontsize',10);
1205 |
1206 | cmap100=cmocean('speed',wormlength);
1207 | cmap300=cmocean('amp',wormlength);
1208 |
1209 | % widthvec=linspace(1,1.8,wormlength);
1210 |
1211 |
1212 | for k=1:size(worm300_lat,1)-1
1213 | for i=1:size(worm300_lat,2)
1214 | m_plot(worm300_lon(k:k+1,i),worm300_lat(k:k+1,i),'-','color',cmap300(k,:),'linewidth',1.8)
1215 | end
1216 | end
1217 |
1218 | for k=1:size(worm100_lat,1)-1
1219 | for i=1:size(worm100_lat,2)
1220 | m_plot(worm100_lon(k:k+1,i),worm100_lat(k:k+1,i),'-','color',cmap100(k,:),'linewidth',1.8)
1221 | end
1222 | end
1223 |
1224 |
1225 | drawnow
1226 |
1227 | set(gcf,'PaperPositionMode','auto')
1228 | print(gcf,'-dpng',[animationdir,'/frame_',num2str(i_iteration)],'-r200')
1229 |
1230 | %
1231 | % F(i_iteration) = getframe(gcf);
1232 | %
1233 | % im = frame2im(F(i_iteration));
1234 | % [A,map] = rgb2ind(im,256);
1235 | % if i== i_iteration;
1236 | % imwrite(A,map,filename,'gif','LoopCount',inf,'DelayTime',.1);
1237 | % else
1238 | % imwrite(A,map,filename,'gif','WriteMode','append','DelayTime',.1);
1239 | % end
1240 |
1241 | end
1242 | ```
1243 | # Making a GIF from the frames
1244 |
1245 | ```Matlab
1246 | %% make gif from images
1247 |
1248 |
1249 | animationdir='imagefolder/wormflow5/gif/';
1250 |
1251 | filelist=dir([animationdir,'*.png']);
1252 | anmimationname='animation.gif';
1253 |
1254 | dates = extractfield(filelist, 'datenum');
1255 | names = extractfield(filelist, 'name');
1256 |
1257 | [a,b]=sort(dates);
1258 | names=names(b);
1259 |
1260 | for i=1:numel(names)
1261 |
1262 | im = imread([animationdir,names{i}]);
1263 | [A,map] = rgb2ind(im,256);
1264 | if i==1;
1265 | imwrite(A,map,[animationdir,anmimationname],'gif','LoopCount',inf,'DelayTime',.07);
1266 | else
1267 | imwrite(A,map,[animationdir,anmimationname],'gif','WriteMode','append','DelayTime',.07);
1268 | end
1269 |
1270 | end
1271 | ```
1272 |
1273 | # References
1274 |
1275 | Davis, R. E. (1985). Objective mapping by least squares fitting. Journal of Geophysical Research, 90(C3), 4773. http://doi.org/10.1029/JC090iC03p04773
1276 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Processing-and-analysis-of-large-ADCP-datasets
2 | This document will guide you through the steps necessary to process and analyse both vessel mounted (VM-ADCP) and lowered acoustic doppler current profilers (L-ADCP). Both are complex data sources that contain a lot of noise and potential biases, but dont despair, with todays programms and code packages anyone can work with this data and produce meaningfull results.
3 |
4 | This tutorial will teach you how to make beautiful visualizations of ADCP data such as these:
5 |
6 | 
7 |
8 | 
9 |
--------------------------------------------------------------------------------
/animation_small.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/animation_small.gif
--------------------------------------------------------------------------------
/code_to_analyse_and_plot_adcp_data_for_paper1.m:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | addpath(genpath('C:\Users\a5278\Documents\MATLAB\matlab_functions'))
6 |
7 |
8 | latlim = [77.9 82.3];
9 | lonlim = [2 25];
10 | ibcaofile='C:\Users\a5278\Documents\MATLAB\matlab_functions\ibcao\IBCAO_V3_30arcsec_SM.grd';
11 |
12 | in=ncinfo(ibcaofile);
13 |
14 | x=ncread(ibcaofile,'x');
15 | y=ncread(ibcaofile,'y');
16 | [ibcao.lon,ibcao.lat]=meshgrid(x,y);
17 | ilat=ibcao.lat';
18 | ilon=ibcao.lon';
19 | idepth=ncread(ibcaofile,'z');
20 |
21 | [ibcao.lon,ibcao.lat]=meshgrid(x(x>lonlim(1)&xlatlim(1)&ylonlim(1)&ilonlatlim(1)&ilat0.5 & dv(:,2)>6 & dv(:,2)<10 & dv(:,1)==2014;
60 | a1=m_plot(adcp.lon(ix),adcp.lat(ix),'.','color',[255, 102, 102]./255)
61 | ix=adcp.dist>0.5 & dv(:,2)>6 & dv(:,2)<10 & dv(:,1)==2015;
62 | a2=m_plot(adcp.lon(ix),adcp.lat(ix),'.','color',[153, 255, 153]./255 )
63 | ix=adcp.dist>0.5 & dv(:,2)>6 & dv(:,2)<10 & dv(:,1)==2016;
64 | a3=m_plot(adcp.lon(ix),adcp.lat(ix),'.','color',[102, 153, 255]./255 )
65 | ix=adcp.dist>0.5 & dv(:,2)>6 & dv(:,2)<10 & dv(:,1)==2017;
66 | a4=m_plot(adcp.lon(ix),adcp.lat(ix),'.','color',[255, 153, 255]./255 )
67 |
68 | for i=1:numel(p_lon)
69 | m_plot(p_lon{i},p_lat{i},'-k','linewidth',1.5)
70 | m_text( mean(p_lon{i}) , mean(p_lat{i}),num2str(i),'fontweight','bold','fontsize',15)
71 |
72 | end
73 |
74 | a1=m_plot([90,90],[90,90],'r-','linewidth',2,'color',[255, 102, 102]./255)
75 | a2=m_plot([90,90],[90,90],'g-','linewidth',2,'color',[153, 255, 153]./255 )
76 | a3=m_plot([90,90],[90,90],'b-','linewidth',2,'color',[102, 153, 255]./255 )
77 | a4=m_plot([90,90],[90,90],'m-','linewidth',2,'color',[255, 153, 255]./255 )
78 |
79 | legend([a1,a2,a3,a4],'2014','2015','2016','2017')
80 |
81 |
82 | % fram strait
83 | stationlist=[540:547];
84 | clear s a ix_transect
85 | [a]=find(ismember(ctd2014_station,stationlist));
86 | s(ctd2014_station(a))=a;
87 | ix_transect=s(stationlist);
88 | la=ctd2014_lat(ix_transect);
89 | lo=ctd2014_lon(ix_transect);
90 | h=m_plot(lo,la,'^r','markerfacecolor','r','markersize',6)
91 | uistack(h,'top');
92 |
93 | %hinlopen
94 | stationlist=[551 552 553 554 556 557];
95 | clear s a ix_transect
96 | [a]=find(ismember(ctd2014_station,stationlist));
97 | s(ctd2014_station(a))=a;
98 | ix_transect=s(stationlist);
99 | la=ctd2014_lat(ix_transect);
100 | lo=ctd2014_lon(ix_transect);
101 | h=m_plot(lo,la,'^r','markerfacecolor','r','markersize',6)
102 | uistack(h,'top');
103 |
104 | %fram2
105 | stationlist=[597,596,595,594,593,591,590];
106 | clear s a ix_transect
107 | [a]=find(ismember(ctd2014_station,stationlist));
108 | s(ctd2014_station(a))=a;
109 | ix_transect=s(stationlist);
110 | la=ctd2014_lat(ix_transect);
111 | lo=ctd2014_lon(ix_transect);
112 | h=m_plot(lo,la,'^r','markerfacecolor','r','markersize',6)
113 | uistack(h,'top');
114 |
115 | %
116 | % %framstrait2017
117 | stationlist=[95,126];
118 | clear s a ix_transect
119 | [a]=find(ismember(ctd2017_station,stationlist));
120 | s(ctd2017_station(a))=a;
121 | ix_transect=s(stationlist);
122 | la=ctd2017_lat(ix_transect);
123 | lo=ctd2017_lon(ix_transect);
124 | h=m_plot(lo,la,'^m','markerfacecolor','r','markersize',6)
125 | uistack(h,'top');
126 |
127 | % h=m_plot(6+44/60,79+40/60,'pb','markerfacecolor','b','markersize',12)
128 | % uistack(h,'top');
129 |
130 |
131 | m_text(15,79,'Isforden')
132 | m_text(15,79,'Prins Karls Forlandet')
133 | m_text(15,79,'Hinlopen strait and trench')
134 | m_text(15,79,'Yermak Plateau')
135 | m_text(15,79,'Spitsbergen')
136 | m_text(15,79,'Nordauslandet')
137 | %
138 | %
139 | % set(gcf,'PaperPositionMode','auto')
140 | % print(gcf,'-dpng',['imagefolder/9boxes_map_3'],'-r600')
141 |
142 | %%
143 |
144 |
145 | addpath(genpath('C:\Users\a5278\Documents\MATLAB\tidal_model\tmd_toolbox'))
146 | Model='C:\Users\a5278\Documents\MATLAB\tidal_model\aotim5_tmd\Model_AOTIM5';
147 |
148 | [tide.u,a]=tmd_tide_pred(Model,adcp.time,adcp.lat,adcp.lon,'u',[]);
149 | [tide.v,a]=tmd_tide_pred(Model,adcp.time,adcp.lat,adcp.lon,'v',[]);
150 |
151 | ix_d=adcp.depth>00 & adcp.depth<500;
152 | u=nanmean(adcp.u_detide(ix_d,:));
153 | v=nanmean(adcp.v_detide(ix_d,:));
154 |
155 | adcp.u_mean_detide=u - (tide.u./100);
156 | adcp.v_mean_detide=v - (tide.v./100);
157 |
158 |
159 |
160 |
161 | factor= deg2km(distance(80,10,81,10))/deg2km(distance(80,10,80,11))
162 |
163 | latlim = [77.9 82.3];
164 | lonlim = [2 25];
165 | [g_lat,g_lon]=meshgrid(latlim(1):.08:latlim(2),lonlim(1):.2:lonlim(2));
166 | errorthreshold=.4;
167 | corr_length=km2deg(25);
168 | dv=datevec(adcp.time);
169 | ix_adcp=adcp.dist>0.5 & ~isnan(adcp.u_mean_detide)' & ~isnan(adcp.v_mean_detide)' & dv(:,2)>6 & dv(:,2)<10;
170 | [xi,yi,ui,emu] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),adcp.u_mean_detide(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
171 | [xi,yi,vi,emv] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),adcp.v_mean_detide(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
172 |
173 | load('p_boxes.mat')
174 |
175 |
176 | bottomdepth = ltln2val(Z, refvec, xi, yi);
177 |
178 | uu=ui;
179 | ix=emu0
218 |
219 | for k=1:numel(lat1(ix_box1))
220 | d=distance( lat1(ix_box1(k)), lon1(ix_box1(k)) , lat2(ix_box2), lon2(ix_box2) );
221 | min_d(k)=deg2km(min(d));
222 | end
223 | segment_km(i_box,i)=median(min_d(min_d<30));
224 |
225 | else
226 | segment_km(i_box,i)=NaN;
227 | end
228 |
229 | end
230 |
231 | end
232 |
233 | %%
234 |
235 |
236 | clear along_slope_current_median along_slope_current_mean along_slope_current_mode
237 | clear across_slope_current_median across_slope_current_mean across_slope_current_mode
238 |
239 | iy=1;
240 | for currrent_year=2014:2017
241 |
242 |
243 |
244 | depth_intervals=[-2500:200:0];
245 | depth_vec=-2400:200:-100;
246 |
247 | for i_box=1:numel(p_lon)
248 |
249 | ix_box = inpolygon(adcp.lat,adcp.lon,p_lat{i_box},p_lon{i_box}) & dv(:,2)>6 & dv(:,2)<10 & dv(:,1)==currrent_year & adcp.dist>0.5;
250 | box_number_of_profiles(i_box)=sum(ix_box);
251 |
252 |
253 | ix_box = inpolygon(adcp.lat,adcp.lon,p_lat{i_box},p_lon{i_box}) & dv(:,2)>6 & dv(:,2)<10 & dv(:,1)==currrent_year;
254 | % ix_box = inpolygon(adcp.lat,adcp.lon,p_lat{i_box},p_lon{i_box}) & dv(:,2)>6 & dv(:,2)<10 ;
255 |
256 |
257 |
258 |
259 | clear u_dist_gauss_mean v_dist_gauss_mean u_dist_gauss_std v_dist_gauss_std uv_distrib_n_profiles
260 | clear rotated_current across along perc_across perc_along perc_u perc_v
261 |
262 |
263 |
264 | for i_depth=1:(numel(depth_intervals)-1)
265 |
266 | ix=adcp.dist>0.5 & ix_box & adcp.bottomdepth>depth_intervals(i_depth) & adcp.bottomdepth0.5 & ~isnan(adcp.u_mean_detide)' & ~isnan(adcp.v_mean_detide)' & dv(:,2)>6 & dv(:,2)<10;
1074 | [xi,yi,ui,emu] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),adcp.u_mean_detide(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
1075 | [xi,yi,vi,emv] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),adcp.v_mean_detide(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
1076 |
1077 | % ui=ui-gu;
1078 | % vi=vi-gv;
1079 |
1080 | bottomdepth = ltln2val(Z, refvec, xi, yi);
1081 | ix=emudepth_intervals(i_depth) & interpfield.bottomdepth0));
1208 | p_box_interptrans_sumsouth(i)=nansum(interpfield.transport_alongslope_median(i,interpfield.transport_alongslope_median(i,:)<0));
1209 |
1210 |
1211 | end
1212 |
1213 | xlabel('Isobath depth in m')
1214 | ylabel('Sv (10^6 m^3 s^{-1})')
1215 |
1216 | legend('2014','2015','2016','2017','Interpolation')
1217 | %
1218 | %
1219 | % mkdir('imagefolder')
1220 | % set(gcf,'PaperPositionMode','auto')
1221 | % print(gcf,'-dpng',['imagefolder/9boxes_mean_across_slope_transport5'],'-r400')
1222 | % savefig(gcf,'imagefolder/9boxes_mean_across_slope_transport5')
1223 | % %
1224 |
1225 | %%
1226 |
1227 | s_lat{1}=[78.1,78.1]; s_lon{1}=[5,10];
1228 | s_lat{2}=[78.33,78.33]; s_lon{2}=[5,10];
1229 | s_lat{3}=[78.66,78.66]; s_lon{3}=[5,10];
1230 | s_lat{4}=[79,79]; s_lon{4}=[4,10];
1231 | s_lat{5}=[79.33,79.33]; s_lon{5}=[4,10.5];
1232 | s_lat{6}=[79.66,79.66]; s_lon{6}=[4,10.5];
1233 |
1234 | s_lat{7}=[81,80.3]; s_lon{7}=[11,13];
1235 |
1236 | s_lat{8}=[81,80.4]; s_lon{8}=[12.7,14.7];
1237 |
1238 | s_lat{9}=[81,80.4]; s_lon{9}=[14.2,16.2];
1239 |
1240 | s_lat{10}=[81.3,81]; s_lon{10}=[15,19];
1241 |
1242 |
1243 | %branches
1244 | s_lat{11}=[80.1,79.9]; s_lon{11}=[9.5,12];
1245 | s_lat{12}=[80.3,81]; s_lon{12}=[10,10];
1246 | s_lat{13}=[80.3,79.88]; s_lon{13}=[7,3];
1247 |
1248 | %%
1249 |
1250 |
1251 | a=deg2km(distance(xi(1,1),yi(1,1),xi(:,1),yi(:,1)) );
1252 | b=deg2km(distance(xi(1,1),yi(1,1),xi(1,:),yi(1,:)) );
1253 |
1254 | xlen=mean(diff(a))
1255 | ylen=mean(diff(b))
1256 |
1257 | bottomd=ltln2val(Z, refvec, xi,yi);
1258 | bottomd(bottomd<-500)=500;
1259 |
1260 | area_x=abs(bottomd)*xlen*1000;
1261 | area_y=abs(bottomd)*ylen*1000;
1262 |
1263 | trans_x=area_x.*vi./10^6;
1264 | trans_y=area_y.*ui./10^6;
1265 |
1266 | trans_abs=sqrt(trans_x.^2 + trans_y.^2);
1267 |
1268 | figure(2)
1269 | clf
1270 | hold on
1271 | set(gcf,'color',[1 1 1])
1272 |
1273 |
1274 | m_proj('lambert','long',lonlim,'lat',latlim);
1275 | % m_coast('patch',[0.9 0.95 0.9]);
1276 | [C,h]=m_contour(ibcao.lon,ibcao.lat,ibcao.depth,[-6000:200:0],'color',[.5 .5 .5]);
1277 | clabel(C,h,[-4000,-2000,-1000:200:-100],'color',[.5 .5 .5]);
1278 |
1279 |
1280 | m_gshhs_h('patch',[.9 .9 .9]);
1281 | m_grid('xlabeldir','end','fontsize',10);
1282 |
1283 | bottomdepth = ltln2val(Z, refvec, xi, yi);
1284 |
1285 | ix=emu0))./10^6;
1361 | pos_transp_u(i)=nansum(section.transp_u(section.transp_u>0))./10^6;
1362 | pos_transp_v(i)=nansum(section.transp_v(section.transp_v>0))./10^6;
1363 |
1364 | neg_transp_across(i)=nansum(section.transp_across(section.transp_across<0))./10^6;
1365 | neg_transp_u(i)=nansum(section.transp_u(section.transp_u<0))./10^6;
1366 | neg_transp_v(i)=nansum(section.transp_v(section.transp_v<0))./10^6;
1367 |
1368 |
1369 | end
1370 |
1371 | %%
1372 |
1373 |
1374 | depth_intervals=[-2500:200:0];
1375 | depth_vec=-2400:200:-100;
1376 |
1377 | for i_box=1:numel(p_lon)
1378 |
1379 | ix_box = inpolygon(interpfield.xi,interpfield.yi,p_lat{i_box},p_lon{i_box});
1380 |
1381 | clear u_dist_gauss_mean v_dist_gauss_mean u_dist_gauss_std v_dist_gauss_std uv_distrib_n_profiles
1382 | clear rotated_current across along perc_across perc_along perc_u perc_v
1383 |
1384 |
1385 |
1386 | for i_depth=1:(numel(depth_intervals)-1)
1387 |
1388 | ix= ix_box & interpfield.bottomdepth>depth_intervals(i_depth) & interpfield.bottomdepth0));
1431 | % p_box_interptrans_sumsouth(i)=nansum(interpfield.transport_alongslope_median_constant_az(i,interpfield.transport_alongslope_median_constant_az(i,:)<0));
1432 | %
1433 |
1434 | end
1435 |
1436 | %%
1437 |
1438 | figure(9)
1439 | clf
1440 | hold on
1441 | box on
1442 | grid on
1443 |
1444 | % boxes
1445 | plot(1:4,p_box_interptrans_sumnorth(1:4),'.--r','markersize',20)
1446 | p1=plot(4:8,p_box_interptrans_sumnorth(4:8),'.-r','markersize',20)
1447 | plot(8:9,p_box_interptrans_sumnorth(8:9),'.--r','markersize',20)
1448 |
1449 | %plot(1:9,p_box_interptrans_sumsouth,'.-b','markersize',20)
1450 | %plot(1:9,p_box_interptrans_sum,'.-k','markersize',20)
1451 | plot(1:4,p_box_interptrans_sum_constantaz(1:4),'.--b','markersize',20)
1452 | p2=plot(4:8,p_box_interptrans_sum_constantaz(4:8),'.-b','markersize',20)
1453 | plot(8:9,p_box_interptrans_sum_constantaz(8:9),'.--b','markersize',20)
1454 |
1455 | x=[linspace(1,5,6),linspace(7,9,4)];
1456 | %plot(x,pos_transp_across(1:10),'^--r','markersize',4,'markerfacecolor','r')
1457 | %plot(x,neg_transp_across(1:10),'^--b','markersize',4,'markerfacecolor','b')
1458 | plot(x(1:5),sum_transp_across(1:5),'.--g','markersize',20,'color',[0 0.7 0])
1459 | p3=plot(x(5:9),sum_transp_across(5:9),'.-g','markersize',20,'color',[0 0.7 0])
1460 | plot(x(9:10),sum_transp_across(9:10),'.--g','markersize',20,'color',[0 0.7 0])
1461 |
1462 | p4=plot(5,1.7,'^k','markerfacecolor','k')
1463 | plot(5,0.7,'^k','markerfacecolor','k')
1464 | text(5.15,1.7,'2015')
1465 | text(5.15,0.7,'2014')
1466 | plot(2,1.2,'^k','markerfacecolor','k')
1467 | text(2,1.2,'2014')
1468 |
1469 | plot(5.5,sum_transp_across(11),'.','color',[0 0.7 0],'markersize',20)
1470 | plot(5.5,-sum_transp_across(12),'.','color',[0 0.7 0],'markersize',20)
1471 | plot(5.5,-sum_transp_across(13),'.','color',[0 0.7 0],'markersize',20)
1472 |
1473 | text(5.5,sum_transp_across(11),'SB','fontweight','bold','color',[0 0.7 0])
1474 | text(5.5,-sum_transp_across(12),'YPB','fontweight','bold','color',[0 0.7 0])
1475 | text(5.5,-sum_transp_across(13),'YB','fontweight','bold','color',[0 0.7 0])
1476 |
1477 | % text(5.5,-sum_transp_across(13)+sum_transp_across(11),'SB+YPB')
1478 |
1479 | for i=1:9
1480 | text(i-.2,4.1,['Box ',num2str(i)],'rotation',30)
1481 | end
1482 |
1483 | ylim([0 4])
1484 | ylabel('Sv (10^6 m^3 s^{-1})')
1485 | legend([p1,p2,p3,p4],'Obj. map. box averged net transport - local azimuth','Obj. map. box averged net transport - box averaged azimuth','Obj. map. transect net transport','L-ADCP net transport')
1486 | set(gca,'xticklabels',{'Isfjorden 78^\circ N','P.K. forlandet 78.5^\circ N','Kongsfjorden 79^\circ N','79.3^\circ N','79.6^\circ N','Yermak Plateau 80^\circ N','13^\circ E', 'Hinlopen trench 15^\circ E','18^\circ E' },'xticklabelrotation',30)
1487 |
1488 | % %
1489 | %
1490 | % mkdir('imagefolder')
1491 | % set(gcf,'PaperPositionMode','auto')
1492 | % print(gcf,'-dpng',['transport_estimates_boxes_vs_transects_comparison2'],'-r300')
1493 | % savefig(gcf,'transport_estimates_boxes_vs_transects_comparison2')
1494 |
1495 | %%
1496 |
1497 |
1498 | %% get current field
1499 | latlim = [77.9 82.3];
1500 | lonlim = [2 25];
1501 |
1502 | [g_lat,g_lon]=meshgrid(latlim(1):.08:latlim(2),lonlim(1):.2:lonlim(2));
1503 |
1504 | errorthreshold=.4;
1505 |
1506 | factor= deg2km(distance(80,10,81,10))/deg2km(distance(80,10,80,11))
1507 | corr_length=km2deg(25);
1508 |
1509 | dv=datevec(adcp.time);
1510 |
1511 | ix_d=adcp.depth>00 & adcp.depth<500;
1512 | u=nanmean(adcp.u_detide(ix_d,:));
1513 | v=nanmean(adcp.v_detide(ix_d,:));
1514 |
1515 | ix_adcp=adcp.dist>0.5 & ~isnan(u)' & ~isnan(v)' & dv(:,2)>6 & dv(:,2)<10;
1516 | [xi,yi,ui,emu] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),u(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
1517 | [xi,yi,vi,emv] = objmap(adcp.lat(ix_adcp),adcp.lon(ix_adcp),v(ix_adcp),g_lat,g_lon,[corr_length,corr_length*factor],errorthreshold);
1518 |
1519 | div = divergence(ui,vi);
1520 | [gu,gv]=gradient(div);
1521 |
1522 | ui=ui+gu;
1523 | vi=vi+gv;
1524 |
1525 | [Z_u, refvec_u] = geoloc2grid( xi, yi, ui,.1);
1526 | [Z_v, refvec_v] = geoloc2grid( xi, yi, vi,.1);
1527 | [Z_eu, refvec_u] = geoloc2grid( xi, yi, emu,.1);
1528 | [Z_ev, refvec_v] = geoloc2grid( xi, yi, emv,.1);
1529 |
1530 | %% calc worms for bin plot
1531 | latlim = [77.9 82.3];
1532 | lonlim = [2 25];
1533 | n=7000;
1534 | t_lat=rand([1,n])*(latlim(2)-latlim(1)) + latlim(1);
1535 | t_lon=rand([1,n])*(lonlim(2)-lonlim(1)) + lonlim(1);
1536 |
1537 | bottomdepth = ltln2val(Z, refvec, t_lat,t_lon);
1538 | emu_t = ltln2val(Z_eu, refvec_u, t_lat,t_lon);
1539 | emv_t = ltln2val(Z_ev, refvec_u, t_lat,t_lon);
1540 |
1541 | errorthreshold=.4
1542 |
1543 | ix=bottomdepth<0 ;%& emu_t b_vec_lat(i1)-.025 & worm_lat(:) < b_vec_lat(i1)+.025 & worm_lon(:) > b_vec_lon(i2)-.075 & worm_lon(:) < b_vec_lon(i2)+.075 );
1674 | b_counts(i2,i1)=n_worms;
1675 |
1676 | n_worms= sum( ixx_sb(:) & worm_lat(:) > b_vec_lat(i1)-.025 & worm_lat(:) < b_vec_lat(i1)+.025 & worm_lon(:) > b_vec_lon(i2)-.075 & worm_lon(:) < b_vec_lon(i2)+.075 );
1677 | b_counts_sb(i2,i1)=n_worms;
1678 |
1679 | n_worms= sum( ixx_ypb(:) & worm_lat(:) > b_vec_lat(i1)-.025 & worm_lat(:) < b_vec_lat(i1)+.025 & worm_lon(:) > b_vec_lon(i2)-.075 & worm_lon(:) < b_vec_lon(i2)+.075 );
1680 | b_counts_ypb(i2,i1)=n_worms;
1681 |
1682 | n_worms= sum( ixx_yb(:) & worm_lat(:) > b_vec_lat(i1)-.025 & worm_lat(:) < b_vec_lat(i1)+.025 & worm_lon(:) > b_vec_lon(i2)-.075 & worm_lon(:) < b_vec_lon(i2)+.075 );
1683 | b_counts_yb(i2,i1)=n_worms;
1684 | end
1685 | i1./numel(b_vec_lat)
1686 | end
1687 |
1688 | %%
1689 |
1690 |
1691 |
1692 | b_counts_yb_n=b_counts_yb ./ max(b_counts_yb(:));
1693 | b_counts_ypb_n=b_counts_ypb ./ max(b_counts_ypb(:));
1694 | b_counts_sb_n=b_counts_sb ./ max(b_counts_sb(:));
1695 |
1696 | plotfield=nan(size(b_counts_yb_n));
1697 | cbins=10;
1698 | for i1=1:numel(b_vec_lat)
1699 | for i2=1:numel(b_vec_lon)
1700 |
1701 | [a,b]=max([b_counts_sb_n(i2,i1),b_counts_ypb_n(i2,i1),b_counts_yb_n(i2,i1)]);
1702 |
1703 | if b==2 & b_counts_yb_n(i2,i1)>b_counts_sb_n(i2,i1)
1704 | b=3;
1705 | end
1706 | if a==0
1707 | plotfield(i2,i1)=NaN;
1708 | else
1709 | switch b
1710 | case 1
1711 | [c]=hist(b_counts_sb_n(i2,i1),[linspace(0,.002,cbins-1),1] );
1712 | plotfield(i2,i1)=find(c);
1713 | case 2
1714 | [c]=hist(b_counts_ypb_n(i2,i1),[linspace(0,.01,cbins-1),1] );
1715 | plotfield(i2,i1)=find(c)+cbins;
1716 | case 3
1717 | [c]=hist(b_counts_yb_n(i2,i1),[linspace(0,.01,cbins-1),1] );
1718 | plotfield(i2,i1)=find(c)+cbins*2;
1719 | end
1720 | end
1721 |
1722 | end
1723 | end
1724 |
1725 | c1=cmocean('amp',cbins)
1726 | c2=cmocean('speed',cbins)
1727 | c3=cmocean('dense',cbins)
1728 |
1729 | cmap=[c1;c2;c3];
1730 |
1731 | % cut off
1732 | plotfield(b_lon>18)=NaN;
1733 | plotfield(b_lat>81.3)=NaN;
1734 |
1735 | figure(4)
1736 | clf
1737 | hold on
1738 | set(gcf,'color',[1 1 1])
1739 | latlim = [77.9 81.5];
1740 | lonlim = [2 20];
1741 | m_proj('lambert','long',lonlim,'lat',latlim);
1742 | % m_coast('patch',[0.9 0.95 0.9]);
1743 | [C,h]=m_contour(ibcao.lon,ibcao.lat,ibcao.depth,[-5000:200:0],'color',[.5 .5 .5]);
1744 | clabel(C,h,[-4000,-2000,-1000:50:-100],'color',[.5 .5 .5]);
1745 |
1746 | m_pcolor(b_lon,b_lat,plotfield);
1747 | shading flat
1748 | colormap(gca,cmap)
1749 | set(gca,'clim',[0 cbins*3])
1750 | m_gshhs_h('patch',[.9 .9 .9]);
1751 | m_grid('xlabeldir','end','fontsize',10);
1752 |
1753 | p_lat=[80.2,80.05];
1754 | p_lon=[10,12];
1755 | m_plot(p_lon,p_lat,'-r','linewidth',2)
1756 |
1757 | p_lat=[80.2,80.8];
1758 | p_lon=[8,9];
1759 | m_plot(p_lon,p_lat,'-g','linewidth',2)
1760 |
1761 | p_lat=[79.88,80.3];
1762 | p_lon=[3,6.6];
1763 | m_plot(p_lon,p_lat,'-b','linewidth',2)
1764 |
1765 |
1766 | % % mkdir('imagefolder')
1767 | % set(gcf,'PaperPositionMode','auto')
1768 | % print(gcf,'-dpng',['imagefolder/particel_tracking_pathways6'],'-r500')
1769 | % savefig(gcf,'imagefolder/particel_tracking_pathways6')
1770 |
1771 |
--------------------------------------------------------------------------------
/f6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/f6.png
--------------------------------------------------------------------------------
/gaussian_eddy_test.m:
--------------------------------------------------------------------------------
1 |
2 | clc;clear;
3 |
4 | % Set coefficients
5 | eta0=0.01; % highest height of eddy
6 | R=300; % eddy's radius
7 | f=0.01; % coriolis coefficient
8 | g=9.81; % gravity constant
9 |
10 | % Set grid
11 | x=-500:10:500;
12 | y=-500:10:500;
13 | [x y]=meshgrid(x,y);
14 |
15 | % Set sea surface height
16 | eta=eta0*exp(-(x.^2+y.^2)/R^2);
17 |
18 | % Calcualte geostrophic velocity
19 | v=(g*eta0)/f*(-2*x/R^2).*exp(-(x.^2+y.^2)/R^2);
20 | u=-(g*eta0)/f*(-2*y/R^2).*exp(-(x.^2+y.^2)/R^2);
21 |
22 |
23 | % Visualization
24 | figure(1)
25 | clf
26 | set(gcf,'color','w')
27 | subplot(2,1,1)
28 | surf(x,y,eta)
29 | view([-45 80])
30 | title('\eta, sea surface height','fontweight','bold')
31 | subplot(2,1,2)
32 | z0=zeros(size(x));
33 | quiver3(x,y,z0,u,v,z0)
34 | view([-45 80])
35 | axis([-500 500 -500 500 0 0.01])
36 | title('u and v, velocities','fontweight','bold')
37 |
38 | %% get observations
39 |
40 | n_obs=200;
41 |
42 | x_vec=x(:);
43 | y_vec=y(:);
44 | u_vec=u(:);
45 | v_vec=v(:);
46 |
47 | ixr=randi(numel(x_vec),[n_obs,1]);
48 | x_obs=x_vec(ixr);
49 | y_obs=y_vec(ixr);
50 | u_obs=u_vec(ixr);
51 | v_obs=v_vec(ixr);
52 |
53 | figure(2)
54 | clf
55 | hold on
56 | quiver(x,y,u,v,'k')
57 | quiver(x_obs,y_obs,u_obs,v_obs,'r')
58 |
59 | figure(3)
60 | clf
61 | div=divergence(u,v);
62 | surf(div)
63 | shading flat
64 | %% determine centers
65 |
66 | % 50 centers
67 | n_centers=50;
68 |
69 | ixr=randi(numel(x_obs),[n_centers,1]);
70 | x_c=x_obs(ixr);
71 | y_c=y_obs(ixr);
72 | u_c=u_obs(ixr);
73 | v_c=v_obs(ixr);
74 |
75 |
76 | figure(2)
77 | clf
78 | hold on
79 | quiver(x,y,u,v,'k')
80 | % quiver(x_obs,y_obs,u_obs,v_obs,'r')
81 | plot(x_c,y_c,'or')
82 |
83 |
84 | %% train RBFs
85 |
86 | data=[u_obs,v_obs]';
87 | data=data(:);
88 |
89 | % determine radiuses/differences
90 | clear r rbf
91 |
92 | dataindex=1;
93 | for i=1:size(x_obs,1)
94 |
95 | %distance to centers
96 | r=sqrt( (x_obs(i)-x_c).^2 + (y_obs(i)-y_c).^2 )';
97 | logr=log(r);
98 | logr(r==0)=0;
99 |
100 | % u part
101 | rbf(dataindex,:) = [ 1,0,x_obs(i),y_obs(i),0 , [r.^2.*(12*logr+7) , zeros(size(r))] + [ -(8*logr+6) .* (x_obs(i)-x_c)' .* (x_obs(i)-x_c)' , -(8*logr+6) .* (x_obs(i)-x_c)' .* (y_obs(i)-y_c)' ] ] ;
102 | %v part
103 | rbf(dataindex+1,:)= [0,1,-y_obs(i),0,x_obs(i) , [zeros(size(r)), r.^2.*(12*logr+7)] + [ -(8*logr+6) .* (y_obs(i)-y_c)' .* (x_obs(i)-x_c)' , -(8*logr+6) .* (y_obs(i)-y_c)' .* (y_obs(i)-y_c)' ] ] ;
104 | dataindex=dataindex+2
105 | end
106 |
107 |
108 | params=data'/rbf' ;%use mrdivide to solve system of equations. For large systems it may
109 |
110 | %% evaluate rbfs
111 |
112 |
113 | % eval rbfs for grid
114 |
115 | [xgrid,ygrid]=meshgrid(-500:50:500,-500:50:500);
116 | xgridv=xgrid(:);
117 | ygridv=ygrid(:);
118 |
119 | clear r rbf
120 | dataindex=1;
121 | for i=1:size(xgridv,1)
122 |
123 | r=sqrt( (xgridv(i)-x_c).^2 + (ygridv(i)-y_c).^2 )';
124 | logr=log(r);
125 | logr(r==0)=0;
126 | % u part
127 | rbf(dataindex,:) = [ 1,0,xgridv(i),ygridv(i),0 , [r.^2.*(12*logr+7) , zeros(size(r))] + [ -(8*logr+6) .* (xgridv(i)-x_c)' .* (xgridv(i)-x_c)' , -(8*logr+6) .* (xgridv(i)-x_c)' .* (ygridv(i)-y_c)' ] ] ;
128 | %v part
129 | rbf(dataindex+1,:)= [0,1,-ygridv(i),0,xgridv(i) , [zeros(size(r)), r.^2.*(12*logr+7)] + [ -(8*logr+6) .* (ygridv(i)-y_c)' .* (xgridv(i)-x_c)' , -(8*logr+6) .* (ygridv(i)-y_c)' .* (ygridv(i)-y_c)' ] ] ;
130 | dataindex=dataindex+2 ;
131 | end
132 |
133 | estimate=params*rbf';%apply weights
134 | estimate=reshape(estimate,[2,size(xgridv,1)]);
135 | ugrid=reshape( estimate(1,:) , size(xgrid) );
136 | vgrid=reshape( estimate(2,:) , size(xgrid) );
137 |
138 | % a=[1,1,1;2,2,2]
139 | % a=a(:)
140 | % reshape(a,[2,3])
141 |
142 | figure(2)
143 | clf
144 | hold on
145 | % quiver(x,y,u,v,'k')
146 | quiver(x_obs,y_obs,u_obs,v_obs,'r')
147 | plot(x_c,y_c,'or')
148 | quiver(xgrid,ygrid,ugrid,vgrid,'k')
149 |
150 | figure(3)
151 | clf
152 | div=divergence(ugrid,vgrid);
153 | surf(div)
154 |
155 |
--------------------------------------------------------------------------------
/ladcp_map_sections_3d_2014_with_vmadcp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/ladcp_map_sections_3d_2014_with_vmadcp.png
--------------------------------------------------------------------------------
/objective_mapping_all_adcp_data_julaugsep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/objective_mapping_all_adcp_data_julaugsep.png
--------------------------------------------------------------------------------
/objmap_function_files.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/objmap_function_files.zip
--------------------------------------------------------------------------------
/si_arctic_df_rbfs_utm_and_coastal6.m:
--------------------------------------------------------------------------------
1 |
2 | clear all
3 | addpath(genpath('C:\Users\a5278\Documents\MATLAB\matlab_functions'))
4 |
5 |
6 | %svalbard
7 | % latlim = [78 81.5];
8 | % lonlim = [0 25];
9 |
10 | %yermak
11 | latlim = [79.5 81];
12 | lonlim = [5 13];
13 |
14 | %hinlopen
15 | % latlim = [79.5 81.2];
16 | % lonlim = [12 20];
17 |
18 | ibcaofile='C:\Users\a5278\Documents\MATLAB\matlab_functions\ibcao\IBCAO_V3_30arcsec_SM.grd';
19 |
20 | in=ncinfo(ibcaofile);
21 |
22 | x=ncread(ibcaofile,'x');
23 | y=ncread(ibcaofile,'y');
24 | [ibcao.lon,ibcao.lat]=meshgrid(x,y);
25 | ilat=ibcao.lat';
26 | ilon=ibcao.lon';
27 | idepth=ncread(ibcaofile,'z');
28 |
29 | [ibcao.lon,ibcao.lat]=meshgrid(x(x>lonlim(1)&xlatlim(1)&ylonlim(1)&ilonlatlim(1)&ilat0.3 & adcp.lat>latlim(1) & adcp.latlonlim(1) & adcp.lon100);
119 | dvdatamonth=datevec(datamonth);
120 |
121 |
122 |
123 | for itime=1:numel(datamonth)
124 | % the observations
125 | %ix=adcp.dist>0.5 & dv(:,2)>6 & dv(:,2)<10 & ~isnan(adcp.u_mean)' & adcp.lat>latlim(1) & adcp.latlonlim(1) & adcp.lon0.3 & dv(:,1)==dvdatamonth(itime,1) & dv(:,2)==dvdatamonth(itime,2) & ~isnan(adcp.u_mean)' & adcp.lat>latlim(1) & adcp.latlonlim(1) & adcp.lon100 & adcp.depth<200;
130 | a_u=nanmean(adcp.u_detide(ix_d,ix));
131 | a_v=nanmean(adcp.v_detide(ix_d,ix));
132 |
133 | ix_nan=isnan(a_u) | isnan(a_v);
134 |
135 | a_v(ix_nan)=[];
136 | a_u(ix_nan)=[];
137 | a_lat(ix_nan)=[];
138 | a_lon(ix_nan)=[];
139 |
140 | % a_v=[a_v(1:10:end)];
141 | % a_u=[a_u(1:10:end)];
142 | % a_lat=[a_lat(1:10:end)];
143 | % a_lon=[a_lon(1:10:end)];
144 |
145 | % [a_utm_x,a_utm_y,f]=ll2utm([a_lat,a_lon]);
146 |
147 |
148 | % the centers
149 | % n_centers=600;
150 | n_centers=round(numel(a_u)*.07 );
151 |
152 | ixr=round(linspace(1,numel(a_lat),n_centers)) ;
153 | c_lat=a_lat(ixr);
154 | c_lon=a_lon(ixr);
155 |
156 | % [idx,C] = kmeans([a_lon,a_lat],n_centers);
157 | % c_lat=C(:,2);
158 | % c_lon=C(:,1);
159 |
160 | for ic=1:numel(lat_coast)
161 | c_lat=[c_lat ; lat_coast{ic}(1:10:end)' ];
162 | c_lon=[c_lon ; lon_coast{ic}(1:10:end)' ];
163 | end
164 | % ixr=randi(numel(a_lat),[n_centers,1])
165 | % c_lat=a_lat(ixr);
166 | % c_lon=a_lon(ixr);
167 | % [x_c_utm,y_c_utm,f]=ll2utm([c_lat,c_lon]);
168 |
169 | % [c_lat,c_lon] = utm2ll(C(:,1),C(:,2),32);
170 | % the grid
171 | % latlim = [77.9 82.3];
172 | % lonlim = [2 25];
173 | [g_lat,g_lon]=meshgrid(latlim(1):.08:latlim(2),lonlim(1):.2:lonlim(2));
174 |
175 | x_c=c_lon;
176 | y_c=c_lat;
177 |
178 | %plot
179 |
180 | figure(1)
181 | clf
182 | hold on
183 |
184 | plot(a_lon,a_lat,'.k')
185 | plot(c_lon,c_lat,'or')
186 | plot(g_lon,g_lat,'.b')
187 |
188 | %%%% utm conversions
189 |
190 | z1 = utmzone( [mean(a_lat),mean(a_lon) ]);
191 | [ellipsoid,estr] = utmgeoid(z1);
192 | utmstruct = defaultm('utm');
193 | utmstruct.zone = '18T';
194 | utmstruct.geoid = ellipsoid;
195 | utmstruct = defaultm(utmstruct);
196 |
197 | [x_utm_a,y_utm_a] = mfwdtran(utmstruct,a_lat,a_lon);
198 | [x_c_utm,y_c_utm] = mfwdtran(utmstruct,c_lat,c_lon);
199 |
200 | % x_c_utm=[x_c_utm ; x_utm_coast{1}(1:10:end)' ; x_utm_coast{2}(1:10:end)' ]
201 | % y_c_utm=[y_c_utm ; y_utm_coast{1}(1:10:end)' ; y_utm_coast{2}(1:10:end)' ]
202 |
203 | figure(1)
204 | clf
205 | hold on
206 |
207 | plot(x_utm_a,y_utm_a,'.k')
208 | plot(x_c_utm,y_c_utm,'or')
209 | for i=1:numel(lat_coast)
210 | plot(x_utm_coast{i},y_utm_coast{i},'.-');
211 |
212 | end
213 | %% train RBFs with observations UTM
214 | %
215 | % a=[1,1,1;2,2,2]
216 | % a=a(:)
217 | % reshape(a,[2,3])
218 |
219 | data=[a_v;a_u];
220 | data_adcp=data(:);
221 | x_obs=x_utm_a;
222 | y_obs=y_utm_a;
223 |
224 | % determine radiuses/differences
225 | clear r rbf_adcp
226 |
227 | dataindex=1;
228 | for i=1:numel(x_obs)
229 |
230 | %distance to centers
231 | % r=sqrt( (x_obs(i)-x_c).^2 + (y_obs(i)-y_c).^2 )';
232 | r=deg2km(distance(a_lat(i),a_lon(i),c_lat,c_lon))'.*1000;
233 | logr=log(r);
234 | logr(r==0)=0;
235 |
236 | % u part
237 | rbf_adcp(dataindex,:) = [ 1,0,x_obs(i),y_obs(i),0 , [r.^2.*(12*logr+7) , zeros(size(r))] + [ -(8*logr+6) .* (x_obs(i)-x_c_utm)' .* (x_obs(i)-x_c_utm)' , -(8*logr+6) .* (x_obs(i)-x_c_utm)' .* (y_obs(i)-y_c_utm)' ] ] ;
238 | %v part
239 | rbf_adcp(dataindex+1,:)= [0,1,-y_obs(i),0,x_obs(i) , [zeros(size(r)), r.^2.*(12*logr+7)] + [ -(8*logr+6) .* (y_obs(i)-y_c_utm)' .* (x_obs(i)-x_c_utm)' , -(8*logr+6) .* (y_obs(i)-y_c_utm)' .* (y_obs(i)-y_c_utm)' ] ] ;
240 | dataindex=dataindex+2;
241 | end
242 |
243 | %% costal segments
244 |
245 | coastcounter=1;
246 | clear rbf_coast
247 |
248 | for icoast=1:numel(x_utm_coast)
249 |
250 | r2=deg2km(distance( lat_coast{icoast}(1) , lon_coast{icoast}(1) ,c_lat,c_lon))'.*1000;
251 | logr2=log(r2);
252 | logr2(r2==0)=0;
253 |
254 | for i=2:numel(lat_coast{icoast})
255 |
256 | %distance to centers
257 | r1= deg2km(distance( lat_coast{icoast}(i) , lon_coast{icoast}(i) ,c_lat,c_lon))'.*1000; ;
258 | logr1=log(r1);
259 | logr1(r1==0)=0;
260 |
261 | alphapart= [ y_utm_coast{icoast}(i)-y_utm_coast{icoast}(1) , -x_utm_coast{icoast}(i)+x_utm_coast{icoast}(1) , x_utm_coast{icoast}(i)*y_utm_coast{icoast}(i)- x_utm_coast{icoast}(1)*y_utm_coast{icoast}(1) , .5*y_utm_coast{icoast}(i).^2-.5*y_utm_coast{icoast}(1).^2 , -.5*x_utm_coast{icoast}(i).^2+.5*x_utm_coast{icoast}(1).^2 ] ;
262 |
263 | % centerpart=[ r1.^2.*(1+4*logr1) .* (x_utm_coast{icoast}(i)-x_c)' - r2.^2.*(1+4*logr2) .* (x_utm_coast{icoast}(1)-x_c)' , -( r1.^2.*(1+4*logr1) .* (y_utm_coast{icoast}(i)-y_c)' - r2.^2.*(1+4*logr2) .* (y_utm_coast{icoast}(1)-y_c)' ) ];
264 | centerpart=[ r1.^2.*(1+4*logr1) .* (y_utm_coast{icoast}(i)-y_c_utm)' - r2.^2.*(1+4*logr2) .* (y_utm_coast{icoast}(1)-y_c_utm)' , - ( r1.^2.*(1+4*logr1) .* (x_utm_coast{icoast}(i)-x_c_utm)' - r2.^2.*(1+4*logr2) .* (x_utm_coast{icoast}(1)-x_c_utm)' ) ];
265 |
266 | rbf_coast(coastcounter,:) = [alphapart,centerpart];
267 | coastcounter=coastcounter+1;
268 | end
269 | end
270 |
271 | data_coast=zeros(coastcounter-1,1)
272 |
273 | %% ectra constraint
274 |
275 | n_params=size(rbf_adcp,2);
276 | dataindex=1;
277 | clear a b rbf_side
278 | a=zeros([1,n_params]);
279 | b=zeros([1,n_params]);
280 | for i=1:numel(x_c_utm)
281 | a(5+dataindex)=sum( [1,0,x_c_utm(i),y_c_utm(i),0] );
282 | b(5+dataindex+1)=sum( [0,1,-y_c_utm(i),0,x_c_utm(i)] );
283 | dataindex=dataindex+2;
284 | end
285 | rbf_side(1,:) = a ;
286 | rbf_side(2,:) = b ;
287 |
288 | data_side=[0;0];
289 |
290 | %%
291 | % params= [data_adcp',data_coast' ]/ [ rbf_adcp',rbf_coast'] ;%use mrdivide to solve system of equations. For large systems it may
292 |
293 | params= [data_adcp',data_coast',data_side' ]/ [ rbf_adcp',rbf_coast',rbf_side'] ;%use mrdivide to solve system of equations. For large systems it may
294 |
295 | % params2 = linsolve(rbf,data);
296 |
297 | % sum(params1==params1)/numel(params1)
298 |
299 | %% evaluate rbfs
300 |
301 |
302 | % eval rbfs for grid
303 |
304 | % latlim = [77.9 82.3];
305 | % lonlim = [2 25];
306 | [g_lat,g_lon]=meshgrid(latlim(1):.04:latlim(2),lonlim(1):.15:lonlim(2));
307 | % [g_lat,g_lon]=meshgrid(latlim(1):.06:latlim(2),lonlim(1):.3:lonlim(2));
308 | latgridv=g_lat(:);
309 | longridv=g_lon(:);
310 | % xgridv=g_lon(:);
311 | % ygridv=g_lat(:);
312 |
313 | [xgridv,ygridv] = mfwdtran(utmstruct,latgridv,longridv);
314 |
315 | clear r rbf dist2centers
316 | dataindex=1;
317 | for i=1:size(xgridv,1)
318 |
319 | % r=sqrt( (xgridv(i)-x_c).^2 + (ygridv(i)-y_c).^2 )';
320 | r=deg2km(distance(latgridv(i),longridv(i),c_lat,c_lon))'.*1000;
321 |
322 | dist2centers(i,:)=r;
323 | logr=log(r);
324 | logr(r==0)=0;
325 | % u part
326 | rbf(dataindex,:) = [ 1,0,xgridv(i),ygridv(i),0 , [r.^2.*(12*logr+7) , zeros(size(r))] + [ -(8*logr+6) .* (xgridv(i)-x_c_utm)' .* (xgridv(i)-x_c_utm)' , -(8*logr+6) .* (xgridv(i)-x_c_utm)' .* (ygridv(i)-y_c_utm)' ] ] ;
327 | %v part
328 | rbf(dataindex+1,:)= [0,1,-ygridv(i),0,xgridv(i) , [zeros(size(r)), r.^2.*(12*logr+7)] + [ -(8*logr+6) .* (ygridv(i)-y_c_utm)' .* (xgridv(i)-x_c_utm)' , -(8*logr+6) .* (ygridv(i)-y_c_utm)' .* (ygridv(i)-y_c_utm)' ] ] ;
329 | dataindex=dataindex+2 ;
330 | end
331 |
332 | estimate=params*rbf';%apply weights
333 | estimate=reshape(estimate,[2,size(xgridv,1)]);
334 |
335 | %%
336 |
337 | ugrid=reshape( estimate(2,:) , size(g_lat) );
338 | vgrid=reshape( estimate(1,:) , size(g_lat) );
339 | dgrid=reshape( sum( dist2centers(:,1:n_centers)<10000 ,2) , size(g_lat) );
340 | ixclose=dgrid>0;
341 | %
342 | % figure(9)
343 | % clf
344 | % dgrid=reshape( sum(dist2centers<20000 ,2) , size(g_lat) );
345 | % imagesc(dgrid)
346 | % colorbar
347 |
348 | m_ugrid(itime,:,:)=ugrid;
349 | m_vgrid(itime,:,:)=vgrid;
350 | m_ixclose(itime,:,:)=ixclose;
351 |
352 |
353 | % end
354 | %
355 | % figure(2)
356 | % clf
357 | % hold on
358 | % % quiver(x,y,u,v,'k')
359 | % % quiver(x_obs,y_obs,u_obs,v_obs,'r')
360 | % % plot(x_c,y_c,'or')
361 | % quiver(xgridv,ygridv,ugrid(:),vgrid(:),'k')
362 | %
363 | % figure(3)
364 | % clf
365 | % hold on
366 | % div=-divergence(vgrid,ugrid);
367 | % pcolor(g_lon,g_lat,div)
368 | % shading flat
369 | % colormap(cmocean('balance'))
370 | % plot(c_lon,c_lat,'or')
371 | % for i=1:numel(lat_coast)
372 | % plot(lon_coast{i},lat_coast{i},'.-');
373 | % end
374 | % colorbar
375 |
376 |
377 | %%
378 |
379 | % for itime=1:numel(datamonth)
380 |
381 | %
382 | % ugrid=squeeze( m_ugrid(itime,:,:));
383 | % vgrid=squeeze( m_vgrid(itime,:,:));
384 | % ixclose=squeeze( m_ixclose(itime,:,:) );
385 |
386 | figure(4)
387 | clf
388 | hold on
389 | set(gcf,'color',[1 1 1])
390 |
391 |
392 | m_proj('lambert','long',lonlim,'lat',latlim);
393 | m_grid('xlabeldir','end','fontsize',10);
394 |
395 | % m_pcolor(g_lon,g_lat,div)
396 | % shading flat
397 | % colormap(cmocean('balance'))
398 | set(gca,'clim',[-0.2 .2])
399 |
400 | m_gshhs_h('patch',[.8 .8 .8]);
401 |
402 | [C,h]=m_contour(ibcao.lon,ibcao.lat,ibcao.depth,[-4000,-3000,-2000,-1000,-800,-600,-400,-200],'color',[.5 .5 .5]);
403 | clabel(C,h,'color',[.5 .5 .5]);
404 |
405 | bottomdepth = ltln2val(Z, refvec, g_lat,g_lon);
406 | ui=ugrid;
407 | vi=vgrid;
408 |
409 |
410 |
411 | c=sqrt(ui.^2+vi.^2);
412 | ix= bottomdepth<0 & c<1 & ixclose==1 ;
413 |
414 |
415 | vecs = m_vec(1, g_lon(ix),g_lat(ix),ui(ix),vi(ix),'k', 'shaftwidth', .7, 'headangle', 30, 'edgeclip', 'on');
416 | vecs = m_vec(1, a_lon(1:5:end),a_lat(1:5:end),a_u(1:5:end),a_v(1:5:end),'r','shaftwidth', .7, 'headangle', 30, 'edgeclip', 'on');
417 |
418 | uistack(vecs);
419 | % cb=colorbar('north')
420 | % xlabel(cb,'Interpolated current speed in m s^{-1}')
421 |
422 | % colormap(gca,cmocean('thermal'))
423 |
424 | m_text(16,79.8,'0.1 m s^{-1}')
425 | vecs = m_vec(1, 16,79.78,.1,0,'shaftwidth', 0.7, 'headangle', 30, 'edgeclip', 'on');
426 | uistack(vecs);
427 | vecs = m_vec(1, 16,79.79,.4,0,'shaftwidth', 0.7, 'headangle', 30, 'edgeclip', 'on');
428 | uistack(vecs);
429 | m_text(23,79.4,'0.4 m s^{-1}')
430 | title(datestr(datamonth(itime),'yyyy-mm'))
431 |
432 | set(gcf,'PaperPositionMode','auto')
433 | print(gcf,'-dpng',[datestr(datamonth(itime),'yyyy-mm')],'-r300')
434 |
435 | end
--------------------------------------------------------------------------------
/sta032_ladcp.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/sta032_ladcp.PNG
--------------------------------------------------------------------------------
/variogram_results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/variogram_results.png
--------------------------------------------------------------------------------
/vmdas.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianmenze/Processing-and-analysis-of-large-ADCP-datasets/c2c96badf80fc5b99e002ee2556f00b16413f842/vmdas.PNG
--------------------------------------------------------------------------------