問題:
按照區域範圍(min_lat, max_lat)~(min_lon, max_lon)讀取一個NC文件,經、緯數據切片如何獲取維數是一個大問題,切片數量不當,容易導致微小的誤差,在後續的矩陣運算帶來大的災難。
例如:依據小間距網格計算結果,需與大間距網格數據進行誤差比較時,一般會對小間距風格數據進行插值,此時因爲插值後的網格精度是確定的,所以需要根據區域範圍,計算出插值後的經緯向維數值1,利用維數值進行遍歷插值。
而根據區域範圍直接讀取大間距網格數據,需要確定切片取值的經緯向維數值2,1與2的值需要嚴格一致,否則會造成矩陣運算錯誤,提示計算矩陣維數不一致錯誤信息。
過程:
1、經緯向維數值1計算公式
緯向維數:lat_steps = int(round((max_lat - min_lat)/grid_size,1)) +1
經向維數:lon_steps = int(round((max_lon - min_lon)/grid_size,1)) +1
此處假設經緯向網格間距一致,均爲grid_size值
採向round取小數1位,防止浮點計算誤差,採用int方式取整,亦可用math.ceil,math.floor取整,方式不影響結果
經向計算維數存在一些複雜性,因爲涉及到跨越日經線或零度線的問題。
如經向值域爲(-180,180],則需考慮跨越日經線,如經向範圍爲:170~-160,30度的範圍,
此時:max_lon = -160,min_lon = 170,顯然:min_lon > max_lon。
則經向維數:lon_steps = int(round((max_lon + 360 - min_lon)/grid_size,1)) + 1
經向值域爲(0, 360],則需考慮跨越零度經線(格林威治線),計算方式一致。
2、準備總維數:
lats = len(data.variables['lat']
lons = len(data.variables['lon']
2、切片取值方法
切片取值基本方法:[起始序號值:起始序號值+切片維數值]
需分別計算起始序號值與切片維數值。
緯向計算:
st_lat_index = max(math.floor((min_lat - nc_min_lat)/grid_size),0) # st_lat爲區域起始點,nc_min_lat爲文件的經向起始點
lat_steps = min(int(round((max_lat - min_lat)/grid_size,1)) +1,lats) # 與之前的計算保持一致
rdata = data.variables[feature][..., start_lat_index:start_lat_index+lat_steps, ...]
經向計算:
如果不考慮跨越日經線,計算方式完全一致,但跨越日經線帶來諸多麻煩事。
st_lon_index = max(math.floor((st_lon - min_lon)/grid_size),0) #起始序號,與緯向一致
if min_lon > max_lon: #跨越日經線,策略:分段取值,再拼接,故需分別求出 #兩切片維數值,同時確保兩段維數總和與之前計算的經向維數值一致。
lon_steps = min(int(round((max_lon + 360 - min_lon)/grid_size,1)) + 1, lons)
lon_steps1 = lons - start_lon_index #用經向總維數 - 起始序號
lon_steps2 = lon_steps - lon_steps1
rdata1 = data.variables[feature][..., ..., start_lon_index:]
rdata2 = data.variables[feature][..., ..., : lon_steps2]
rdata=np.concatenate((rdata1,rdata2), axis=2) # axis = 1/2根據實際情況定
else: #簡單模式
lon_steps = int(round((max_lon-min_lon)/grid_size,1)) + 1
rdata = data.variables[feature][..., ..., start_lon_index:start_lon_index+lon_steps]