BC_predNaturalMovies.m 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. function [naturalMovie_output]=BC_predNaturalMovies(loadData,filename,movieSignal,STA_output,NL_output,Hz)
  2. %[naturalMovie_output]=BC_predNaturalMovies(loadData,filename,movieSignal,STA_output,NL_output,Hz)
  3. %this function shows the prinicpal calculation for the prediction of the
  4. %response to the natural movie, from the linear-nonlinear model (LN-model)
  5. %computed with white noise stimulus.
  6. %Inputs:
  7. % loadData = the folder path of the natural movie files
  8. % filename = the filename of the BC of interest
  9. % movieSignal = the preprocessed natural movie signal the
  10. % output of the BC_getNaturalMovies.m. Important that the
  11. % movie signal has the same dimensions as the STA_output
  12. % STA_output = output of the BC_STA function; containing the
  13. % STA (filter) of the white noise stimulus
  14. % NL_output = output of the BC_NL function; containing the
  15. % output nonlinearity of the white noise stimulus
  16. % Hz = movie update rate given in excel file
  17. %
  18. %Outpus: naturalMovie_output = structure containing the output of the
  19. % prediction
  20. %
  21. % code by HS last modiefied March 2021
  22. %% Constants
  23. findBreak=500; %the movie is repeated multiple times. Between the movies there is
  24. %a break/gray screen of >0.5s. To find the start of each movie trial, you find the gray screen between the movies
  25. %-------------------------------------------------------------------------------
  26. %% 1. cut the natural movie signal to the size of the filter
  27. %in the BC_STA.m function, the STA was cut. Here the natural movie signal
  28. %has to be cut to the same dimensions.
  29. movieSignal_zoom=movieSignal(STA_output.rangeY_zoom,STA_output.rangeX_zoom,:);
  30. %make the signal 2D for prediction
  31. movieSignal2D_zoom=reshape(movieSignal_zoom,size(movieSignal_zoom,1)*...
  32. size(movieSignal_zoom,2),size(movieSignal_zoom,3));
  33. %-------------------------------------------------------------------------------
  34. %% 2. compute the prediction
  35. %% 2.1 convolution
  36. %normalize the filter
  37. linearFiler=normSTA(STA_output.STA2D_zoom);
  38. %convolve the natural movie stimulus sequence with the
  39. %normalized STA.
  40. stim2pred=filter2(linearFiler,movieSignal2D_zoom,'valid');
  41. %%IMPORTANT: if you have a best spatial and temporal component as described in Point 7
  42. %in the function BC_STA.m (see Method of Manuscript), this part hast to be done in two lines, e.g.:
  43. %NL_PredXaxis2=filter2(sp_bestnorm,movieSignal2D_zoom,'valid'); %first
  44. %convolve the spatial dimension
  45. %generator_signal=filter2(temp_bestnorm,NL_PredXaxis2,'valid'); %then the
  46. %temporal dimension
  47. %%Also note, to avoid noise contributions from pixels outside the receptive
  48. %%field,it is important to cut the STA into a smaller region around the maximum pixel, this
  49. %%gives a much cleaner NL-> see BC_STA.m and Methods in Schreyer&Gollisch (2021).
  50. %% 2.2 compute the prediction through linear interpolation
  51. NL_x=NL_output.bins.NL_xbin;
  52. NL_y=NL_output.bins.NL_ybin;
  53. %example of how to make the prediction through linear interpolation
  54. predMemP_y=nan(1,size(stim2pred,2));
  55. for kk=1:size(stim2pred,2)
  56. nbrTemp=stim2pred(kk); %first x-axis value to predict
  57. [xIndxS,xIndxL]= getIndex(NL_x,nbrTemp,1); %get those values that are on left and rigth
  58. xValueS=NL_x(xIndxS);
  59. xValueL=NL_x(xIndxL);
  60. %do the linear interpolation
  61. [polyCoeff] = polyfit([xValueS;xValueL],[NL_y(xIndxS);...
  62. NL_y(xIndxL)],1);
  63. predMemP_y(kk)=polyCoeff(1)*nbrTemp+polyCoeff(2);
  64. end
  65. %-------------------------------------------------------------------------------
  66. %% 4. compute the average response to the move
  67. %% 4.1 load movie response
  68. data=load([loadData,filename]); %load the file
  69. %sort the different pulses for the different trials
  70. diffttls=diff(data.ttls_ms);
  71. nbrTrials=find(diffttls>findBreak); %to find out which pulse correspond to a new trial (gray break)
  72. nbrFrames=diff(nbrTrials);
  73. if isempty(nbrFrames)
  74. nbrFrames=nbrTrials;
  75. end
  76. %I get the membrane potential per trial & frames per trial
  77. reOrderFrames=nan(nbrFrames(1),length(nbrTrials));
  78. membranePerTrial_origRes=cell(1,length(nbrTrials));
  79. for kk=1:length(nbrTrials)
  80. if kk==1 %first trial
  81. reOrderFrames(:,kk)=data.ttls_ms(1:nbrTrials(kk));
  82. membranePerTrial_origRes{kk}=data.membPot(reOrderFrames(1,kk):reOrderFrames(end,kk)-1); %-1 because the last frame is the start of the gray screen
  83. else
  84. reOrderFrames(:,kk)=data.ttls_ms(nbrTrials(kk-1)+1:nbrTrials(kk)); %end of previous trial +1 (starts at 999)
  85. membranePerTrial_origRes{kk}=data.membPot(reOrderFrames(1,kk):reOrderFrames(end,kk)-1);
  86. end
  87. end
  88. %I only include trials here that here fully finished until the break!
  89. %------------------------------------------------------------------------------------------
  90. %% 4.2 Natural Movie Build average per frame
  91. %make one value for the membrane potential between two stimulus signal (two
  92. %frames), where the same image was shown
  93. memPperTrial_Movie=avgPerFrameNatMovies(data.membPot,...
  94. reOrderFrames,nbrFrames(1),Hz);
  95. memP_AVGMovie=mean(memPperTrial_Movie,2);
  96. %------------------------------------------------------------------------------------------
  97. %% 5 compute the pearson correlation coefficient
  98. %pearson correlation
  99. corrcoeff_temp=corrcoef(memP_AVGMovie(STA_output.STA_fnbr:end),predMemP_y);
  100. pearCorrSqrt=corrcoeff_temp(2)^2;
  101. %not with this method the prediction value is a bit lower than what we report in the
  102. %manuscript. To get the same values as in the mansucript, you have to
  103. %cut 3sigma around the RF and perform the SVD (see also Manuscript and
  104. %BC_STA, BC_NL)
  105. %-------------------------------------------------------------------------------
  106. %% 6. plot the output
  107. figure;
  108. %plot the first frame of the move
  109. subplot(2,1,1)
  110. imagesc(movieSignal(:,:,1))
  111. colormap('gray'); %how the sitmulus was shown
  112. axis equal; axis tight;
  113. xticks([]); yticks([]);
  114. %plot the prediction trace
  115. subplot(2,1,2)
  116. %only for visual comparison we normalize the predicted trace to have the
  117. %same mean and std as the response to the movie.
  118. x=predMemP_y;
  119. m2=mean(memP_AVGMovie);
  120. s2=std(memP_AVGMovie);
  121. s1=std(x);
  122. m1=mean(x);
  123. corrPredMemPred=m2+(x-m1)*(s2/s1);
  124. plot(memP_AVGMovie(STA_output.STA_fnbr:end),'k') %original membrane potential
  125. hold on;
  126. plot(corrPredMemPred,'r')%predicted membrane potential
  127. title(['pCorr:' mat2str(round(pearCorrSqrt,2)) ' Filename: ' STA_output.filename])
  128. xlabel('stimulus frames')
  129. ylabel('voltage (ms)')
  130. legend('original response','predicted response')
  131. %-------------------------------------------------------------------------------
  132. %% 5. add variables into the output
  133. naturalMovie_output.pearCorrSqrt=pearCorrSqrt;
  134. naturalMovie_output.memP_AVGMovie=memP_AVGMovie;
  135. end
  136. function [IndS,IndL]= getIndex(x,valConv,Points)
  137. IndS=find(x<valConv,Points,'last'); %find the last 5 closest smaller values
  138. IndL=find(x>=valConv,Points);
  139. if isempty(IndS)|| length(IndS)<Points %if you are on the left border
  140. if isempty(IndS) %take value from 1:10
  141. IndL=find(x>=valConv,Points*2);
  142. IndS=IndL(1);
  143. IndL=IndL(2:end);
  144. else
  145. IndL=find(x>=valConv,Points*2-length(IndS));
  146. end
  147. elseif isempty(IndL)|| length(IndL)<Points %if you are on the right border
  148. if isempty(IndL) %take value from 1:10
  149. IndS=find(x<valConv,Points*2,'last');
  150. IndL=IndS(end);
  151. IndS=IndS(1:end-1);
  152. else
  153. IndS=find(x<valConv,Points*2-length(IndL));
  154. end
  155. end
  156. end
  157. % %make SVD of the filter
  158. % [sp,sigma,temp] = svd(STA_output.STA2D_zoom,'econ');
  159. % sp=sp(:,1);
  160. % imagesc(reshape(sp,size(STA_output.rangeY_zoom,2),size(STA_output.rangeX_zoom,2)));
  161. % temp=temp(:,1);
  162. % %linear filters
  163. % linearFiler1=normSTA(sp);
  164. % linearFiler2=normSTA(temp);
  165. % stim2pred=filter2(linearFiler1,movieSignal2D_zoom,'valid');
  166. % stim2pred=filter2(linearFiler2',stim2pred,'valid');