├── 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 | ![Here is a visualization of VM-ADCP and L-ADCP current profiles](ladcp_map_sections_3d_2014_with_vmadcp.png) 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 | ![](sta032_ladcp.PNG) 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 | ![](variogram_results.png) 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 | ![Here is a visualization of VM-ADCP and L-ADCP durrent profiles](ladcp_map_sections_3d_2014_with_vmadcp.png) 7 | 8 | ![](animation_small.gif) 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 --------------------------------------------------------------------------------