├── .gitignore ├── LICENSE ├── alti_read ├── read_aviso_mss.py ├── readhy2b.py └── readsa3.py ├── pylake.png ├── readme.md ├── ssh.png ├── waveform.png └── wls.png /.gitignore: -------------------------------------------------------------------------------- 1 | # python ignre 2 | .idea/ 3 | *.gz 4 | alti_read/*.txt 5 | alti_read/*.npy 6 | alti_read/*.kml 7 | *.dat 8 | data/ 9 | ex_data/ 10 | 11 | read2.txt 12 | testsave.py 13 | readhy2b_copy.py 14 | readsa3_copy.py 15 | testsave_copy.py -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2018, First Institute of Oceanography, SOA. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | 3. Neither the name of the First Institute of Oceanography, SOA, may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE First Institute of Oceanography, SOA BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | 11 | -------------------------------------------------------------------------------- /alti_read/read_aviso_mss.py: -------------------------------------------------------------------------------- 1 | from netCDF4 import Dataset 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | # ---------------Introduction----------------------------- 6 | # This is a simple program to read and process the AVISO monthly MSS data. 7 | # First, you should download some data from AVISO FTP site. Then run this program and get the similar result. 8 | # leiyang@fio.org.cn 9 | # 2020-07 10 | # -------------------------------------------------------- 11 | 12 | 13 | # Get the user home directory 14 | from os.path import expanduser 15 | import os 16 | 17 | home = expanduser("~") 18 | 19 | # set directory containing AVISO SLA data. You should change this to your data location. 20 | dir_setup = os.path.join(home, 'alti_data', 'avisoMMS') 21 | files = sorted(os.listdir(dir_setup)) # sort the file name list 22 | 23 | 24 | # define function 25 | def read_aviso_mss(filelist, lon_min, lon_max, lat_min, lat_max): 26 | msla = [] 27 | tims = [] 28 | 29 | for filename in filelist[0:]: # Try to select a small set of data and test it (like one year [0:12]). 30 | # print(filename) 31 | # ------ Here we choose the enhanced data because it contains the waveform data. 32 | file_path = os.path.join(dir_setup, filename) 33 | print("The Aviso MSS grid file is:") 34 | print(file_path) 35 | 36 | # -----------------------# 37 | # Open nc file using NetCDF tools 38 | # -----------------------# 39 | ncs3 = Dataset(file_path) 40 | 41 | # print(ncs3.variables.keys()) # keys 是字典数据类型的元素名称,对应这里就是经纬度时间等参数名字 42 | 43 | lat = ncs3.variables['lat'][:] 44 | lon = ncs3.variables['lon'][:] 45 | tim = ncs3.variables['time'][:] 46 | asla = ncs3.variables['sla'][:] # 注意asla表示海面高度异常,是一个三维数组。时间、经、纬度 47 | 48 | # print("data dimention") 49 | # print(np.shape(lon)) 50 | # print(np.shape(lat)) 51 | # print(np.shape(tim)) 52 | # print(np.shape(asla)) # 数据是二维的 53 | # print('time is:', tim) 54 | # print(asla[0, 0:10, 0:10]) 55 | # print(lat[0:10]) 56 | 57 | # -----------------------# 58 | # select data in the south china sea at about 5-20 110-120. You can change the boundary as you need. 59 | # Here we can change the selection from 'if' to 'slice' later to get faster. Need to fix. 60 | # The resolution is 15 minute at latitude and longitude direction. 61 | lat_min_ind = (lat_min + 90) * 4 62 | lat_max_ind = (lat_max + 90) * 4 63 | lon_min_ind = lon_min * 4 64 | lon_max_ind = lon_max * 4 65 | tmp = asla[0, lat_min_ind:lat_max_ind, lon_min_ind:lon_max_ind] 66 | 67 | # print(tmp) 68 | # -----------------------# 69 | # This is a original method to select data. low speed. 70 | 71 | # tmp = [] 72 | # for i in range(720): # 720 this is the resolution along latitude and 1440 is longitude. 73 | # for j in range(1440): 74 | # if lat[i] > 15 and lat[i] < 20: 75 | # if lon[j]>115 and lon[j]<120: 76 | # if isinstance(asla[0, i, j], float): 77 | # tmp2 = asla[0, i, j] 78 | # tmp.append(tmp2) 79 | # -----------------------# 80 | 81 | # print(len(tmp)) 82 | tmp3 = np.mean(tmp) 83 | msla.append(tmp3) 84 | tims.append(tim) 85 | print('\n') 86 | # # plot the time series of sea surface level over south china sea 87 | # plt.plot(tims, msla) 88 | # plt.show() 89 | return [tims, msla] 90 | 91 | 92 | # call function 93 | 94 | lat_min = 0 # set the extent 95 | lat_max = 20 96 | lon_min = 110 97 | lon_max = 120 98 | # call read_aviso_mss 99 | out = read_aviso_mss(files, lon_min, lon_max, lat_min, lat_max) # the out format is 'list' 100 | # print(out[0]) 101 | 102 | # plot the time series of sea surface level over south china sea 103 | plt.plot(out[0], out[1]) 104 | plt.show() 105 | 106 | -------------------------------------------------------------------------------- /alti_read/readhy2b.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding=utf-8 3 | 4 | from netCDF4 import Dataset 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | import matplotlib.gridspec as gridspec 8 | import netCDF4 as ncf 9 | # import pandas as pd 10 | import sys 11 | import pickle 12 | from os.path import expanduser 13 | import os 14 | import subprocess 15 | import operator 16 | from functools import reduce 17 | 18 | 19 | # -- Get the user home directory 20 | 21 | home = expanduser("~") 22 | # ------ Directory contains sentinel3A SRAL data 23 | dir_setup = os.path.join(home, '/home/yl/Documents/download/testdata/H2B_OPER_SDR_2PT_0018_0181_20190701T084456_20190701T093033') 24 | # ------ Name of the SRAL file. There have three kinds of S3A data which are the enhanced,standard and the reduced data. 25 | # ------ Here we choose the enhanced data because it contains the waveform data. 26 | file_path = os.path.join(dir_setup, 'H2B_OPER_SDR_2PT_0018_0181_20190701T084456_20190701T093033.nc') 27 | print("The HY2B ALt file is:") 28 | print(file_path) 29 | print('\n') 30 | 31 | # -----------------------# 32 | # Open nc file using NetCDF tools 33 | # -----------------------# 34 | ncs3 = Dataset(file_path) 35 | 36 | print(ncs3.variables.keys()) #keys 是字典数据类型的元素名称,对应这里就是经纬度时间等参数名字 37 | # print(ncs3.variables) 38 | s3ak = ncs3.variables.keys() 39 | print(type(s3ak)) # 注意数据类型 40 | print(len(s3ak)) # 数据的维度? 41 | s3ak2 = str(s3ak) 42 | print(type(s3ak2)) 43 | print(len(s3ak2)) # 字符串的长度 44 | 45 | # save variable names 46 | fh = open("hy2b_sdr.txt", "w") 47 | for i in s3ak: 48 | fh.write(str(i)+'\n') 49 | fh.close() 50 | 51 | # -----------------------# 52 | # 测高数据的赋值 53 | # -----------------------# 54 | lat = ncs3.variables['lat_20hz'][:] 55 | lon = ncs3.variables['lon_20hz'][:] 56 | tim = ncs3.variables['time_20hz'][:] 57 | alt = ncs3.variables['alt_20hz'][:] 58 | r_ku = ncs3.variables['range_20hz_ku'][:] 59 | 60 | lat1 = ncs3.variables['lat'][:] 61 | lon1 = ncs3.variables['lon'][:] 62 | tim1 = ncs3.variables['time'][:] 63 | alt1 = ncs3.variables['alt'][:] 64 | r_ku1 = ncs3.variables['range_ku'][:] 65 | r_c1 = ncs3.variables['range_c'][:] 66 | 67 | dry = ncs3.variables['model_dry_tropo_corr'][:] 68 | wet = ncs3.variables['rad_wet_tropo_corr'][:] 69 | wet_m = ncs3.variables['model_wet_tropo_corr'][:] 70 | 71 | ino = ncs3.variables['iono_corr_alt_ku'][:] 72 | ssb = ncs3.variables['sea_state_bias_ku'][:] 73 | sig_ku = ncs3.variables['sig0_ku'][:] 74 | inv = ncs3.variables['inv_bar_corr'][:] 75 | hff = ncs3.variables['hf_fluctuations_corr'][:] 76 | ots = ncs3.variables['ocean_tide_sol1'][:] 77 | sot = ncs3.variables['solid_earth_tide'][:] 78 | pot = ncs3.variables['pole_tide'][:] 79 | 80 | 81 | wav = ncs3.variables['waveforms_20hz_ku'][:] 82 | 83 | # vlz = nc.variables['z'][:] 84 | # 85 | print("data dimention") 86 | print(np.shape(lon1)) # 数据是二维的,(1953, 20),20 means 20hz 87 | print(np.shape(lat1)) 88 | print(np.shape(tim)) 89 | print(np.shape(alt)) 90 | print(np.shape(wav)) # 数据是二维的,(1953, 2560) 2560=128*20 91 | 92 | # print(wav[1, 0:128]) 93 | 94 | # -------------------------- 95 | # 查看数据的类型,注意python和MATLAB的差异 96 | print(type(wav)) #查看数据类型 97 | print(type(tim)) 98 | print(type(lat1)) 99 | print(r_ku1) 100 | # print(wav[1, :]) #注意大括号和小括号的使用。 101 | # -------------------------- 102 | 103 | # -------------------------- 104 | # Plot wavform 105 | 106 | num = len(lon1) # define the length and step, used in for loop, num=1953 107 | print("num", num) 108 | ste = -int(num/16) 109 | print("ste", ste) 110 | 111 | myslice = slice(num-1, 0, ste) # 采用切片的形式,均分整个数据集 112 | x = np.arange(1, 129, 1) 113 | y = np.array(wav[myslice, :]) 114 | 115 | lat2 = np.array(lat[myslice]) 116 | 117 | 118 | # print(y[1, 0:128]) # 需要了解数据的结构,HY-2B的数据格式和Sentinel 3A B 不一样,20Hz的数据做成了二维数组。波形则是【num,20*128】 119 | 120 | # Plot waveforms on one figure 121 | # for i in range(1, 10): 122 | # plt.plot(x, y[i, 0:128], 'r') 123 | # plt.show() 124 | 125 | # Plot waveforms on sub figures 126 | figsize = (10, 8) 127 | gs = gridspec.GridSpec(4, 4) 128 | # print(type(gs)) 129 | gs.update(hspace=0.4) 130 | fig1 = plt.figure(num=2, figsize=figsize) 131 | ax = [] 132 | 133 | for i in range(16): 134 | row = (i // 4) 135 | # print(i, row) 136 | col = i % 4 137 | # print(i, col) 138 | ax.append(fig1.add_subplot(gs[row, col])) 139 | ax[-1].set_title('lat=%s' % str(round(lat2[i, 0], 4))) 140 | # 2B的数据格式使然,[i, 0]表示第i个点(按照1hz的统计点数)里面的第一个波形(共有20个波形) 141 | ax[-1].plot(x, y[i, 0:128], 'ro', ms=2, ls='-', linewidth=0.5) 142 | # y表示波形,x表示横坐标轴,128个数据 143 | # plt.show() 144 | 145 | # =================================== 146 | 147 | # plot the waveform over selected area 148 | # First reshape the two-D array to one-D, the same with the Sentinel-3A B 149 | 150 | lat = np.ma.getdata(lat).reshape((num*20,)) 151 | lon = np.ma.getdata(lon).reshape((num*20,)) 152 | tim = np.ma.getdata(tim).reshape((num*20,)) 153 | alt = np.ma.getdata(alt).reshape((num*20,)) 154 | r_ku = np.ma.getdata(r_ku).reshape((num*20,)) 155 | wav = np.ma.getdata(wav).reshape((num*20, 128)) 156 | 157 | print("=================test for and if") 158 | num = 0 # count the number of the waveforms over the selected area 159 | sel = [] # save the index of selected area 160 | for i in range(len(lat.tolist())): 161 | # print(i) 162 | if lat[i] > 37.3 and lat[i] < 37.6: 163 | # print(lat[i], wav[i, :]) 164 | num = num + 1 165 | sel.append(i) 166 | print(num) 167 | print(len(sel)) 168 | 169 | 170 | myslice = slice(sel[num-1], 0, -10) # 采用切片的形式,均分整个数据集 171 | x = np.arange(1, 129, 1) 172 | y = np.array(wav[myslice, :]) 173 | lat2 = np.array(lat[myslice]) 174 | lon2 = np.array(lon[myslice]) 175 | print(lon2, lat2) 176 | 177 | with open('cst.npy', 'w') as fileobj: # save points over the CST 178 | fileobj.write('lon lat \n') 179 | 180 | for i in range(len(lat2.tolist())): 181 | fileobj.write(str('%15.5f' % lon2.tolist()[i])+' ') 182 | fileobj.write(str('%15.5f' % lat2.tolist()[i]) + ' \n ') 183 | 184 | subprocess.call(["awk '!/2147483647.00000/ && NR>1 {print $0}' cst.npy > cst2.npy"], shell=True) 185 | 186 | # Plot waveforms on sub figures 187 | figsize = (10, 8) 188 | gs = gridspec.GridSpec(4, 4) 189 | # print(type(gs)) 190 | gs.update(hspace=0.4) 191 | fig1 = plt.figure(num=3, figsize=figsize) 192 | ax = [] 193 | 194 | num = 0 # count the number of the waveforms over the selected area 195 | sel = [] # save the index of selected area 196 | with open('cst3.npy', 'w') as fileobj: # save points over the CST 197 | fileobj.write('lon lat \n') 198 | 199 | for i in range(16): 200 | row = (i // 4) 201 | # print(i, row) 202 | col = i % 4 203 | # print(i, col) 204 | ax.append(fig1.add_subplot(gs[row, col])) 205 | ax[-1].set_title('lat=%s' % str(round(lat2[i], 4))) 206 | # 2B的数据格式使然,[i, 0]表示第i个点(按照1hz的统计点数)里面的第一个波形(共有20个波形) 207 | ax[-1].plot(x, y[i, 0:128], 'ro', ms=2, ls='-', linewidth=0.5) 208 | # y表示波形,x表示横坐标轴,128个数据 209 | num = num + 1 210 | sel.append(i) 211 | fileobj.write(str('%15.5f' % lon2.tolist()[i]) + ' ') 212 | fileobj.write(str('%15.5f' % lat2.tolist()[i]) + ' \n ') 213 | 214 | plt.show() 215 | 216 | subprocess.call(["awk '!/2147483647.00000/ && NR>1 {print $0}' cst3.npy > cst4.npy"], shell=True) 217 | print(num) 218 | print(sel) 219 | 220 | print("=================test for and if") 221 | 222 | # =================================== 223 | # =================================== 224 | # write 1hz data to file 225 | 226 | # fill masked data with other data, such as -999999 227 | # r_ku1 = np.ma.filled(r_ku1, [-999999]) 228 | # ino = np.ma.filled(ino, [-999999]) 229 | # ots = np.ma.filled(ots, [-999999]) 230 | # hff = np.ma.filled(hff, [-999999]) 231 | # ssb = np.ma.filled(ssb, [-999999]) 232 | # sig_ku = np.ma.filled(sig_ku, [-999999]) 233 | 234 | # the masked value is 2147483647 235 | 236 | r_ku1 = np.ma.getdata(r_ku1) 237 | ino = np.ma.getdata(ino) 238 | ots = np.ma.getdata(ots) 239 | hff = np.ma.getdata(hff) 240 | ssb = np.ma.getdata(ssb) 241 | sig_ku = np.ma.getdata(sig_ku) 242 | 243 | print(type(r_ku1)) 244 | 245 | # save data including the masked data, which is set to -999999 246 | with open('tt.npy', 'w') as fileobj: 247 | fileobj.write('lat lon tim \n') 248 | 249 | for i in range(len(lat1.tolist())): 250 | fileobj.write(str('%15.5f' % lat1.tolist()[i])+' ') 251 | fileobj.write(str('%15.5f' % lon1.tolist()[i]) + ' ') 252 | fileobj.write(str('%15.5f' % tim1.tolist()[i]) + ' ') 253 | fileobj.write(str('%15.5f' % alt1.tolist()[i]) + ' ') 254 | fileobj.write(str('%15.5f' % r_ku1.tolist()[i]) + ' ') 255 | fileobj.write(str('%15.5f' % wet_m.tolist()[i]) + ' ') 256 | fileobj.write(str('%15.5f' % dry.tolist()[i]) + ' ') 257 | fileobj.write(str('%15.5f' % ino.tolist()[i]) + ' ') 258 | fileobj.write(str('%15.5f' % ots.tolist()[i]) + ' ') 259 | fileobj.write(str('%15.5f' % pot.tolist()[i]) + ' ') 260 | fileobj.write(str('%15.5f' % inv.tolist()[i]) + ' ') 261 | fileobj.write(str('%15.5f' % hff.tolist()[i]) + ' ') 262 | fileobj.write(str('%15.5f' % ssb.tolist()[i]) + ' ') 263 | fileobj.write(str('%15.5f' % sig_ku.tolist()[i]) + '\n ') 264 | 265 | # =================================== 266 | # save data excluding the masked data 267 | print("===================== test mask") 268 | subprocess.call(["awk '!/2147483647.00000/ && $8!=32767 && $13!=32767 && NR>1{print $0}' tt.npy >tt2.dat"], shell=True) 269 | subprocess.call(["awk '{print $2,$1,$4-$5-($6+$7+$8+$9+$10+$11+$13)}' tt2.dat >result.dat"], shell=True) 270 | subprocess.call(["sed -i '$d' result.dat"], shell=True) 271 | 272 | # 调用系统命令awk提取有效数据 273 | # the bad value of 32767 is still exist. 274 | # the hff data are not valid 275 | # =================================== 276 | 277 | # =================================== 278 | 279 | # print(np.shape(lat)) 280 | 281 | # write 20hz data to file 282 | 283 | # with open('tt20.npy', 'w') as fileobj: 284 | # fileobj.write('lat20 lon20 tim20 \n') 285 | # 286 | # for i in range(len(lat.tolist())): 287 | # fileobj.write(str('%15.5f' % lat.tolist()[i])+' \n ') 288 | # fileobj.write(str('%15.5f' % lon.tolist()[i]) + ' ') 289 | # fileobj.write(str('%15.5f' % tim.tolist()[i]) + ' ') 290 | # fileobj.write(str('%15.5f' % alt.tolist()[i]) + ' ') 291 | # fileobj.write(str('%15.5f' % r_ku.tolist()[i]) + ' ') 292 | 293 | -------------------------------------------------------------------------------- /alti_read/readsa3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding=utf-8 3 | 4 | # Main functions: 5 | # -Read Sentinel-3 A/B altimeter GDR data 6 | # -Calculate the 20Hz water level over lakes and wide rivers 7 | # -Plot waveforms of the altimeter. From the waveforms, the surface could be determined, such as sea ice, calm water, ocean. 8 | # 9 | 10 | from netCDF4 import Dataset 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | import matplotlib.gridspec as gridspec 14 | import netCDF4 as ncf 15 | # import pandas as pd 16 | import sys 17 | import pickle 18 | 19 | ## -- Get the user home directory 20 | from os.path import expanduser 21 | import os 22 | 23 | 24 | # ------ Directory contains sentinel3A SRAL data 25 | path0 = r"D:\s3a_land" 26 | dir_name = os.listdir(path0) 27 | # print(dir_name) 28 | s3ak = [] # parameter names 29 | 30 | # --------------------------------------------------------------------------------------------------------------------- 31 | # Define input parameters 32 | # define the pass number: 152 Poyang, 260 Poyang(2) 33 | pass_num = 260 # 152,260 for S3A; 317 For S3B 34 | s_model = "LAN" # define the data mode: `LAN` (land) or `MAR` (marine) 35 | plot_wave = "no" # Plot wave form. `yes` or `no` 36 | site = "py_lake" # choose the site. `jiujiang`| `py_lake` 37 | output_name = "no" # If output the names of the variables. 38 | # define the latitude boundary 39 | if pass_num == 152: 40 | lat_min = 29. 41 | lat_max = 30 42 | lat_out_min = 29.0833 43 | lat_out_max = 29.2 44 | plot_cycle = 60 # choose the cycle to plot 45 | outfile = "wsl_152.npy" 46 | file_out = os.path.join('..', 'data', 'wsl_152.npy') 47 | if os.path.exists(file_out): # 如果文件存在 48 | # 删除文件,可使用以下两种方法。 49 | os.remove(file_out) 50 | # os.unlink(path) 51 | else: 52 | print('no such file:%s' % file_out) # 则返回文件不存在 53 | elif pass_num == 260: 54 | if site == "py_lake": 55 | lat_min = 29 56 | lat_max = 30.5 57 | lat_out_min = 29.358 58 | lat_out_max = 29.3727 59 | plot_cycle = 60 # choose the cycle to plot 60 | outfile = "wsl_260.npy" 61 | file_out2 = os.path.join('..', 'data', 'wsl_260.npy') 62 | if os.path.exists(file_out2): # 如果文件存在 63 | # 删除文件,可使用以下两种方法。 64 | os.remove(file_out2) 65 | # os.unlink(path) 66 | elif site == "jiujiang": 67 | lat_min = 29 68 | lat_max = 30.5 69 | lat_out_min = 29.8301 70 | lat_out_max = 29.8369 71 | plot_cycle = 60 # choose the cycle to plot 72 | outfile = "wsl_260jj.npy" 73 | file_out2 = os.path.join('..', 'data', 'wsl_260_jj.npy') 74 | if os.path.exists(file_out2): # 如果文件存在 75 | # 删除文件,可使用以下两种方法。 76 | os.remove(file_out2) 77 | # os.unlink(path) 78 | elif pass_num == 317: 79 | lat_min = 28.6 80 | lat_max = 29.3 81 | lat_out_min = 29.0 82 | lat_out_max = 29.0333 83 | plot_cycle = 40 # choose the cycle to plot 84 | outfile = "wsl_317.npy" 85 | file_out2 = os.path.join('..', 'data', 'wsl_317.npy') 86 | if os.path.exists(file_out2): # 如果文件存在 87 | # 删除文件,可使用以下两种方法。 88 | os.remove(file_out2) 89 | # os.unlink(path) 90 | else: 91 | print('no such file:%s' % file_out2) # 则返回文件不存在 92 | # --------------------------------------------------------------------------------------------------------------------- 93 | 94 | for file_s3a in dir_name[::-1]: 95 | # print(np.array(file_s3a[69:72])) 96 | # print("The baseline is %s"%(file_s3a[92:94])) 97 | # print(type(file_s3a)) 98 | if int(file_s3a[73:76]) == pass_num and file_s3a[9:12] == s_model and int(file_s3a[92:94]) > 2: 99 | # ------ Name of the SRAL file. There have three kinds of S3A data which are the enhanced,standard and the reduced data. 100 | # ------ Here we choose the enhanced data because it contains the waveform data. 101 | file_path = os.path.join(path0, file_s3a, 'enhanced_measurement.nc') 102 | 103 | print("The Sentinel3A SRAL file is:%s" %(file_path)) 104 | # print('\n') 105 | # ------ Finish loading file 106 | 107 | # -----------------------# 108 | # Open nc file using NetCDF tools 109 | # -----------------------# 110 | ncs3 = Dataset(file_path) 111 | 112 | # print(ncs3.variables.keys()) #keys 是字典数据类型的元素名称,对应这里就是经纬度时间等参数名字 113 | # print(ncs3.variables) 114 | s3ak = ncs3.variables.keys() 115 | # print(type(s3ak)) # 注意数据类型 116 | # print(len(s3ak)) # 数据的维度? 117 | s3ak2 = str(s3ak) 118 | # print(type(s3ak2)) 119 | # print(len(s3ak2)) # 字符串的长度 120 | 121 | 122 | 123 | # read variables 124 | lat = ncs3.variables['lat_20_ku'][:] # 20Hz 125 | lon = ncs3.variables['lon_20_ku'][:] 126 | tim = ncs3.variables['time_20_ku'][:] 127 | wav = ncs3.variables['waveform_20_ku'][:] 128 | r_ku = ncs3.variables['range_ocog_20_ku'][:] 129 | 130 | lat1 = ncs3.variables['lat_01'][:] # 1Hz 131 | lon1 = ncs3.variables['lon_01'][:] 132 | alt = ncs3.variables['alt_20_ku'][:] 133 | tim1 = ncs3.variables['time_01'][:] 134 | alt1 = ncs3.variables['alt_01'][:] 135 | r_ku1 = ncs3.variables['range_ocean_01_ku'][:] 136 | r_c1 = ncs3.variables['range_ocean_01_c'][:] 137 | 138 | dry = ncs3.variables['mod_dry_tropo_cor_meas_altitude_01'][:] 139 | wet = ncs3.variables['mod_wet_tropo_cor_meas_altitude_01'][:] 140 | # wet_m = ncs3.variables['model_wet_tropo_corr'][:] 141 | 142 | ino = ncs3.variables['iono_cor_gim_01_ku'][:] # iono_cor_alt_01_ku 143 | ssb = ncs3.variables['sea_state_bias_01_ku'][:] 144 | sig_ku = ncs3.variables['sig0_ocean_01_ku'][:] 145 | inv = ncs3.variables['inv_bar_cor_01'][:] 146 | hff = ncs3.variables['hf_fluct_cor_01'][:] 147 | ots = ncs3.variables['ocean_tide_sol1_01'][:] 148 | sot = ncs3.variables['solid_earth_tide_01'][:] 149 | pot = ncs3.variables['pole_tide_01'][:] 150 | geo = ncs3.variables['geoid_01'][:] 151 | ssha = ncs3.variables['ssha_01_ku'][:] 152 | 153 | ssh = alt1-r_ku1-dry-wet-ino-inv-sot-pot 154 | 155 | # ssh = double(alt(i) - r_ku(i)) / 10000 - ... 156 | # double(dry(i) + wet(i) + ino(i) + ssb(i) + inv(i) + hff(i) + set(i) + pt(i)) / 1E4 - double(ots(i)) / 1E4; % SSH is the 157 | # stable 158 | # measurements 159 | # for geodesy, oceanography.. 160 | 161 | # vlz = nc.variables['z'][:] 162 | # 163 | # print("data dimention") 164 | # print(np.shape(lon)) 165 | # print(np.shape(lat)) 166 | # print(np.shape(r_ku)) 167 | # print(np.shape(wav)) # 数据是二维的 168 | # print(np.shape(lat1)) # 数据是二维的 169 | 170 | # -------------------------- 171 | # 查看数据的类型,注意python和MATLAB的差异 172 | # print(type(wav)) #查看数据类型 173 | # print(type(tim)) 174 | # print(wav[1, :]) #注意大括号和小括号的使用。 175 | # -------------------------- 176 | 177 | # -------------------------- 178 | # Plot wavform 179 | maxd = len(lat) 180 | interv = 10 181 | # select area 182 | lat_select = [] 183 | 184 | # define the latitude boundary 185 | k = 0 186 | for i in lat: 187 | k = k+1 188 | if i > lat_min and i < lat_max: 189 | # print('location:', i) 190 | lat_select.append(k) 191 | myslice = lat_select[0::1] # This is a slice. [a:b:c] means begin a ,end b, step c. 192 | k = 0 193 | lat_select = [] 194 | for i in lat1: 195 | k = k+1 196 | if i > lat_min and i < lat_max: 197 | lat_select.append(k) 198 | myslice_1hz = np.array(lat_select)[0::1] 199 | 200 | # myslice = slice(29000, maxd, interv) # Here you can control the interval by 'interv'. 201 | # Then the figures will show different waveforms. 202 | x = np.arange(1, 129, 1) # This is the bin index. Is constant number for each satellite. 203 | y = np.array(wav[myslice, :]) 204 | r = np.array(r_ku[myslice]) 205 | 206 | lat2 = np.array(lat[myslice]) 207 | lon2 = np.array(lon[myslice]) 208 | print("The length of 20Hz data is %d" % (len(lon2))) 209 | # print(len(lon2)) 210 | 211 | # Plot waveforms on one figure 212 | if plot_wave == "yes" and int(file_s3a[69:72]) == plot_cycle: 213 | for i in range(1, 16): 214 | plt.plot(x, y[i], 'r') 215 | # Plot waveforms on sub figures 216 | figsize = (10, 8) 217 | gs = gridspec.GridSpec(4, 4) 218 | # print(type(gs)) 219 | gs.update(hspace=0.4) 220 | fig1 = plt.figure(num="waveform", figsize=figsize) 221 | ax = [] 222 | 223 | for i in range(16): 224 | row = (i // 4) 225 | # print(i, row) 226 | col = i % 4 227 | # print(i, col) 228 | ax.append(fig1.add_subplot(gs[row, col])) 229 | ax[-1].set_title('lat=%s' % str(round(lat2[i], 4))) 230 | ax[-1].plot(x, y[i], 'ro', ms=2, ls='-', linewidth=0.5) 231 | plt.show() 232 | # 233 | # ---------------------------------------------------------------------------------------------------------------------- 234 | # latinfo = nc.variables['latitude'] 235 | 236 | # vlzinfo = nc.variables['u'] 237 | # print (vlzinfo) 238 | 239 | # ---------------------------------------------------------------------------------------------------------------------- 240 | # Fit 1Hz to 20 Hz 241 | # The method needs to be improved. Some parameters not interp well.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 242 | z = np.polyfit(lat1[myslice_1hz], wet[myslice_1hz], 1) 243 | wet_20 = np.polyval(z, lat[myslice]) 244 | z = np.polyfit(lat1[myslice_1hz], dry[myslice_1hz], 1) 245 | dry_20 = np.polyval(z, lat[myslice]) 246 | z = np.polyfit(lat1[myslice_1hz], sot[myslice_1hz], 1) 247 | sot_20 = np.polyval(z, lat[myslice]) 248 | z = np.polyfit(lat1[myslice_1hz], pot[myslice_1hz], 1) 249 | pot_20 = np.polyval(z, lat[myslice]) 250 | z = np.polyfit(lat1[myslice_1hz], inv[myslice_1hz], 1) 251 | inv_20 = np.polyval(z, lat[myslice]) 252 | z = np.polyfit(lat1[myslice_1hz], ino[myslice_1hz], 1) 253 | ino_20 = np.polyval(z, lat[myslice]) 254 | z = np.polyfit(lat1[myslice_1hz], geo[myslice_1hz], 1) 255 | geo_20 = np.polyval(z, lat[myslice]) 256 | ssh_20 = alt[myslice] - r_ku[myslice] - dry_20 - wet_20 - ino_20 - inv_20 - sot_20 - pot_20 - geo_20 257 | 258 | # plt.plot(lat1[myslice_1hz], ino[myslice_1hz], 'o') 259 | # plt.plot(lat[myslice], ino_20, '+') 260 | # plt.show() 261 | # ---------------------------------------------------------------------------------------------------------------------- 262 | 263 | # Save data 264 | file_out = os.path.join('..', 'data', outfile) 265 | first_line = file_s3a[69:72]+' lat lon tim \n' 266 | # print(first_line) 267 | with open(file_out, 'a') as fileobj: 268 | # fileobj.write(first_line) 269 | for i in range(len(np.array(lat[myslice]).tolist())): 270 | if np.array(r_ku[myslice])[i] != 2147483647 and np.array(lat[myslice])[i] > lat_out_min and np.array(lat[myslice])[i] < lat_out_max: 271 | 272 | fileobj.write(str('%15.5f' % np.array(lat[myslice]).tolist()[i]) + ' ') 273 | fileobj.write(str('%15.5f' % np.array(lon[myslice]).tolist()[i]) + ' ') 274 | fileobj.write(str('%15.5f' % np.array(tim[myslice]).tolist()[i]) + ' ') 275 | # fileobj.write(str('%15.5f' % np.array(alt[myslice]).tolist()[i]) + ' ') 276 | fileobj.write(str('%15.5f' % np.array(ssh_20).tolist()[i]) + ' \n ') 277 | # fileobj.write(str('%15.5f' % np.array(r_ku[myslice]).tolist()[i]) + '\n ') 278 | 279 | file_out2 = os.path.join('..', 'data', 'wsl_1hz.npy') 280 | with open(file_out2, 'a') as fileobj: 281 | fileobj.write(first_line) 282 | for i in range(len(np.array(lat1[myslice_1hz]).tolist())): 283 | # print(i) 284 | fileobj.write(str('%15.5f' % np.array(lon1[myslice_1hz]).tolist()[i]) + ' ') 285 | fileobj.write(str('%15.5f' % np.array(lat1[myslice_1hz]).tolist()[i]) + ' ') 286 | fileobj.write(str('%15.5f' % np.array(tim1[myslice_1hz]).tolist()[i]) + ' ') 287 | fileobj.write(str('%15.5f' % np.array(alt1[myslice_1hz]).tolist()[i]) + ' ') 288 | fileobj.write(str('%15.5f' % np.array(sig_ku[myslice_1hz]).tolist()[i]) + ' ') 289 | fileobj.write(str('%15.5f' % np.array(dry[myslice_1hz]).tolist()[i]) + ' ') 290 | fileobj.write(str('%15.5f' % np.array(wet[myslice_1hz]).tolist()[i]) + ' ') 291 | fileobj.write(str('%15.5f' % np.array(ino[myslice_1hz]).tolist()[i]) + ' ') 292 | fileobj.write(str('%15.5f' % np.array(inv[myslice_1hz]).tolist()[i]) + ' ') 293 | fileobj.write(str('%15.5f' % np.array(sot[myslice_1hz]).tolist()[i]) + ' ') 294 | fileobj.write(str('%15.5f' % np.array(pot[myslice_1hz]).tolist()[i]) + ' ') 295 | fileobj.write(str('%15.5f' % np.array(r_ku1[myslice_1hz]).tolist()[i]) + ' ') 296 | fileobj.write(str('%15.5f' % np.array(geo[myslice_1hz]).tolist()[i]) + ' ') 297 | fileobj.write(str('%15.5f' % np.array(ssh[myslice_1hz]).tolist()[i]) + '\n ') 298 | # OR 299 | # np.savetxt("WSL.npy", (lat2, lon2, r), fmt="%10.5f", delimiter=",") 300 | 301 | 302 | # Save names of s3a variables 303 | if len(s3ak) != 0 and output_name == "yes": 304 | fh = open("s3adata.txt", "w") 305 | for i in s3ak: 306 | fh.write(str(i)+'\n') 307 | fh.close() 308 | else: 309 | print("You choose not to output the variables to file") 310 | -------------------------------------------------------------------------------- /pylake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenericAltimetryTools/altimeter_read/cb3d9c2103c3405dee648cacf752c31ccb9dca40/pylake.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Read me 2 | 3 | ## Introduction 4 | This software is aimed to read satellite altimetry data of the netCDF format. It is still undergoing development. More functions will be added in future, such as the waveform retracking over lakes, AI application on waveform determination, sea ice thickness estimation. 5 | 6 | The netCDF4 lib is used under python3. 7 | This software is aimed to: 8 | - Read Sentinel-3A SRAL data, including the waveform data, analysis data and show data in 9 | figures. 10 | - Apply AI algorithm to the waveform data to classify sea ice and sea water in the arctic ocean. 11 | - ... 12 | 13 | ## Snapshot of Examples 14 | You can download data example from [here](https://www.jianguoyun.com/p/DfGdEB8Q2PCQBxidq9YC). 15 | 16 | The waveform will be plotted as: 17 |  18 | In the future, I will add the surface type determination (sea ice types, ponds in Arctic,etc.) by AI. 19 | 20 | The time series of AVISO MMS over South China Sea will be plotted like: 21 |  22 | 23 | The seasonal signals were not excluded here. 24 | 25 | The water level of the Poyang Lake during the flood will be estimated like (without data filtering and waveform retracking): 26 | 27 |