爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 20127|回复: 2

[程序设计] EOF MATLAB

[复制链接]

新浪微博达人勋

发表于 2020-12-11 13:33:48 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
  1. clc;clear;close all
  2. % 参考书籍
  3. % 黄嘉佑《气象统计分析与预报方法》(第四版)
  4. % 魏凤英《现代气候统计诊断与预测技术》(第2版)
  5. % matlab eig 函数:https://ww2.mathworks.cn/help/matlab/ref/eig.html
  6. % matlab M_Map 工具箱:https://www.eoas.ubc.ca/~rich/map.html
  7. % matlab M_Map 工具箱工具箱的安装:http://blog.sina.com.cn/s/blog_8fc890a20102v6pm.html
  8. %% 数据读取
  9. % ncdisp('sst-195001-201712.nc');             % NOAA Extended Reconstructed SST V4
  10. sst=ncread('sst-195001-201712.nc','sst');     % 海温
  11. lon=ncread('sst-195001-201712.nc','lon');     % 经度,分辨率:2°
  12. lat=ncread('sst-195001-201712.nc','lat');     % 纬度,分辨率:2°
  13. time=ncread('sst-195001-201712.nc','time');   % 时间,月平均,68年,12个月
  14. %% 选区域
  15. % 框选热带太平洋地区(Tropical Pacific:120°E-70°W;30°S-30°N)
  16. sst_TP=sst(61:146,30:60,:);
  17. % 把数据展开为四维(经度、纬度、月、年)
  18. sst_TP_12=reshape(sst_TP,86,31,12,68);
  19. [lon_TP,lat_TP,month_TP,year_TP]=size(sst_TP_12);
  20. %% 资料预处理
  21. % 求平均(每个格点不同月份的年平均)
  22. average=squeeze(nanmean(sst_TP_12(:,:,:,1:year_TP),4));  % 68年
  23. % 算距平(减去对应月份的平均值)
  24. sst_TP_anomaly_12=sst_TP_12-repmat(average,[1,1,1,year_TP]);
  25. % 降维,排列成m×n的形式(m:站点;n:时间)
  26. sst_TP_anomaly=reshape(sst_TP_anomaly_12,lon_TP,lat_TP,month_TP*year_TP);
  27. X_NaN=reshape(sst_TP_anomaly,lon_TP*lat_TP,month_TP*year_TP);
  28. % 去除NaN数据(NaN为陆地,没有海温)
  29. X_logical=isnan(X_NaN);  % 逻辑判断
  30. i=0;
  31. for j=1:lon_TP*lat_TP
  32.     if sum(X_logical(j,:))==0
  33.        i=i+1;
  34.        X(i,:)=X_NaN(j,:);
  35.     end
  36. end
  37. X=X/sqrt(month_TP*year_TP);  % 《气象统计分析与预报方法》142页
  38. %% EOF运算
  39. [X_x,X_y]=size(X);
  40. if X_x<=X_y             % 不考虑时空转换
  41.     S=X*X';             % 计算协方差
  42.     [v,d]=eig(S);       % 使用eig函数求特征向量v和特征值d
  43.     % 使用sort函数将特征值、特征向量按升序排序
  44.     [~,ind]=sort(diag(d));
  45.     Ds=d(ind,ind);
  46.     Vs=v(:,ind);
  47.     V=fliplr(Vs);  % 排序后的特征向量V
  48.     D=rot90(Ds,2); % 排序后的特征值D
  49. else                     % 考虑时空转换
  50.     S=X'*X;              % 计算协方差
  51.     [v,d]=eig(S);        % 使用eig函数求特征向量v和特征值d
  52.     % 使用sort函数将特征值、特征向量按升序排序
  53.     [~,ind]=sort(diag(d));
  54.     Ds=d(ind,ind);
  55.     Vs=v(:,ind);
  56.     VR=fliplr(Vs);  % 排序后的特征向量V
  57.     D=rot90(Ds,2);  % 排序后的特征值D
  58.     % 求X*X'的特征值(《现代气候统计诊断与预测技术》109页)
  59.     VR=X*VR;        
  60.     for i=1:length(D)
  61.         V(:,i)=VR(:,i)/sqrt(D(i,i));
  62.     end
  63. end
  64. % 时间系数
  65. T=V'*X*sqrt(month_TP*year_TP);
  66. % 特征向量的方差贡献
  67. diagonal=diag(D);
  68. total=0;
  69. for i=1:length(diagonal)
  70.     R(i)=diagonal(i)/sum(diagonal);  % 方差贡献率
  71.     total=total+diagonal(i);
  72.     G(i)=total/sum(diagonal);        % 累积方差贡献率
  73. end
  74. % 标准化处理
  75. for i=1:length(diagonal)
  76.     V(:,i)=V(:,i)*sqrt(D(i,i));    % 特征向量乘以特征值的平方根
  77.     T(i,:)=T(i,:)/sqrt(D(i,i));    % 时间系数除以特征值的平方根
  78. end
  79. %% 把删去的NaN数据补回
  80. [a,b]=size(V);

  81. V_NaN=NaN(lon_TP*lat_TP,b);
  82. j=1;
  83. for i=1:lon_TP*lat_TP
  84.     if sum(X_logical(i,:))==0
  85.        V_NaN(i,:)=V(j,:);
  86.        j=j+1;
  87.     end
  88. end
  89. %% 升维
  90. V_NaN=reshape(V_NaN,lon_TP,lat_TP,b);
  91. %% 显著性检验
  92. figure
  93. err=sqrt(2/(month_TP*year_TP))*diagonal/sum(diagonal); % 特征值的取样误差(North et al.,1982)
  94. dot=1:4;
  95. R_1_4=R(1:4)*100;
  96. err=err(1:4)'*100;
  97. plot(dot,R_1_4,'.','Markersize',12);
  98. hold on
  99. errorbar(dot,R_1_4,err,'LineStyle','none');
  100. axis([0 5 0 50]);
  101. set(gca,'YTick',0:10:50,'tickdir','out','yminortick','off');
  102. set(gca,'YTicklabel',{'0','10','20','30','40','50'});
  103. set(gca,'XTick',0:1:5,'tickdir','out','xminortick','off');
  104. set(gca,'XTicklabel',{'0','1','2','3','4','5'});
  105. set(gca,'linewidth',1,'fontsize',15,'fontname','Times');
  106. set(gcf,'color','white','Position',[100,100,1000,500]);
  107. title('Percentage variance (%)','fontsize',15,'color','b','position',[2.5,52]);
  108. %% 第一模态画图
  109. load colormap.mat
  110. figure ('colormap',colormap)
  111. % 空间分布
  112. subplot(2,1,1);
  113. V_1=V_NaN(:,:,1);  
  114. m_proj('miller','lon',[120 290],'lat',[-30 30]);
  115. [X1,Y1]=meshgrid(120:2:290,-30:2:30);
  116. m_contourf(X1,Y1,rot90(V_1),'linestyle','none');
  117. hold on
  118. m_contour(X1,Y1,rot90(V_1),[-0.1 0.1 0.4 0.8],'linecolor','k','ShowText','on');
  119. m_coast('patch',[.85 .85 .85 ],'edgecolor',[0.6 0.6 0.6]);
  120. m_grid('linestyle','none','xtick',[140 180 220 260],'ytick',[30 15 0 -15 -30],'fontsize',14,'tickdir','out');
  121. caxis([-1,1])
  122. ax=colorbar;
  123. set(ax,'linewidth',0.5,'fontsize',12,'edgecolor','k','YTick',[-1,-0.5,0,0.5,1],'YTickLabel',{'-1','-0.5','0','0.5','1'})
  124. set(gcf,'color','white','Position',[100,100,1000,500]);
  125. title(['(a) EOF1 = ' num2str(R(1:1)*100,4) '%'],'fontsize',15,'color','b');
  126. % 时间系数
  127. subplot(2,1,2);
  128. T_1=T(1,:);
  129. t=[1:month_TP*year_TP];
  130. plot(t,T_1,'k','linewidth',1);
  131. hold on;
  132. T_0=zeros(1,month_TP*year_TP);
  133. plot(t,T_0,'k--','linewidth',1);
  134. axis([0 840 -4 4]);
  135. set(gca,'YTick',-4:1:4,'tickdir','out','yminortick','on');
  136. set(gca,'YTicklabel',{'-4','-3','-2','-1','0','1','2','3','4'});
  137. set(gca,'XTick',0:60:840,'tickdir','out','xminortick','off');
  138. set(gca,'XTicklabel',{'1950','1955','1960','1965','1970','1975','1980','1985','1990','1995','2000','2005','2010','2015','2020'});
  139. set(gca,'linewidth',1,'fontsize',15,'fontname','Times');
  140. set(gcf,'color','white','Position',[100,100,1000,500]);
  141. title('(b) PC1','fontsize',15,'color','b');
  142. %% 第二模态画图
  143. load colormap.mat
  144. figure ('colormap',colormap)
  145. % 空间分布
  146. subplot(2,1,1);
  147. V_2=V_NaN(:,:,2);  
  148. m_proj('miller','lon',[120 290],'lat',[-30 30]);
  149. [X1,Y1]=meshgrid(120:2:290,-30:2:30);
  150. m_contourf(X1,Y1,rot90(V_2),'linestyle','none');
  151. hold on
  152. m_contour(X1,Y1,rot90(V_2),[-0.1 0.1 0.4 0.8],'linecolor','k','ShowText','on');
  153. m_coast('patch',[.85 .85 .85 ],'edgecolor',[0.6 0.6 0.6]);
  154. m_grid('linestyle','none','xtick',[140 180 220 260],'ytick',[30 15 0 -15 -30],'fontsize',14,'tickdir','out');
  155. caxis([-1,1])
  156. ax=colorbar;
  157. set(ax,'linewidth',0.5,'fontsize',12,'edgecolor','k','YTick',[-1,-0.5,0,0.5,1],'YTickLabel',{'-1','-0.5','0','0.5','1'})
  158. set(gcf,'color','white','Position',[100,100,1000,500]);
  159. title(['(a) EOF2 = ' num2str(R(2:2)*100,4) '%'],'fontsize',15,'color','b');
  160. % 时间系数
  161. subplot(2,1,2);
  162. T_2=T(2,:);
  163. t=[1:month_TP*year_TP];
  164. plot(t,T_2,'k','linewidth',1);
  165. hold on;
  166. T_0=zeros(1,month_TP*year_TP);
  167. plot(t,T_0,'k--','linewidth',1);
  168. axis([0 840 -4 4]);
  169. set(gca,'YTick',-4:1:4,'tickdir','out','yminortick','on');
  170. set(gca,'YTicklabel',{'-4','-3','-2','-1','0','1','2','3','4'});
  171. set(gca,'XTick',0:60:840,'tickdir','out','xminortick','off');
  172. set(gca,'XTicklabel',{'1950','1955','1960','1965','1970','1975','1980','1985','1990','1995','2000','2005','2010','2015','2020'});
  173. set(gca,'linewidth',1,'fontsize',15,'fontname','Times');
  174. set(gcf,'color','white','Position',[100,100,1000,500]);
  175. title('(b) PC2','fontsize',15,'color','b');
复制代码

评分

参与人数 1金钱 +5 收起 理由
天语 + 5 很给力!

查看全部评分

密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2020-12-22 14:52:15 | 显示全部楼层
你这复制粘贴别人代码还不标出处不太合适吧
密码修改失败请联系微信:mofangbao
回复 支持 1 反对 0

使用道具 举报

新浪微博达人勋

发表于 2021-10-9 16:48:03 | 显示全部楼层
您好,我想请问一下,做EOF分析是不是一定要要求数据是正态分布的,如果不是正态分布的数据可以做EOF嘛?
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表