BC_STA.m 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. function [STA_output]=BC_STA(loadData,filename,pixelSize,seed,Hz)
  2. %[STA_output]=BC_STA(loadData,filename,pixelSize,seed,Hz)
  3. %this function loads the voltage trace of the selected bipolar cell (BC)
  4. %and perorms a response-weighted average analysis analogous to the commonn
  5. %spike-triggered average (STA). For simplicity we refer to the analysis
  6. %STA,even though we work with a continous voltage signal and not spikes.
  7. %Inputs:
  8. % loadData = the folder path of the white noise files
  9. % filename = the filename of the BC of interest
  10. % pixelSize = the size of a square (checker) in monitor
  11. % pixels (see Documentation_Data.pdf)
  12. % seed = seed for the random number generator
  13. % Hz = stimulus update rate
  14. %
  15. %Outpus: STA_output = structure containing the STA, stimulus signal,
  16. % averaged membrane potential for calculating the output
  17. % nonlinearity
  18. %
  19. %
  20. % Note: the function is built only for cells recorded without frozen frames.
  21. % But additional comments are made for cells with frozen frames.
  22. % code by HS, last modified March 2021
  23. %% constants
  24. %OLED dimensions for regenerating the stimulus
  25. monitorXPixels=800; %x pixels of OLED monitor;
  26. monitorYPixels=600; %y pixels of OLED monitor;
  27. microPerPix=2.5; %one pixel=2.5 micrometer in size
  28. STA_TimeBack=1000; %time in ms you want to go back for generating the STA (to get smaller data I use here 1000ms, in the manuscript we use 2000ms).
  29. %-------------------------------------------------------------------------------
  30. %% 1.load cell
  31. data=load([loadData,filename]); %load the file
  32. %-------------------------------------------------------------------------------
  33. %% 2. regenerate the stimulus
  34. Nframes=length(data.ttls_ms); %number of frames shown (how many times the stimulus was updated)
  35. Nx=ceil(monitorXPixels/pixelSize); %number of squares shown X dimension
  36. Ny=ceil(monitorYPixels/pixelSize); %number of squares shown Y dimension
  37. nbrCheckers_total=Nx*Ny; %total number of checkers/square presented on the screen
  38. stimulus = recreateBinaryWhiteNoiseStimulus(Nx, Ny, Nframes, seed); %the function is available under: https://github.com/gollischlab/RecreateWhiteNoiseStimuliWithMatlab
  39. stimulus =stimulus(:,:,1:end-1);%take the last frame out ->needed for doing the average per frames see avgPerFrame
  40. %the output stimulus has 3 dimensions: Y,X (nbr of checkers on Y and X axis) and time. Easiest to understand the stimulus is by
  41. %plotting for example the first stimulus frame presented on the retina:
  42. %imagesc(stimulus(:,:,1));
  43. %Note: the stimulus values are drawn onto the
  44. %retina from the lower left corner, yet matlab displays it from the upper left corner.
  45. %Therefore the y axis has to be flipped when displaying.
  46. %set(gca,'YDir','normal');
  47. %For me the easiest is to directly flip the stimulus y dimension (and then I dont flip the axis when displaying):
  48. stimulus_origD = flipdim(stimulus,1);
  49. clear stimulus
  50. %Yet that might be personal preferences.Note: For generating the STA it does not
  51. %matter whether it is flipped or not. However if the STA is convolved with the natural movies it matters.
  52. %Further, if you have frozen and running frames, regenerate the stimulus separatly
  53. %for running and frozen frames (see Documentation_Data.pdf for the corresponding seeds).
  54. %-------------------------------------------------------------------------------
  55. %% 3. make average per stimulus frame
  56. membranPotAVG=avgPerFrame(data.membPot,data.ttls_ms); % weights needed for computing the STA
  57. %-------------------------------------------------------------------------------
  58. %% 4. Computing the STA
  59. %decide for numbers of frames you want to go back in time
  60. STA_fnbr=(ceil(STA_TimeBack/(1000/Hz))); % define the number of frame you want to go back in time
  61. %here I prefer to work with a 2D signal of the stimulus
  62. stimulus_2D = reshape(stimulus_origD, nbrCheckers_total, []);
  63. tic
  64. [~,STA_2D]=buildSTA ...
  65. (stimulus_2D,membranPotAVG,STA_fnbr);
  66. toc
  67. %if you like the STA as a 3D e.g.:
  68. STA_3D=reshape(STA_2D,Ny,Nx, ...
  69. size(STA_2D,2));% Y (monitor axis), X (monitor axis) and Z (STA_fnbr)
  70. %-------------------------------------------------------------------------------
  71. %% 5. Make a zoom-in of the STA
  72. %For simplification and to keep the code simple, I cut a window of around
  73. %100 micrometer on each side from the maximum. A zoom-in of the STA is better
  74. %to avoid overfitting for the NL and prediction.See Methods part of the
  75. %manuscript and comment-section 7 below for how it is done in the manuscript.
  76. oneCheckInMicron=pixelSize*microPerPix;
  77. zoom_RF=ceil(100/oneCheckInMicron);
  78. %get the maximum of the STA to make a zoom-in
  79. [max_Color,indx_Zoom]=max(abs(STA_3D(:)));
  80. [posY,posX,posZ]=ind2sub(size(STA_3D),indx_Zoom);
  81. %cut a window around the STA ->make a zoom-in STA
  82. %zoom STA -> here you take the x-y coordinates
  83. rangeY_zoom = posY+(-zoom_RF:zoom_RF); rangeY_zoom = rangeY_zoom(rangeY_zoom>0 & rangeY_zoom<=size(STA_3D,1));
  84. rangeX_zoom = posX+(-zoom_RF:zoom_RF); rangeX_zoom = rangeX_zoom(rangeX_zoom>0 & rangeX_zoom<=size(STA_3D,2));
  85. STA_3D_zoom=STA_3D(rangeY_zoom,rangeX_zoom,:); %take the data from the 2000ms STA
  86. %reshape the STA
  87. STA2D_zoom=reshape(STA_3D_zoom,size(rangeY_zoom,2)*size(rangeX_zoom,2),size(STA_3D_zoom,3));
  88. %get the zoom in of the stimulus signal
  89. stimulus3D_zoom=stimulus_origD(rangeY_zoom,rangeX_zoom,:);
  90. %reshap to 2D
  91. stimulus2D_zoom=reshape(stimulus3D_zoom,size(rangeY_zoom,2)*size(rangeX_zoom,2),size(stimulus3D_zoom,3));
  92. %-------------------------------------------------------------------------------
  93. %% 5. visualize STA: plot the frame with maximal intensity value
  94. %I also like to plot all/multiple STA frames around the maximum.
  95. colorLimits = [-max_Color,max_Color]; %mainly relevant if you plot multiple frames and want to keep the same colorbar
  96. %plot
  97. figure;
  98. imagesc(STA_3D(:,:,posZ))
  99. caxis(colorLimits);
  100. colormap('gray'); %how the sitmulus was shown
  101. axis equal; axis tight;
  102. title(['STA best frame, filename: ' filename])
  103. %-------------------------------------------------------------------------------
  104. %% 6. add variables into the output
  105. STA_output.STA_2D=STA_2D;
  106. STA_output.STA2D_zoom=STA2D_zoom;
  107. % STA_output.STA=STA; %not normalized
  108. STA_output.stimulus2D_zoom=stimulus2D_zoom;
  109. STA_output.Nx=Nx; %for reshapeing to 3D structure if needed
  110. STA_output.Ny=Ny;
  111. STA_output.membranPotAVG=membranPotAVG;
  112. STA_output.STA_fnbr=STA_fnbr;
  113. STA_output.filename=filename;
  114. STA_output.rangeX_zoom=rangeX_zoom;
  115. STA_output.rangeY_zoom=rangeY_zoom;
  116. STA_output.pixelSize=pixelSize;
  117. %-------------------------------------------------------------------------------
  118. %% 7. additional comments:
  119. %From the zoom STA, I seperate the response into the highest-ranked spatial and temporal
  120. %components by singular-value decomposition (see Mansucript Schreyer & Gollisch, 2021)
  121. %example code for the SVD:
  122. %[sp,sigma,temp] = svd(STA,'econ'); %use the non-normalized STA here!
  123. %sp=spatial component and temp= the temporal component.
  124. %the highest-ranked spatial and temporal component has to be defined e.g. by manually looking
  125. %at the components.
  126. %From here, I fitted a 2D Gaussian to the best spatial component.
  127. %Important for nonlinearity and prediction calculation:
  128. %To avoid noise contributions from pixels outside the receptive field, I reduced
  129. %the number of elements in the STA by setting pixel values of the STA outside
  130. %the 3-sigma contour of the Gaussian fit to zero and re-separating the spatiotemporal
  131. %receptive field within this window into the highest-ranked spatial and temporal components
  132. %by singular-value decomposition. To compute the nonlinearity, each component
  133. %was normalized to unit Euclidean norm. E.g.
  134. %sp_bestnorm=normSTA(sp_best);
  135. %temp_bestnorm=normSTA(temp_best);
  136. end