RQL's Blog 菜鸟成长记

ncl中的傅里叶变换与频谱分析

2019-04-25
renql
ncl

红噪声是低频长波,其功率谱能量主要集中于低频处
白噪声是各个频率上的谱密度值相同

傅里叶变换

类似于谐波分析,将序列中的周期性视为正弦波
可以对数据做纬向傅里叶变换,也可以做时间上的傅里叶变换,得到傅里叶系数。常用的函数有以下三种

除以下三种外,还有基于复数时间序列的傅里叶变换 cfftf, cfftb ,当把其中的虚部数值设为0时,其计算结果类似于用 ezfftf,但用 ezfftf 时得到的频率只有正值,而用 cfftf 时可以得到负的频率值,适用于纬向数据,可以得到东传和西传的傅里叶系数,用该函数也可以对经傅里叶变换的傅里叶系数再进行傅里叶变换。
但用 cfftf 计算得到的结果没有标准化,若要得到标准化的结果,需要的输出结果再除以样本数

fourier_info

finfo = fourier_info(data, nhx, sclPhase) ;返回数组 finfo[3][...][N/2]
;对data的最右边一维做傅里叶变换,返回每个周期对应的振幅、第一个极大值的位置、方差百分比
;其中,振幅即每个周期对应的傅里叶系数的平方和的均方根
;设data最右边一维的长度为N,则分解得到的每个周期中包含的谐波数范围为 (0, N/2],谐波数值越大,周期越短。
;nhx=0时会返回谐波数分别为 (0, N/2] 时所对应的周期的信息,若 0 < nhx <= N/2,则返回谐波数分别为 (0, nhx] 时所对应的周期信息
;sclPhase其实就是data最右边一维点与点之间的间隔数,若最右边一维是经度,有72个点,则 sclPhase = 360/72 = 5

;注意点:data不能有缺测值,不包括周期点
;此外,该函数也有 fourier_info_n 的形式

ezfftf 向前快速傅里叶变换

cf = ezfftf(data) ;返回数组 [2][...][N/2]
;对data最右边一维做傅里叶变换,设其最右边一维的长度为N,返回傅里叶的实部与虚部系数
;同时以属性 xbar 返回data最右边一维的均值,以 npts 返回data最右边一维的长度,最右边一维不需要是2的倍数
;如果有缺测值,计算出来的傅里叶系数为0

ezfftb 向后快速傅里叶变换

其实就是根据傅里叶系数进行合成

data = ezfftb(cf, xbar) 
;cf 即利用 ezfftf 生成的傅里叶系数,其最左边维的长度必须是2,且 cf(0,...) 为实部,cf(1,...) 为虚部
;xbar 是data最右边维的平均数,可以是一个数,也可以是一维数组,长度为 data 左边维数长度的乘积

;利用该函数及 ezfftf 函数可以提取出 data 前几个波数周期的合成
;或者只提取出其中一个波动的曲线
;设现在有一个 data (ntime, nlev, nlat, nlon)
cf = ezfftf (data) ;得到 cf (2, ntime, nlev, nlat, nlon/2)
cf(:,:,:,:,3:nlon/2) = 0.0
data_wave1_3 = ezfftb (cf, 0)
;重构的data_wave1-3的平均数为0
data_wave1_3 = ezfftb (cf, cf@xbar)
;重构的data_wave1-3的平均数为cf@xbar

功率谱分析

功率谱分析以傅里叶变换为基础,将时间序列的总能量分解到不同频率上的分量,根据不同频率波的方差贡献诊断出序列的主要周期,从而确定周期的主要频率。常用的函数有 specx_anal, 交叉功率谱 specxy_anal, 功率谱显著性检验specx_ci

功率谱分析的步骤:

  1. 原始数据处理,求距平,去趋势。求距平不会改变数据的总方差,但可以避免突变偏移量,因为在后续的分析步骤中一般会用0来扩充序列。而趋势会在频率为0的地方产生一个功率谱峰值,这个峰值会影响整个功率谱的分布,进而掩盖其他周期。The trend removal is performed first, then the trend-removed data are tapered. This combination minimizes “ringing” and “leakage”.
  2. 利用自相关系数或离散傅里叶变换计算粗谱估计
  3. 由于光谱估计的高方差,原始周期图几乎没有直接的用处。原始周期图的波动可以由采样变异性驱动,这个问题在序列越短时就越严重。平滑原始周期图可以减少这个问题。如果用不同跨度的Daniell滤波器对原始周期图进行平滑处理,得到的结果是光谱表面更加平滑。置信区间更小。但是过度的平滑会模糊重要的光谱细节,而不充分的平滑会留下不稳定的不重要的光谱细节。

光谱估计的稳定性是“从一个序列的不同部分计算出的谱估计在多大程度上是一致的”或者“周期图中不相关的精细结构被消除的程度”。高稳定性对应于低方差的估计,是通过对多个周期图纵坐标求平均得到的。

在ncl中用 specx_anal 计算得到的功率谱值spcx随频率的积分等于序列方差,如下所示 (N是样本数,df=1/N是频率间隔)

(spcx(0)+spcx(N/2-1))*(df/2) + SUM{spcx(1:N/2-2)*df} = total variance of the series 

对应spcx-frequency的曲线图中,曲线与横坐标所围面积即序列方差。由于大于10天的低频区域所占横坐标窄,对应的spcx虚假偏高。如果用周期作为横坐标,则spcx需要乘以对应频率的平方,才能保证曲线与横坐标所围面积依然是序列方差,但此时高频区域所占横坐标变窄,对应的方差密度 spcx*frq^2 偏高。那么用什么来作为横坐标能更好地表示每个周期对应地方差密度?根据下面ppt中的公式演算,认为用频率or周期的自然对数作为横坐标,能使横坐标的分布相对比较均匀,不会因横坐标范围的过度压缩,而产生虚高的方差密度。通过虚构有固定周期的序列,以往研究也表明这种方式能更好地凸显出序列的主要周期。

如果需要对27年每年夏季功率谱做气候态平均,此时马尔可夫显著线不是简单的27年的马尔可夫线平均,而是需要通过如下算法去计算(该算法摘自官网):

d   = 0     ; detrending opt: 0=>remove mean 1=>remove mean + detrend
sm  = 1     ; smooth: should be at least 3 and odd; if small than 3, it would do no smoothing
pct = 0.10  ; percent taper: (0.0 <= pct <= 1.0) 0.10 common. If pct =0.0, no tapering will be done. If pct = 1.0, the whole series is affected

  ;************************************************
  ; calculate mean spectrum spectrum and lag1 auto cor
  ;************************************************
  
  ; loop over each segment of length ntim
  
   spcavg = new ( ntim/2, typeof(x))
   spcavg = 0.0
  
   r1zsum = 0.0
  
   do nt=0,nyear-1
      dof    = specx_anal(x(nt,:),d,sm,pct)      ; current segment spc
      spcavg = spcavg + dof@spcx                ; sum spc of each segment
      r1     = dof@xlag1                        ; extract segment lag-1
      r1zsum = r1zsum  + 0.5*log((1+r1)/(1-r1)) ; sum the Fischer Z
   end do
  
   r1z  = r1zsum/nyear                          ; average r1z
   r1   = (exp(2*r1z)-1)/(exp(2*r1z)+1)         ; transform back
                                                ; this is the mean r1
   spcavg  = spcavg/nyear                       ; average spectrum
  
  ;************************************************
  ; Assign mean spectrum to data object
  ;************************************************
  
   df      = 2.0*nyear   ; deg of freedom
   df@spcx = spcavg      ; assign the mean spc
   df@frq  = dof@frq
   df@xlag1= r1          ; assign mean lag-1
  
   splt = specx_ci(df, 0.05, 0.95)   ; confidence interval

;splt(4,ntim/2) including input spectrum (indx=0), Markov Red Noise spectrum (indx=1), 
;lower confidence bound for Markov (indx=2), upper confidence bound for Markov (indx=3)

Space-time Spectral Analysis

时空谱分析,主要用于研究热带波动。

带通滤波

ncl中的滤波主要有三种:

  • 权重因子加滑动平均:用 ` filwgts_lanczos 函数产生权重,然后用 wgt_runave_n_Wrap `结合上面产生的权重来进行滑动平均滤波。这种方法可以用于处理含缺测的数据,难点在于如何确定权重数的个数(必须是奇数)。当滤出的波段频率越低,需要的权重点数就越多,但这样会导致首尾的缺测数增多。因此可能需要重复计算以找出最佳的权重个数
  • Butterworth带通滤波器:另一种是直接利用Butterworth带通滤波器 bw_bandpass_filter ,这是一种信号处理滤波器,其设计目标是在通频带内具有尽可能平坦的频率响应。但该函数不能处理含缺测值的数据,因为它会把缺测值当正常数据处理,导致数值偏大最后超出数据范围。因此在使用该函数前,可以用 linmsg_n 函数,把缺测值都补上。其优点是在序列首尾的数据不会丢失。
  • 利用傅里叶变换滤波:先用向前快速傅里叶变换 ezfftf 函数得到傅里叶系数,然后将不需要的波段的系数设为0,再利用向后快速傅里叶变换 ezfftb 重构数据。该方法不会在首尾处产生缺测。但它无法对含有缺测值的序列进行运算。

此外还有专门用于空间滤波的函数 smth9

上述三种方法中,个人比较常用的是后两种。在计算EKE的时候,发现Butterworth带通滤波得到的EKE能量比基于傅里叶变换的带通滤波得到的EKE能量高很多,尤其是低频变率(10-90天)。于是特地对比了Butterworth带通滤波基于傅里叶变换的带通滤波的时间序列(都去除了平均值),发现Butterworth带通滤波似乎保留了年循环的过程。

权重因子加滑动平均

利用 ` filwgts_lanczos `产生对称的权重因子时,该函数会以属性形式 wgt@freq, wgt@resp (一维数组,长度为 2*权重因子数nwgt+3) 返回该权重因子滤波的响应函数。响应函数图的绘制代码:

  xyres = True
  xyres@gsnMaximize    = True
  xyres@gsnFrame       = False
  xyres@tiMainString   = "Band Pass: 20-100 srate=1: sigma = " + sigma
  xyres@tiXAxisString  = "frequency"
  xyres@tiYAxisString  = "response"
  xyres@gsnLeftString  = "fca=" + fca + "; fcb=" + fcb
  xyres@gsnRightString = nWgt
  xyres@trXMaxF        = 0.1
  xyres@trYMaxF        = 1.1
  xyres@trYMinF        = -0.1
  plot = gsn_csm_xy(wks, wgt@freq, wgt@resp, xyres)

  X = (/0.0, fca, fca, fcb, fcb, 0.1/)      ; ideal filter
  Y = (/0.0, 0.0, 1.0, 1.0, 0.0,  0.0 /) 
  resGs = True
  resGs@gsLineThicknessF = 1.0
  gsn_polyline(wks,plot,X,Y,resGs)

不同权重因子数量对应的响应函数分布,其中矩形曲线即理想型的响应函数

不同权重因子数的对比,蓝线(nwgt=49)和红线(nwgt=121)是24个月的滤波结果,绿线(nwgt=121)和黑线(nwgt=241)是120个月的低通滤波结果。

当第一种方法所使用的权重因子数越多,其结果与第二种带通滤波的结果类似,但会在首尾处产生很多缺测。

Butterworth带通滤波器

bw_bandpass_filter ( x, fca, fcb, opt, dims )

  • x是需要滤波的数据列,可以是多维数组
  • fca和fcb是滤波范围,一般是时间段的倒数,且两个都必须要小于0.5,按理来说fcb要大于fca,但大小关系反一下问题也不大
  • opt是选项,默认情况下是用6阶滤波(opt@m=6),时间间隔为1(opt@dt=1),减去平均值(opt@remove_mean=True),输出滤波后的时间序列(opt@return_filtered=True),不输出滤波后的波包(opt@return_envelope=False)

不能处理含有缺测值的数据

    ua    = f->U_anom(:,{LAT},{LON})   ; ua(time), read from one grid point

    ca    = 50.0        ; band start (longer period)
    cb    = 40.0        ; band end (时间间隔不能等于2)

    fca   = 1.0/ca      ; 'left'  frequency
    fcb   = 1.0/cb      ; 'right' frequency

    dims  = 0           ; 'time' dimension of ua  

    opt   = True        ; options to set
    opt@return_envelope = True ; time series of filtered and envelope values

    ua_bf = bw_bandpass_filter (ua,fca,fcb,opt,dims)       ; (ua,fca,fcb,opt,dims)
    copy_VarMeta(ua, ua_bf)
    ua_bf@long_name = "Band Pass: "+cb+"-"+ca+" day"

计算得到的结果示意如下,其中上图是原始序列,下图是滤波后的时间序列(蓝色)与波包(红色)

http://www.seismosoc.org/Publications/BSSA_html/bssa_96-2/05055-esupp/

利用傅里叶变换滤波

见1.3小节


支持 支付宝鼓励 鸡腿鸡腿

喜欢此文!

Content