⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s_principal_components.m

📁 matlab源代码
💻 M
字号:
function [pc,aux]=s_principal_components(seismic,varargin)
% Function computes principal components of seismic data. It can output the 
% input data represented by any combination of the principal components --- 
% usually the first few. 
% It can also output a seismic data set representing one or more of the principal components
%
% Written by E. R., July 18, 2000
% Last updated July 27, 2001: Copy 'headers' if output is 'seismic'.
%
%             [pc,aux]=s_principal_components(seismic,varargin)
% INPUT
% seismic     seismic data set
% varargin    one or more cell arrays; the first element of each cell array is a keyword,
%             the other elements are parameters. Presently, keywords are:
%             'output' Type of output. Possible values are: 
%                     'pc' (principal components), 'seismic', 'coefficients'. 
%                      In the first case one trace is output for each principal 
%                      component requested; headers which are constant are output as well.
%                      In the second case the number of output traces equals the number
%                      of input traces and all headers are copied.
%                      In the third case the coefficients of each with 
%                      which the principal components are multiplied to form one 
%                      trace are output.
%                      Default: {'output','seismic'}
%             'components' Principal components requested. Possible values are integers > 0.
%                      The maximum value is the smaller of the number of
%                      samples and the number of traces. A request for principal components
%                      with higher order is ignored. 
%                      Default: if {'output','seismic'} then {'components',1}
%                               if {'output','pc'} then {'components',1:maximum_value}
%             'scale'  Only used if {'output','pc'}. Possible values are: 'yes' (scale them by
%                      energy) or 'no'. Default: {'scale','yes'}
% OUTPUT
% pc          seismic structure; if {'output','seismic'} it is the seismic input data 
%             represented by the principal components defined via keyword 'components'.
%             if {'output','pc'} it is the principal components defined via keyword 
%             'components'.
% aux         structure with auxiliary information
%     if output is "seismic'
%     'energy' row vector: scaled energy of the principal components of each trace
%     'd'     column vector: cumulative sum of the squared singular values (scaled so that 
%             the last entry is 1)
%     if output is "pc"
%     'sing_values"   singular values


if ~isstruct(seismic)
  error(' First input argument must be a structure')
end

if isfield(seismic,'null') & isnan(seismic.null)
  error(' Seismic data must not contain NaNs')
end

pc=seismic;

[nsamp,ntr]=size(seismic.traces);
min_nsamp_ntr=min([nsamp,ntr]);

% 	Set default values
param.output='seismic';
param.components=[];

%       Decode and assign input arguments
param=assign_input(param,varargin);

%       Set/check number of principal components requested.
if isempty(param.components)
   if strcmpi(param.output,'seismic')
      param.components=1;
   else
      param.components=1:min_nsamp_ntr;
   end
else
%   idx=find(param.components <= min_nsamp_ntr);
   param.components=param.components(param.components <= min_nsamp_ntr);
end


switch param.output

           	case 'seismic'
[pr_cmp,energy,d]=princ_comp_no1(seismic.traces,param.components);
pc.traces=pr_cmp;

%   	Copy rest of the fields
pc=copy_fields(seismic,pc);

%	Add history field if it exists in seismic
aux.energy=energy;
aux.d=d;
pc=s_header(pc,'add_ne','energy',energy,'n/a','Fraction of total trace energy retained');
 
        	case 'pc'
[pc.traces,sing_val]=princ_comp_no2(seismic.traces,param.components);

%   	Copy rest of the fields
% pc=copy_fields(seismic,pc);

%   	Copy headers that are constant and delete others
if isfield(seismic,'header_info')
   nh=size(seismic.headers,1);
   headers=zeros(nh,1);
   header_info=cell(nh,3);
   icount=0;
   for ii=1:nh
      if min(seismic.headers(ii,:)) == max(seismic.headers(ii,:))
         icount=icount+1;
         headers(icount)=seismic.headers(ii,1);
         header_info(icount,:)=seismic.header_info(ii,:);
      end
   end
   if icount > 0
      pc.headers=headers(1:icount,:);
      pc.header_info=header_info(1:icount,:);
   else
      pc=rmfield(pc,{'header','header_info'});
   end
end      

%	Choose sign of the principal components so that they best
% 	represents the average of the input data
stack=sum(seismic.traces,2);
pcc=pc.traces'*stack;
idx=find(pcc < 0);
if  ~isempty(idx), 
   pc.traces(:,idx)=-pc.traces(:,idx); 
end

if nargout > 1
   aux.sing_values=sing_val;
end

                case 'coefficients'
[pc.traces,d]=princ_comp_no3(seismic.traces,param.components);
if nargout > 1
   aux.sing_values=d;
end
pc.first=1;
pc.last=length(param.components);
pc.step=1;
pc.unit='samples';
pc.tag='principal_components';
pc.row_label=param.components(:);


  		otherwise
error([' Unknowm option for keyword "output": ',param.output])
		
end		% End of switch block


%	Add entry to the history field if it exists in seismic
htext=[' Principal components: ',num2str(param.components)];
pc=s_history(pc,'append',htext); 


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [pc,energy,dd]=princ_comp_no1(s,npc)
% Function computes principal components of s over the range npc and outputs
% them together with the total relative energy in each column of s.
%       [pc,energy,d]=princ_comp(s,npc)
% INPUT
% s     input array
% npc   indices of principal components to use
%       max(npc) <= number of columns of s
% OUTPUT
% pc    principal components
% energy  fraction of total trace energy

[ns,ntr]=size(s);

if ns >= ntr
  [u,d,v]=svd(s,0);
else
  [v,d,u]=svd(s',0);
end

d=diag(d);

if nargout > 2; 
   dd=d.^2;
   scf=1/sum(dd);
   dd=cumsum(dd)*scf; 
else
   scf=1/sum(d.^2);
end

%scf=1/sum(d.^2);

ik=0;
for ii=npc
   ik=ik+1;
   vv(:,ik)=v(:,ii)*d(ii);
end

pc=u(:,npc)*vv';
if ik == 1
   energy=reshape((vv.^2)*scf,1,[]);
else
   energy=sum(vv.^2,2)*scf;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [pc,sing_val]=princ_comp_no2(s,npc)
% Function computes principal components of s over the range of indices npc 
% and outputs them together with the total relative energy in each column of s.
%
%           [pc,sing_val]=princ_comp1(s,npc)
% INPUT
% s         input array
% npc       indices of principal components to use
% OUTPUT
% pc        principal components
% sing_val  normalized singular values (sum of squares = 1)

[u,d]=svd(s,0);

pc=u(:,npc);
sing_val=d(npc)./sqrt(sum(diag(d).^2));


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [vv,d]=princ_comp_no3(s,npc)
% Function computes coefficients of the principal components of s over
% the range of indices npc and outputs them together with the total 
% relative energy in each column of s.
%
%           [pc,sing_val]=princ_comp1(s,npc)
% INPUT
% s         input array
% npc       indices of principal components to use
% OUTPUT
% vv        Matrix with coefficients of the principal components for each column of s
%           there are as many columns as there are columns of "s"
% d         all singular values 

[ns,ntr]=size(s);

if ns >= ntr
   [u,d,v]=svd(s,0);
else
   [v,d]=svd(s',0);
end

d=diag(d);

ik=0;
for ii=npc
   ik=ik+1;
   vv(:,ik)=v(:,ii)*d(ii);
end

if ns < ntr
   vv=vv';
end


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -