SSA_prelim_pipeline.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. % run from C:\Users\Fee/ Lab\Documents\MATLAB\NCM/ Project\useful/
  2. % scripts\custom\
  3. % for speed, it is important to have raw data local when processing
  4. addpath(genpath('neuropix_pipeline'))
  5. close all;
  6. clear;
  7. bird_id = '9074';
  8. rec_date = '210811';
  9. stim_date = '210810';
  10. dataset_name = '9074_210811_LH_NCM_g0';
  11. bin_name = [dataset_name '_t0.nidq.bin'];
  12. path = ['D:\\' dataset_name];
  13. DemoReadSGLXData(bin_name, path, rec_date)
  14. myKsDir = [path '\' dataset_name '_imec0'];
  15. thisBinName = [dataset_name '_t0.nidq.bin'];
  16. thisPath = ['D:\\' dataset_name];
  17. [sp, b, Audio_eventTimes, IMEC_eventTimes] = correct_IMEC_Spiketimes(thisPath, thisBinName);
  18. save([thisPath '\syncData_' rec_date '.mat'], 'sp', 'b', 'Audio_eventTimes', 'IMEC_eventTimes')
  19. disp('done with sync!')
  20. save('sync_checkpoint.mat')
  21. %%
  22. spwf = sp;
  23. cids = sp.cids(find(sp.cgs==2));
  24. best_wfs = zeros(length(cids),82);
  25. myKsDir = [path '\' dataset_name '_imec0'];
  26. %%
  27. for neuron = 1:length(cids)
  28. gwfparams.dataDir = myKsDir; % KiloSort/Phy output folder
  29. apD = dir(fullfile(myKsDir, '*ap*.bin')); % AP band file from spikeGLX specifically
  30. gwfparams.fileName = apD(1).name; % .dat file containing the raw
  31. gwfparams.dataType = 'int16'; % Data type of .dat file (this should be BP filtered)
  32. gwfparams.nCh = 385; % Number of channels that were streamed to disk in .dat file
  33. gwfparams.wfWin = [-40 41]; % Number of samples before and after spiketime to include in waveform
  34. gwfparams.nWf = 100; % Number of waveforms per unit to pull out
  35. gwfparams.spikeTimes = ceil(spwf.st(spwf.clu==cids(neuron))*30000); % Vector of cluster spike times (in samples) same length as .spikeClusters
  36. gwfparams.spikeClusters = spwf.clu(spwf.clu==cids(neuron));
  37. wf = getWaveForms(gwfparams);
  38. theseWFs = squeeze(wf.waveFormsMean);
  39. wfRange = range(theseWFs,2);
  40. [~, maxIdx] = max(wfRange);
  41. best_wf = theseWFs(maxIdx,:);
  42. best_wfs(neuron,:) = best_wf;
  43. end
  44. save([thisPath '\wfData_' rec_date '.mat'], 'best_wfs')
  45. disp('done with waveforms')
  46. %% timeline info
  47. % motif times start here
  48. [micData, fs] = audioread([path '\micData_' rec_date '.wav']);
  49. load(['workspace_' stim_date '.mat'], 'stim_timeline', 'timeline', 'syll_phase')
  50. save_info = [path '/timingData_' rec_date '.mat'];
  51. %theoretically, this varies... (and it got us into trouble)...
  52. minThresh = 0.0149; % should be fine, but change if there are issues!
  53. if strcmp(bin_name, '9074_210811_LH_NCM_g0_t0.nidq.bin')
  54. purge_data = [1.401e8 1.5e8+1.823e6];
  55. micData(purge_data(1):purge_data(2)) = 0;
  56. elseif strcmp(bin_name, '9063_210812_LH_NCM_g0_t0.nidq.bin')
  57. purge_data = [1 787800];
  58. pd2 = [14.1e7 15e7];
  59. micData(purge_data(1):purge_data(2)) = 0;
  60. micData(pd2(1):pd2(2)) = 0;
  61. end
  62. timeOffset = find(micData>minThresh,1);
  63. motifStarts = stim_timeline.motifs{2,1};
  64. motifStarts = motifStarts + (timeOffset/fs);
  65. x_MotifStarts = motifStarts;
  66. motifStarts_samples = round(motifStarts*fs);
  67. motif_lengths = diff(motifStarts_samples);
  68. mStarts_2 = zeros(1,length(motifStarts));
  69. mStarts_2(1) = motifStarts_samples(1);
  70. precess = [];
  71. for mIdx = 2:length(motifStarts)
  72. prev_m_start = mStarts_2(mIdx-1);
  73. prev_m_end = prev_m_start + motif_lengths(mIdx-1);
  74. windowTime1 = 0.02;
  75. windowTime2 = 0.02;
  76. end_check = prev_m_end - round(windowTime1*fs); % try 10ms step back - equal to shortest ISI (in case overshot)
  77. fr_samp = [end_check prev_m_end+round(windowTime2*fs)]; % also go forward just in case undershot (can be arbitrarily forward bc only first will be found)
  78. next_m_start = find(micData(fr_samp(1):fr_samp(2)) > minThresh,1);
  79. % figure(3); plot(micData(fr_samp(1):fr_samp(2))); pause;
  80. mStarts_2(mIdx) = end_check + next_m_start;
  81. precess = [precess; prev_m_end-mStarts_2(mIdx)];
  82. end
  83. % at end of motif period, there's a syllable period. this always starts at
  84. % the same time, and we just need to check when.
  85. mStarts_samples_2 = mStarts_2;
  86. mStarts_2 = mStarts_samples_2 / fs;
  87. % good for checking!
  88. for n = 1:length(mStarts_2)
  89. figure(1);
  90. if n < length(mStarts_2)
  91. plot(micData((mStarts_samples_2(n)):mStarts_samples_2(n+1)))
  92. else
  93. plot(micData((mStarts_samples_2(n)):mStarts_samples_2(n)+fs))
  94. end
  95. title(num2str(n))
  96. pause(0.05);%(0.05);
  97. end
  98. % ALRIGHT, mStarts_samples_2 and mStarts_2 look good! -
  99. % maybe now we could do the other analyses
  100. timingData = cell(length(mStarts_2), 2);
  101. timingData(:,1) = stim_timeline.motifs{1};
  102. timingData(:,2) = mat2cell(mStarts_2', ones(1,length(mStarts_2)),1);
  103. motifTimingData = timingData; % this is what needs to be saved!
  104. % nb we also want syllable timing data from end of experiment
  105. end_of_motifs = mStarts_samples_2(end) + 10000000;
  106. this_syll_start_win = [end_of_motifs end_of_motifs+5000000];
  107. syll_phase_starts = zeros(length(syll_phase),1);
  108. for sIdx = 1:length(syll_phase)
  109. if sIdx > 1
  110. prev_s_start = syll_phase_starts(sIdx-1);
  111. prev_s_end = prev_s_start + (.5*fs); %just before earliest conceivable start of next syll
  112. end_check = prev_s_end + (2*fs); % if we hit here, we've gone too far
  113. fr_samp = [prev_s_end end_check]; % also go forward just in case undershot (can be arbitrarily forward bc only first will be found)
  114. else
  115. fr_samp = this_syll_start_win;
  116. end
  117. next_s_start = find(micData(fr_samp(1):fr_samp(2)) > minThresh,1);
  118. syll_phase_starts(sIdx) = fr_samp(1) + next_s_start;
  119. end
  120. sStarts_samples = syll_phase_starts;
  121. sStarts = sStarts_samples / fs;
  122. % good for checking!
  123. for n = 1:length(sStarts)
  124. figure(1);
  125. if n < length(sStarts)
  126. plot(micData((sStarts_samples(n)):sStarts_samples(n+1)))
  127. else
  128. plot(micData((sStarts_samples(n)):sStarts_samples(n)+(.5*fs)))
  129. end
  130. title(num2str(n))
  131. pause(0.05);%(0.05);
  132. end
  133. % ALRIGHT, mStarts_samples_2 and mStarts_2 look good! -
  134. % maybe now we could do the other analyses
  135. syll_phase_timingData = cell(length(sStarts), 2);
  136. syll_phase_timingData(:,1) = syll_phase;
  137. syll_phase_timingData(:,2) = mat2cell(sStarts, ones(1,length(sStarts)),1);
  138. save(save_info, 'motifTimingData', 'syll_phase_timingData');
  139. disp('ALL DONE WITH TIMING DATA!')
  140. %% load checkpoint
  141. load([path '\timingData_' rec_date '.mat']);
  142. load([path '\syncData_' rec_date '.mat']);
  143. load(['workspace_' stim_date '.mat'], 'timeline', 'exp_info');
  144. fs = 40000; % update fs to that of microphone
  145. % oh no - we'll need syllable lengths etc for all syllables. let's get this
  146. % from the stimuli script
  147. [micData, ~] = audioread([path '\micData_' rec_date '.wav']);
  148. % song 6-10-21
  149. if strcmp(stim_date, '210810')
  150. syllable_lengths = [4359
  151. 1516
  152. 4248
  153. 3222
  154. 5505
  155. 3839
  156. 3742
  157. 3759
  158. 9613
  159. 8268
  160. 7274
  161. 2261
  162. 2459
  163. 4645
  164. 5909
  165. 6976
  166. 4113
  167. 11403
  168. 10760
  169. 3947
  170. 5504
  171. 7099] / 44100;
  172. end
  173. % matrix of offsets for each motif
  174. syll_offsets = zeros(8, 5);
  175. syll_offsets(1, 1:5) = [0, syllable_lengths(1)+.02, ...
  176. sum(syllable_lengths([1 6]))+.04, sum(syllable_lengths([1 6 11]))+.06,...
  177. sum(syllable_lengths([1 6 11 16]))+.08];
  178. syll_offsets(2, 1:5) = [0, syllable_lengths(2)+.02, ...
  179. sum(syllable_lengths([2 7]))+.04, sum(syllable_lengths([2 7 12]))+.06,...
  180. 0];
  181. syll_offsets(3, 1:5) = [0, syllable_lengths(4)+.02, ...
  182. sum(syllable_lengths([3 8]))+.04, sum(syllable_lengths([3 8 13]))+.06,...
  183. sum(syllable_lengths([3 8 13 18]))+.08];
  184. syll_offsets(4, 1:5) = [0, syllable_lengths(4)+.02, ...
  185. sum(syllable_lengths([4 9]))+.04, sum(syllable_lengths([4 9 14]))+.06,...
  186. 0];
  187. syll_offsets(5, 1:5) = [0, syllable_lengths(1)+.02, ...
  188. sum(syllable_lengths([1 9]))+.04, sum(syllable_lengths([1 9 11]))+.06,...
  189. 0];
  190. syll_offsets(6, 1:5) = [0, syllable_lengths(5)+.02, ...
  191. sum(syllable_lengths([5 6]))+.04, sum(syllable_lengths([5 6 11]))+.06,...
  192. sum(syllable_lengths([5 6 11 16]))+.08];
  193. syll_offsets(7, 1:5) = [0, syllable_lengths(4)+.02, ...
  194. sum(syllable_lengths([4 10]))+.04, sum(syllable_lengths([4 10 15]))+.06,...
  195. 0];
  196. syll_offsets(8, 1:5) = [0, syllable_lengths(17)+.02, ...
  197. sum(syllable_lengths([17 12]))+.04, sum(syllable_lengths([17 12 7]))+.06,...
  198. 0];
  199. motif_length = syll_offsets(:,4) + syllable_lengths([21; 17; 22; 19; 16; 21; 20; 2]);
  200. motifInfo = cell(length(motifTimingData(:,1)),3);
  201. % how many sylls? it'll always be the same - should be 5825...
  202. syllableInfo = cell(5825,4);
  203. this_syll_idx = 1;
  204. for mIdx = 1:length(motifTimingData(:,1))
  205. motifInfo(mIdx,1) = motifTimingData(mIdx,2); %start time
  206. motifInfo(mIdx,2) = motifTimingData(mIdx,1); %start
  207. mType = motifTimingData{mIdx,1};
  208. if strcmp(stim_date, '210810')
  209. sTypes = {...
  210. 'a1','a2','a3','a4','a5',...
  211. 'b1','b2','b3','b4','b5',...
  212. 'c1','c2','c3','c4','c5',...
  213. 'd1','d2','d3','d4','d5',...
  214. 'e1','e3'};
  215. end
  216. % before this, we need to figure out which motif it is
  217. switch mType
  218. case 'std_A' % idk what the labels are
  219. mType_num = 1;
  220. this_syll_ids = [1 6 11 16 21];
  221. max_sub = 5;
  222. case 'std_B'
  223. mType_num = 2;
  224. this_syll_ids = [2 7 12 17];
  225. max_sub = 4;
  226. case 'std_C'
  227. mType_num = 3;
  228. this_syll_ids = [3 8 13 18 22];
  229. max_sub = 5;
  230. case 'std_D'
  231. mType_num = 4;
  232. this_syll_ids = [4 9 14 19];
  233. max_sub = 4;
  234. case 'std_E'
  235. mType_num = 5;
  236. this_syll_ids = [1 9 11 16];
  237. max_sub = 4;
  238. case 'std_F'
  239. mType_num = 6;
  240. this_syll_ids = [5 6 11 16 21];
  241. max_sub = 5;
  242. case 'std_G'
  243. mType_num = 7;
  244. this_syll_ids = [4 10 15 20];
  245. max_sub = 4;
  246. case 'std_H'
  247. mType_num = 8;
  248. this_syll_ids = [17 12 7 2];
  249. max_sub = 4;
  250. end
  251. motifInfo(mIdx,3) = {cell2mat(motifInfo(mIdx,1))+motif_length(mType_num)};
  252. these_sylls = sTypes(this_syll_ids);
  253. for sub_idx = 1:max_sub
  254. syllableInfo(this_syll_idx,1) = ...
  255. {cell2mat(motifTimingData(mIdx,2)) + syll_offsets(mType_num,sub_idx)};
  256. syllableInfo{this_syll_idx,2} = mType;
  257. syllableInfo{this_syll_idx,3} = sTypes{this_syll_ids(sub_idx)}; % this is wrong!
  258. syllableInfo(this_syll_idx,4) = ...
  259. {cell2mat(syllableInfo(this_syll_idx,1))...
  260. + syllable_lengths(this_syll_ids(sub_idx))};
  261. this_syll_idx = this_syll_idx + 1;
  262. end
  263. end
  264. for sp_idx = 1:length(syll_phase)
  265. real_id = this_syll_idx - 1 + sp_idx;
  266. syllableInfo(real_id,1) = {cell2mat(syll_phase_timingData(sp_idx,2))};
  267. syllableInfo(real_id,2) = {'NA'};
  268. syllableInfo(real_id,3) = syll_phase_timingData(sp_idx,1);
  269. this_syll_id = find(strcmp(syll_phase_timingData(sp_idx,1), sTypes));
  270. this_len = syllable_lengths(this_syll_id);
  271. syllableInfo(real_id,4) = {cell2mat(syllableInfo(real_id,1)) + this_len};
  272. end
  273. save('motif_checkpoint.mat')
  274. disp('Ready for action!')
  275. %% unit quality screen - sometimes ksDriftmap runs out of memory??? no idea what to do in that case...
  276. % i could probably go all the way back to kilosort and disable some
  277. % channels? ksdriftmap memory requirement depends on number of spikes
  278. % what do i do when this happens? reload from motif_checkpoint and keep
  279. % trying... if issues aren't solved, try different dataset
  280. valid_contacts = [1 240];
  281. [spikeTimes, spikeAmps, spikeDepths, spikeSites] = ksDriftmap(myKsDir);
  282. disp('drift info here and ready')
  283. valid_spikes = find(spikeSites<=240);
  284. spikeSites = spikeSites(valid_spikes);
  285. spikeDepths = spikeDepths(valid_spikes);
  286. spikeAmps = spikeAmps(valid_spikes);
  287. spikeTimes = spikeTimes(valid_spikes);
  288. sp.st = sp.st(valid_spikes);
  289. sp.spikeTemplates = sp.spikeTemplates(valid_spikes);
  290. sp.clu = sp.clu(valid_spikes);
  291. %% now, create response matrices
  292. % this changes because we may now have a different response mat for each of
  293. % the 8 motif types. i think that's the idea, and then we can use eval
  294. % statements to make comparisons across these tensors
  295. % although do we even want it? or do we want motif response mats (standard
  296. % motifs, 4xtrialsxNeurons and alternate motfs mats, 4xtrialsxneurons).
  297. % that sorts us for the basic stuff, and then we can have one for syllables
  298. % x trials x neurons, along with a matrix that tells where transition
  299. % points are for each syllable.
  300. goodUnits = sp.cids(find(sp.cgs==2));
  301. good_unit_ids = 1:length(goodUnits);
  302. resp_win = [0 0.2]; % resp win extends 200ms past syllable end. NOT NECESSARILY THE RIGHT THING TO DO
  303. % we could do better here, but at the moment we're using same matrix for
  304. % iti during syllable phase
  305. iti_win_syll = [-0.250 0]; % should always be at least .5 between motifs, but we want to allow up to 250ms for motif response i think...
  306. iti_win_bouts = [-7 -2]; % at least 8 seconds between bouts - check 5 sec window in middle
  307. % std motifs from motifs 1-700 (with first repeats 1-500, 125 each)
  308. % alt motifs from motifs 701-1200 (125 each, no repeats)
  309. iti_starts_syll = [syllableInfo(end-549:end,1)];
  310. bout_starts = [motifInfo(1:5:end,1)];
  311. % should always be the same for stim 6/10
  312. if strcmp(stim_date, '210810')
  313. %idk what matters yet
  314. end
  315. % initialize matrix
  316. all_motif_resp = zeros(length(motifInfo(:,1)), length(good_unit_ids));
  317. all_syll_resp = zeros(length(syll_phase(:,1)), length(good_unit_ids));
  318. all_bout_resp = zeros(length(bout_starts), length(good_unit_ids));
  319. iti_resp = zeros(length(bout_starts), length(good_unit_ids));
  320. iti_resp_syll = zeros(length(iti_starts_syll), length(good_unit_ids));
  321. for unitIdx = 1:length(good_unit_ids)
  322. disp(['resp matrices for unit ' num2str(unitIdx) ' of ' num2str(length(good_unit_ids)) '.'])
  323. this_id = good_unit_ids(unitIdx);
  324. theseSpikes = sp.st(sp.clu==goodUnits(this_id));
  325. % create massive response matrix!
  326. %(syllable archetype x motif num x neuron)
  327. for motifIdx = 1:size(motifInfo,1)
  328. this_win = cell2mat(motifInfo(motifIdx, [1 3])) + resp_win;
  329. motif_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  330. resp_fr = length(motif_spikes) / (this_win(2) - this_win(1));
  331. all_motif_resp(motifIdx, unitIdx) = resp_fr;
  332. end
  333. % for each inter-bout period (when motifs are separated by at least
  334. % 750ms), find the firing rate during that period (within iti_win)
  335. for syllIdx = 1:length(syllableInfo(:,1))
  336. this_win = cell2mat(syllableInfo(syllIdx, [1 4])) + resp_win;
  337. syll_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  338. resp_fr = length(syll_spikes) / (this_win(2) - this_win(1));
  339. all_syll_resp(syllIdx, unitIdx) = resp_fr;
  340. end
  341. % for each motif, find the response to that motif (again allowing a
  342. % resp_win response window)
  343. for boutIdx = 1:length(bout_starts)
  344. this_win = cell2mat(bout_starts(boutIdx)) + resp_win;
  345. bout_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  346. resp_fr = length(bout_spikes) / (this_win(2) - this_win(1));
  347. all_bout_resp(boutIdx, unitIdx) = resp_fr;
  348. end
  349. for itiIdx = 1:length(bout_starts)
  350. this_win = cell2mat(bout_starts(itiIdx)) + iti_win_bouts;
  351. iti_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  352. resp_fr = length(iti_spikes) / (this_win(2) - this_win(1));
  353. iti_resp(itiIdx, unitIdx) = resp_fr;
  354. end
  355. % for each motif, find the response to that motif (again allowing a
  356. % resp_win response window)
  357. for itiIdx = 1:length(iti_starts_syll)
  358. this_win = cell2mat(iti_starts_syll(itiIdx)) + iti_win_syll;
  359. iti_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  360. resp_fr = length(iti_spikes) / (this_win(2) - this_win(1));
  361. iti_resp_syll(itiIdx, unitIdx) = resp_fr;
  362. end
  363. end
  364. %% repeat resp mat calculations for multi-units
  365. goodUnits_mu = sp.cids(find(sp.cgs==1));
  366. good_unit_ids_mu = 1:length(goodUnits_mu);
  367. % initialize matrix
  368. all_motif_resp_mu = zeros(length(motifInfo(:,1)), length(good_unit_ids_mu));
  369. all_syll_resp_mu = zeros(length(syll_phase(:,1)), length(good_unit_ids_mu));
  370. all_bout_resp_mu = zeros(length(bout_starts), length(good_unit_ids_mu));
  371. iti_resp_mu = zeros(length(bout_starts), length(good_unit_ids_mu));
  372. iti_resp_syll_mu = zeros(length(iti_starts_syll), length(good_unit_ids_mu));
  373. for unitIdx = 1:length(good_unit_ids_mu)
  374. disp(['resp matrices for unit ' num2str(unitIdx) ' of ' num2str(length(good_unit_ids_mu)) '.'])
  375. this_id = good_unit_ids_mu(unitIdx);
  376. theseSpikes = sp.st(sp.clu==goodUnits_mu(this_id));
  377. % create massive response matrix!
  378. %(syllable archetype x motif num x neuron)
  379. for motifIdx = 1:size(motifInfo,1)
  380. this_win = cell2mat(motifInfo(motifIdx, [1 3])) + resp_win;
  381. motif_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  382. resp_fr = length(motif_spikes) / (this_win(2) - this_win(1));
  383. all_motif_resp_mu(motifIdx, unitIdx) = resp_fr;
  384. end
  385. % for each inter-bout period (when motifs are separated by at least
  386. % 750ms), find the firing rate during that period (within iti_win)
  387. for syllIdx = 1:length(syllableInfo(:,1))
  388. this_win = cell2mat(syllableInfo(syllIdx, [1 4])) + resp_win;
  389. syll_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  390. resp_fr = length(syll_spikes) / (this_win(2) - this_win(1));
  391. all_syll_resp_mu(syllIdx, unitIdx) = resp_fr;
  392. end
  393. % for each motif, find the response to that motif (again allowing a
  394. % resp_win response window)
  395. for boutIdx = 1:length(bout_starts)
  396. this_win = cell2mat(bout_starts(boutIdx)) + resp_win;
  397. bout_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  398. resp_fr = length(bout_spikes) / (this_win(2) - this_win(1));
  399. all_bout_resp_mu(boutIdx, unitIdx) = resp_fr;
  400. end
  401. for itiIdx = 1:length(bout_starts)
  402. this_win = cell2mat(bout_starts(itiIdx)) + iti_win_bouts;
  403. iti_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  404. resp_fr = length(iti_spikes) / (this_win(2) - this_win(1));
  405. iti_resp_mu(itiIdx, unitIdx) = resp_fr;
  406. end
  407. % for each motif, find the response to that motif (again allowing a
  408. % resp_win response window)
  409. for itiIdx = 1:length(iti_starts_syll)
  410. this_win = cell2mat(iti_starts_syll(itiIdx)) + iti_win_syll;
  411. iti_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  412. resp_fr = length(iti_spikes) / (this_win(2) - this_win(1));
  413. iti_resp_syll_mu(itiIdx, unitIdx) = resp_fr;
  414. end
  415. end
  416. %% eliminate low fr (do this for MU too)
  417. fr_thresh = 1/60; % 1 spike per minute
  418. % exclude low fr - dangerous because neuron may ONLY spike during pert
  419. low_fr = [];
  420. low_fr_mu = [];
  421. goodUnits = sp.cids(find(sp.cgs==2)); % 1 for MUs, 2 for isolated
  422. for unitIdx = 1:length(goodUnits)
  423. theseSpikes = sp.st(sp.clu==goodUnits(unitIdx));
  424. this_fr = length(theseSpikes) / (length(micData)/fs);
  425. if this_fr < fr_thresh
  426. low_fr = [low_fr; unitIdx];
  427. end
  428. end
  429. disp(['found ' num2str(length(low_fr)) ' low fr single units.'])
  430. for unitIdx = 1:length(goodUnits_mu)
  431. theseSpikes = sp.st(sp.clu==goodUnits_mu(unitIdx));
  432. this_fr = length(theseSpikes) / (length(micData)/fs);
  433. if this_fr < fr_thresh
  434. low_fr_mu = [low_fr_mu; unitIdx];
  435. end
  436. end
  437. disp(['found ' num2str(length(low_fr_mu)) ' low fr multiunits.'])
  438. %% eliminate units without auditory responses, also for multiunits
  439. % really what we need is average response for each syllable type, then keep
  440. % doing what we're doing (except instead of 2*sd, use 2.87*sd for
  441. % bonferroni correction - pvalue of responsiveness is then .05/23)
  442. % technically, to claim that a unit is definitely auditory, we'd want 2.87
  443. % sds because of bonferroni. But really we just want to eliminate units
  444. % that are clearly non-auditory, so we'll use a single std. dev
  445. % we just can't make claims about nonexistence of certain units, but we
  446. % wouldn't be able to do that anyway
  447. mean_iti = mean(iti_resp,1);
  448. sd_iti = std(iti_resp,1);
  449. mean_iti_mu = mean(iti_resp_mu,1);
  450. sd_iti_mu = std(iti_resp_mu,1);
  451. iti_floor = mean_iti - sd_iti; % bonferroni corrected bounds
  452. iti_ceil = mean_iti + sd_iti;
  453. iti_floor_mu = mean_iti_mu - sd_iti_mu; % bonferroni corrected bounds
  454. iti_ceil_mu = mean_iti_mu + sd_iti_mu;
  455. % just looking for syllable type that drives greatest response
  456. max_resp = max(all_motif_resp, [], 1);
  457. min_resp = min(all_motif_resp, [], 1);
  458. max_resp_mu = max(all_motif_resp_mu, [], 1);
  459. min_resp_mu = min(all_motif_resp_mu, [], 1);
  460. non_aud = find(iti_floor < min_resp & iti_ceil > max_resp);
  461. non_aud_mu = find(iti_floor_mu < min_resp_mu & iti_ceil_mu > max_resp_mu);
  462. disp(['found ' num2str(length(non_aud)) ' single non-aud'])
  463. disp(['found ' num2str(length(non_aud_mu)) ' multi non-aud'])
  464. %% eliminate units with significant, long-lasting fr changes, SINGLE AND MULTI
  465. drift_thresh= 10;
  466. high_fr_drift = [];
  467. high_fr_drift_mu = [];
  468. win_size = 100;
  469. step_size = 5;
  470. moving_avg = [];
  471. moving_avg_mu = [];
  472. for this_start = 1:step_size:size(iti_resp,1)-(win_size-1)
  473. this_end = this_start + (win_size-1);
  474. this_row = mean(iti_resp(this_start:this_end,:),1);
  475. moving_avg = [moving_avg; this_row];
  476. end
  477. for this_start = 1:step_size:size(iti_resp_mu,1)-(win_size-1)
  478. this_end = this_start + (win_size-1);
  479. this_row = mean(iti_resp_mu(this_start:this_end,:),1);
  480. moving_avg_mu = [moving_avg_mu; this_row];
  481. end
  482. mv_avg_denom = moving_avg;
  483. mv_avg_denom(mv_avg_denom == 0) = 0.1;
  484. mv_avg_denom_mu = moving_avg_mu;
  485. mv_avg_denom_mu(mv_avg_denom_mu == 0) = 0.1;
  486. for this_col = 1:size(moving_avg,2)
  487. if ((max(moving_avg(:,this_col))/min(moving_avg(:,this_col)))/mean(moving_avg(:,this_col))) > drift_thresh
  488. high_fr_drift = [high_fr_drift; this_col];
  489. end
  490. end
  491. for this_col = 1:size(moving_avg_mu,2)
  492. if ((max(moving_avg_mu(:,this_col))/min(moving_avg_mu(:,this_col)))/mean(moving_avg_mu(:,this_col))) > drift_thresh
  493. high_fr_drift_mu = [high_fr_drift_mu; this_col];
  494. end
  495. end
  496. disp(['found ' num2str(length(high_fr_drift)) ' su with fr drift'])
  497. disp(['found ' num2str(length(high_fr_drift_mu)) ' mu with fr drift'])
  498. % 1. use motif_resp
  499. % 2. take moving average of that (10 trials, step of 1 trial)
  500. % 3. fr_drift = diff of that moving average
  501. % 4. eliminate neurons where fr_drift exceeds 5 (maybe 10) hz (experiment)
  502. % 5. update all_trial_resp, iti_resp and good_unit_ids accordingly
  503. %% eliminate units that drift significantly in space, SINGLE ONLY
  504. sd_win_size = 10*fs; % 10 second window
  505. sd_step_size = 2*fs; % 1 second
  506. spatial_drift_thresh = 30;
  507. high_spatial_drift = [];
  508. % deffo_bad = load('def_bad_210119b.mat');
  509. tape_length = round(max(round(spikeTimes*fs))+(5*fs), 5, 'significant');
  510. win_starts = 1:sd_step_size:(tape_length-sd_win_size)+1;
  511. win_ends = win_starts + sd_win_size - 1;
  512. depth_traces = zeros(length(goodUnits),length(win_starts));
  513. density_traces = depth_traces;
  514. ctr_samples = (sd_win_size/2):sd_step_size:(tape_length-(sd_win_size/2));
  515. depth_means = zeros(length(goodUnits),1);
  516. depth_sds = depth_means;
  517. for unitIdx = 1:length(goodUnits)
  518. theseDepths = spikeDepths(sp.clu==goodUnits(unitIdx));
  519. theseSpikes = spikeTimes(sp.clu==goodUnits(unitIdx));
  520. depth_means(unitIdx) = mean(theseDepths);
  521. depth_sds(unitIdx) = std(theseDepths);
  522. for winIdx = 1:length(win_starts)
  523. this_win_start = win_starts(winIdx)/fs;
  524. this_win_end = win_ends(winIdx)/fs;
  525. these_spike_ids = find(theseSpikes>this_win_start & theseSpikes<this_win_end);
  526. these_sds = theseDepths(these_spike_ids);
  527. depth_traces(unitIdx,winIdx) = mean(these_sds);
  528. density_traces(unitIdx,winIdx) = length(these_spike_ids)/(this_win_end-this_win_start);
  529. end
  530. end
  531. total_drift = range(depth_traces,2);
  532. high_spatial_drift = find(total_drift>=spatial_drift_thresh);
  533. depth_traces = zeros(length(goodUnits_mu),length(win_starts));
  534. density_traces = depth_traces;
  535. ctr_samples = (sd_win_size/2):sd_step_size:(tape_length-(sd_win_size/2));
  536. depth_means = zeros(length(goodUnits_mu),1);
  537. depth_sds = depth_means;
  538. for unitIdx = 1:length(goodUnits_mu)
  539. theseDepths = spikeDepths(sp.clu==goodUnits_mu(unitIdx));
  540. theseSpikes = spikeTimes(sp.clu==goodUnits_mu(unitIdx));
  541. depth_means(unitIdx) = mean(theseDepths);
  542. depth_sds(unitIdx) = std(theseDepths);
  543. for winIdx = 1:length(win_starts)
  544. this_win_start = win_starts(winIdx)/fs;
  545. this_win_end = win_ends(winIdx)/fs;
  546. these_spike_ids = find(theseSpikes>this_win_start & theseSpikes<this_win_end);
  547. these_sds = theseDepths(these_spike_ids);
  548. depth_traces(unitIdx,winIdx) = mean(these_sds);
  549. density_traces(unitIdx,winIdx) = length(these_spike_ids)/(this_win_end-this_win_start);
  550. end
  551. end
  552. total_drift = range(depth_traces,2);
  553. high_spatial_drift_mu = find(total_drift>=spatial_drift_thresh);
  554. disp(['found ' num2str(length(high_spatial_drift)) ' unstable single units'])
  555. disp(['found ' num2str(length(high_spatial_drift_mu)) ' unstable multiunits'])
  556. % 1. signal_loc is average depth of unit across 10 sec window with 2 sec
  557. % steps
  558. % 2. eliminate neurons where range of signal_loc exceeds 30u (experiment)
  559. % 3. update all_trial_resp, iti_resp and good_unit_ids accordingly
  560. %% CHECK IN - HOW MANY NEURONS REMAIN? ARE THEY REASONABLE?
  561. bad_units = union(union(low_fr, non_aud), union(high_fr_drift, high_spatial_drift));
  562. good_unit_ids = setdiff(1:length(goodUnits), bad_units);
  563. bad_units_mu = union(union(low_fr_mu, non_aud_mu), union(high_fr_drift_mu, high_spatial_drift_mu));
  564. good_unit_ids_mu = setdiff(1:length(goodUnits_mu), bad_units_mu);
  565. disp(['there are ' num2str(length(good_unit_ids)) ' good single units'])
  566. disp(['there are ' num2str(length(good_unit_ids_mu)) ' good multiunits'])