%solves the forward Kalman filter efficiently for a large dendritic tree, %using a low-rank approximation to the steady-state (zero-SNR) solution. %this is a basic version of the code used to create the movies %'low_rank_horiz' and 'low_rank_speckle' %uses an implicit Euler implementation of the cable equation %for details, see Paninski 2009, 'Fast Kalman filtering on quasilinear dendritic trees' clear; %params/setup dt=.001; %sec g=50; %leakiness a=2e4; %intercompartmental coupling T=20; %number of time steps recalc_U_tol=1e-4; %tolerance for updating forward covariance movie_flag=1; %flag for plotting movie var_frac=.995; %defines how many singular values to keep horiz_scan=1; %flag setting which sim to run: speckle or horiz W=.005; %assume that observation noise covariance is proportional to the identity disp('loading tree...'); load THINSTAR; %available at http://neuromorpho.org/neuroMorpho/neuron_info.jsp?neuron_name=THINSTAR neuron=THINSTAR; parents=neuron(:,7); parents(1)=0; %soma = root of tree in this case x=neuron(:,3)'; h=neuron(:,4)'; N=length(parents); %number of compartments %setup for plotting below f = find(parents~=0); pp = parents(f); X = [x(f); x(pp); repmat(NaN,size(f'))]; H = [h(f); h(pp); repmat(NaN,size(f'))]; X = X(:); H = H(:); col=jet(100); %set colormap %create dynamics matrix (implict Euler implementation of cable equation) I=speye(N); e = ones(N,1); K=dt*(-g*I); for(i=1:N) j=parents(i); if(j~=0) adt=a*dt; K(i,j)=adt; K(j,i)=adt; K(i,i)=K(i,i)-adt; K(j,j)=K(j,j)-adt; end; end; mu=zeros(N,1); IK2=(I-K)^2; disp('making data...') V=zeros(N,1); Vs=zeros(N,T); %true V matrix if(~horiz_scan) B=zeros(N); %build observation matrix B (note: B is transposed relative to the paper) sb2=100; %make this many observations for(j=1:sb2) B(ceil(N*j/sb2),j)=1; if(size(B,1)>N) error('error specifying B'); end; end; B=B(:,1:j); else B=zeros(N,250); sb2=size(B,2); [junk,xx]=hist(x,sb2); dx=diff(xx); dx=dx(1)/2; ffx=zeros(sb2,1); for(i=1:sb2) fx=find(abs(x-xx(i))1) AU_old=cholIK\(cholIK'\U); R=AU_old/dt-IK2\AU_old/dt; Q=inv(inv(D)+AU_old'*R); O=orth([R B]); else %handle i=1 case: U,D=0 AU_old=0; D=0; O=orth(B); Q=0; R=0; end; OR=O'*R; OB=O'*B; M=-OR*Q*OR'+OB*inv(W)*OB'; CO=(IK2-I)\(IK2*O)*dt; [U_full,D_temp,junk]=svd(CO*(inv(M)+O'*CO)^-.5,'econ'); d=diag(D_temp).^2; if(1) %choose number of singular vals adaptively n=min(find(cumsum(d)/sum(d)>=var_frac)); %grab enough singular vals to cover var_frac of variance else n_svs=10; n=min(size(U,2),n_svs); %choose number of singular vals non-adaptively, with a hard ceiling end; D_old=D; U=U_full(:,1:n); D=-spdiags(d(1:n),0,n,n); disp(sprintf('number of retained singular values = %i',n)); if(i>1) nd=1:min(n,length(d_old)); if(norm(-d(nd)-d_old(nd))