timing_prelim_pipeline.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. % run from C:\Users\Fee/ Lab\Documents\MATLAB\NCM/ Project\useful/
  2. % scripts\custom\
  3. addpath(genpath('neuropix_pipeline'))
  4. close all;
  5. clear;
  6. bird_id = '9299';
  7. rec_date = '222301';
  8. stim_date = '222201';
  9. dataset_name = '9299_222301_LH_NCM_g0';
  10. bin_name = [dataset_name '_t0.nidq.bin'];
  11. path = ['D:\\' dataset_name];
  12. DemoReadSGLXData(bin_name, path, rec_date)
  13. %% we don't have imec if we didn't cluster...
  14. % not much to be done if we don't even hve memory here...
  15. myKsDir = [path '\' dataset_name '_imec0'];
  16. % [spikeTimes, spikeAmps, spikeDepths, spikeSites] = ksDriftmap(myKsDir);
  17. % disp('done with dir')
  18. thisBinName = [dataset_name '_t0.nidq.bin'];
  19. thisPath = ['D:\\' dataset_name];
  20. [sp, b, Audio_eventTimes, IMEC_eventTimes] = correct_IMEC_Spiketimes(thisPath, thisBinName);
  21. save([thisPath '\syncData_' rec_date '.mat'], 'sp', 'b', 'Audio_eventTimes', 'IMEC_eventTimes')
  22. disp('done with sync!')
  23. save('sync_checkpoint.mat')
  24. %%
  25. spwf = sp;
  26. cids = sp.cids(find(sp.cgs==2));
  27. best_wfs = zeros(length(cids),82);
  28. % for some reason, we can get waveforms here in 9062, 8/12 - just skipping
  29. % individual problematic neurons. not too clear what consequences will be.
  30. % could be the case that some neurons just have rates that are too high?
  31. % would be great if it were easy to check this... let's figure it out
  32. % doesn't seem to be the case... it doesn't necessarily stop on neurons
  33. % that have high firing rates
  34. %
  35. % in fact, it's extremely unclear what is happening. we don't get issues on
  36. % the same unit every time, and sometimes it just works... it's not some
  37. % rolling memory issue, since sometimes, upon restarting, it stops much
  38. % sooner than the original time
  39. myKsDir = [path '\' dataset_name '_imec0'];
  40. %%
  41. for neuron = 1:length(cids)
  42. gwfparams.dataDir = myKsDir; % KiloSort/Phy output folder
  43. apD = dir(fullfile(myKsDir, '*ap*.bin')); % AP band file from spikeGLX specifically
  44. gwfparams.fileName = apD(1).name; % .dat file containing the raw
  45. gwfparams.dataType = 'int16'; % Data type of .dat file (this should be BP filtered)
  46. gwfparams.nCh = 385; % Number of channels that were streamed to disk in .dat file
  47. gwfparams.wfWin = [-40 41]; % Number of samples before and after spiketime to include in waveform
  48. gwfparams.nWf = 100; % Number of waveforms per unit to pull out
  49. gwfparams.spikeTimes = ceil(spwf.st(spwf.clu==cids(neuron))*30000); % Vector of cluster spike times (in samples) same length as .spikeClusters
  50. gwfparams.spikeClusters = spwf.clu(spwf.clu==cids(neuron));
  51. wf = getWaveForms(gwfparams);
  52. theseWFs = squeeze(wf.waveFormsMean);
  53. wfRange = range(theseWFs,2);
  54. [~, maxIdx] = max(wfRange);
  55. best_wf = theseWFs(maxIdx,:);
  56. best_wfs(neuron,:) = best_wf;
  57. end
  58. save([thisPath '\wfData_' rec_date '.mat'], 'best_wfs')
  59. disp('done with waveforms')
  60. %% timeline info
  61. % motif times start here
  62. [micData, fs] = audioread([path '\micData_' rec_date '.wav']);
  63. load(['workspace_' stim_date '.mat'], 'stim_timeline', 'timeline')
  64. save_info = [path '/timingData_' rec_date '.mat'];
  65. %theoretically, this varies... (and it got us into trouble)...
  66. if strcmp(dataset_name, '9206_222201_LH_NCM_g0')
  67. minThresh = 0.0149;
  68. elseif strcmp(dataset_name, '9299_222301_LH_NCM_g0')
  69. minThresh = 0.0125; % should be fine
  70. else
  71. minThresh = 0.0125;
  72. end
  73. timeOffset = find(micData>minThresh,1);
  74. motifStarts = stim_timeline.motifs{2,1};
  75. motifStarts = motifStarts + (timeOffset/fs);
  76. x_MotifStarts = motifStarts;
  77. motifStarts_samples = round(motifStarts*fs);
  78. motif_lengths = diff(motifStarts_samples);
  79. mStarts_2 = zeros(1,length(motifStarts));
  80. mStarts_2(1) = motifStarts_samples(1);
  81. precess = [];
  82. for mIdx = 2:length(motifStarts)
  83. prev_m_start = mStarts_2(mIdx-1);
  84. prev_m_end = prev_m_start + motif_lengths(mIdx-1);
  85. windowTime1 = 0.02;
  86. windowTime2 = 0.02;
  87. end_check = prev_m_end - round(windowTime1*fs); % try 10ms step back - equal to shortest ISI (in case overshot)
  88. 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)
  89. next_m_start = find(micData(fr_samp(1):fr_samp(2)) > minThresh,1);
  90. % figure(3); plot(micData(fr_samp(1):fr_samp(2))); pause;
  91. mStarts_2(mIdx) = end_check + next_m_start;
  92. precess = [precess; prev_m_end-mStarts_2(mIdx)];
  93. end
  94. % at end of motif period, there's a syllable period. this always starts at
  95. % the same time, and we just need to check when.
  96. mStarts_samples_2 = mStarts_2;
  97. mStarts_2 = mStarts_samples_2 / fs;
  98. % good for checking!
  99. for n = 1:length(mStarts_2)
  100. figure(1);
  101. if n < length(mStarts_2)
  102. plot(micData((mStarts_samples_2(n)):mStarts_samples_2(n+1)))
  103. else
  104. plot(micData((mStarts_samples_2(n)):mStarts_samples_2(n)+fs))
  105. end
  106. title(num2str(n))
  107. pause(0.05);%(0.05);
  108. end
  109. % ALRIGHT, mStarts_samples_2 and mStarts_2 look good! -
  110. % maybe now we could do the other analyses
  111. timingData = cell(length(mStarts_2), 2);
  112. timingData(:,1) = stim_timeline.motifs{1};
  113. timingData(:,2) = mat2cell(mStarts_2', ones(1,length(mStarts_2)),1);
  114. motifTimingData = timingData; % this is what needs to be saved!
  115. save(save_info, 'motifTimingData');
  116. disp('ALL DONE WITH TIMING DATA!')
  117. %% load checkpoint
  118. load([path '\timingData_' rec_date '.mat']);
  119. load([path '\syncData_' rec_date '.mat']);
  120. load(['workspace_' stim_date '.mat'], 'timeline', 'exp_info');
  121. fs = 40000; % update fs to that of microphone
  122. % oh no - we'll need syllable lengths etc for all syllables. let's get this
  123. % from the stimuli script
  124. [micData, ~] = audioread([path '\micData_' rec_date '.wav']);
  125. % song 6-10-21
  126. if strcmp(stim_date, '210810')
  127. syllable_lengths = [4359
  128. 1516
  129. 4248
  130. 3222
  131. 5505
  132. 3839
  133. 3742
  134. 3759
  135. 9613
  136. 8268
  137. 7274
  138. 2261
  139. 2459
  140. 4645
  141. 5909
  142. 6976
  143. 4113
  144. 11403
  145. 10760
  146. 3947
  147. 5504
  148. 7099] / 44100;
  149. elseif strcmp(stim_date, '222201')
  150. syllable_lengths = [4359
  151. 3839
  152. 7274
  153. 6976
  154. 5504
  155. 2643
  156. 6369
  157. 4118
  158. 5319
  159. 6054
  160. 4248
  161. 3759
  162. 2459
  163. 11403
  164. 7099
  165. ] /44100;
  166. end
  167. % matrix of offsets for each motif
  168. syll_offsets = zeros(3, 5);
  169. syll_offsets(1, 1:5) = [0, syllable_lengths(1)+.02, ...
  170. sum(syllable_lengths([1 2]))+.04, sum(syllable_lengths([1 2 3]))+.06,...
  171. sum(syllable_lengths([1 2 3 4]))+.08];
  172. syll_offsets(2, 1:5) = [0, syllable_lengths(2)+.02, ...
  173. sum(syllable_lengths([6 7]))+.04, sum(syllable_lengths([6 7 8]))+.06,...
  174. sum(syllable_lengths([6 7 8 9]))+.08];
  175. syll_offsets(3, 1:5) = [0, syllable_lengths(11)+.02, ...
  176. sum(syllable_lengths([11 12]))+.04, sum(syllable_lengths([11 12 13]))+.06,...
  177. sum(syllable_lengths([11 12 13 14]))+.08];
  178. motif_length = syll_offsets(:,5) + syllable_lengths([5; 10; 15]);
  179. motifInfo = cell(length(motifTimingData(:,1)),3);
  180. % how many sylls? it'll always be the same - should be 5825...
  181. syllableInfo = cell(12975,4);
  182. this_syll_idx = 1;
  183. for mIdx = 1:length(motifTimingData(:,1))
  184. motifInfo(mIdx,1) = motifTimingData(mIdx,2); %start time
  185. motifInfo(mIdx,2) = motifTimingData(mIdx,1); %start
  186. mType = motifTimingData{mIdx,1};
  187. if strcmp(stim_date, '210810')
  188. sTypes = {...
  189. 'a1','a2','a3','a4','a5',...
  190. 'b1','b2','b3','b4','b5',...
  191. 'c1','c2','c3','c4','c5',...
  192. 'd1','d2','d3','d4','d5',...
  193. 'e1','e3'};
  194. elseif strcmp(stim_date, '222201')
  195. sTypes = {...
  196. 'a1','b1','c1','d1','e1',...
  197. 'a2','b2','c2','d2','e2',...
  198. 'a3','b3','c3','d3','e3'};
  199. end
  200. % before this, we need to figure out which motif it is
  201. switch mType
  202. case 'std_A' % idk what the labels are
  203. mType_num = 1;
  204. this_syll_ids = [1 2 3 4 5];
  205. max_sub = 5; %idk what max sub is - max syll id?
  206. case 'std_B'
  207. mType_num = 2;
  208. this_syll_ids = [6 7 8 9 10];
  209. max_sub = 5;
  210. case 'std_C'
  211. mType_num = 3;
  212. this_syll_ids = [11 12 13 14 15];
  213. max_sub = 5;
  214. end
  215. motifInfo(mIdx,3) = {cell2mat(motifInfo(mIdx,1))+motif_length(mType_num)};
  216. these_sylls = sTypes(this_syll_ids);
  217. for sub_idx = 1:max_sub
  218. syllableInfo(this_syll_idx,1) = ...
  219. {cell2mat(motifTimingData(mIdx,2)) + syll_offsets(mType_num,sub_idx)};
  220. syllableInfo{this_syll_idx,2} = mType;
  221. syllableInfo{this_syll_idx,3} = sTypes{this_syll_ids(sub_idx)}; % this is wrong! % ??
  222. syllableInfo(this_syll_idx,4) = ...
  223. {cell2mat(syllableInfo(this_syll_idx,1))...
  224. + syllable_lengths(this_syll_ids(sub_idx))};
  225. this_syll_idx = this_syll_idx + 1;
  226. end
  227. end
  228. save('motif_checkpoint.mat')
  229. disp('Ready for action!')
  230. %% unit quality screen - sometimes ksDriftmap runs out of memory??? no idea what to do in that case...
  231. % i could probably go all the way back to kilosort and disable some
  232. % channels? ksdriftmap memory requirement depends on number of spikes
  233. % what do i do when this happens? reload from motif_checkpoint and keep
  234. % trying... if issues aren't solved, try different dataset
  235. valid_contacts = [1 240];
  236. [spikeTimes, spikeAmps, spikeDepths, spikeSites] = ksDriftmap(myKsDir);
  237. disp('drift info here and ready')
  238. valid_spikes = find(spikeSites<=240);
  239. spikeSites = spikeSites(valid_spikes);
  240. spikeDepths = spikeDepths(valid_spikes);
  241. spikeAmps = spikeAmps(valid_spikes);
  242. spikeTimes = spikeTimes(valid_spikes);
  243. sp.st = sp.st(valid_spikes);
  244. sp.spikeTemplates = sp.spikeTemplates(valid_spikes);
  245. sp.clu = sp.clu(valid_spikes);
  246. disp('we survived memory issues!')
  247. %% now, create response matrices
  248. % this changes because we may now have a different response mat for each of
  249. % the 8 motif types. i think that's the idea, and then we can use eval
  250. % statements to make comparisons across these tensors
  251. % although do we even want it? or do we want motif response mats (standard
  252. % motifs, 4xtrialsxNeurons and alternate motfs mats, 4xtrialsxneurons).
  253. % that sorts us for the basic stuff, and then we can have one for syllables
  254. % x trials x neurons, along with a matrix that tells where transition
  255. % points are for each syllable.
  256. % NB: can't really do ITI windows during first epoch
  257. goodUnits = sp.cids(find(sp.cgs==2));
  258. good_unit_ids = 1:length(goodUnits);
  259. resp_win = [0 0.2]; % resp win extends 200ms past syllable end. NOT NECESSARILY THE RIGHT THING TO DO
  260. bout_starts = [motifInfo(1:5:end,1)];
  261. % prep for getting non-aud responses
  262. pre_frame_size = mean(motif_length) * fs;
  263. pre_expmt = [1 timeOffset];
  264. pre_win_starts = (pre_expmt(1):round(pre_frame_size/2):pre_expmt(2)-pre_frame_size) ./ fs;
  265. pre_win_ends = (pre_win_starts + (pre_frame_size/fs));
  266. % initialize matrix
  267. all_motif_resp = zeros(length(motifInfo(:,1)), length(good_unit_ids));
  268. all_bout_resp = zeros(length(bout_starts), length(good_unit_ids));
  269. all_pre_resp = zeros(length(pre_win_starts), length(good_unit_ids));
  270. for unitIdx = 1:length(good_unit_ids)
  271. disp(['resp matrices for unit ' num2str(unitIdx) ' of ' num2str(length(good_unit_ids)) '.'])
  272. this_id = good_unit_ids(unitIdx);
  273. theseSpikes = sp.st(sp.clu==goodUnits(this_id));
  274. for pre_win_idx = 1:length(pre_win_starts)
  275. this_win = [pre_win_starts(pre_win_idx) pre_win_ends(pre_win_idx)];
  276. pre_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  277. pre_fr = length(pre_spikes) / (this_win(2) - this_win(1));
  278. all_pre_resp(pre_win_idx,unitIdx) = pre_fr;
  279. end
  280. % create massive response matrix!
  281. %(syllable archetype x motif num x neuron)
  282. for motifIdx = 1:size(motifInfo,1)
  283. this_win = cell2mat(motifInfo(motifIdx, [1 3])) + resp_win;
  284. motif_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  285. resp_fr = length(motif_spikes) / (this_win(2) - this_win(1));
  286. all_motif_resp(motifIdx, unitIdx) = resp_fr;
  287. end
  288. % for each motif, find the response to that motif (again allowing a
  289. % resp_win response window)
  290. for boutIdx = 1:length(bout_starts)
  291. this_win = cell2mat(bout_starts(boutIdx)) + resp_win;
  292. bout_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  293. resp_fr = length(bout_spikes) / (this_win(2) - this_win(1));
  294. all_bout_resp(boutIdx, unitIdx) = resp_fr;
  295. end
  296. end
  297. %% repeat resp mat calculations for multi-units
  298. goodUnits_mu = sp.cids(find(sp.cgs==1));
  299. good_unit_ids_mu = 1:length(goodUnits_mu);
  300. % initialize matrix
  301. all_motif_resp_mu = zeros(length(motifInfo(:,1)), length(good_unit_ids_mu));
  302. all_bout_resp_mu = zeros(length(bout_starts), length(good_unit_ids_mu));
  303. all_pre_resp_mu = zeros(length(pre_win_starts), length(good_unit_ids_mu));
  304. for unitIdx = 1:length(good_unit_ids_mu)
  305. disp(['resp matrices for unit ' num2str(unitIdx) ' of ' num2str(length(good_unit_ids_mu)) '.'])
  306. this_id = good_unit_ids_mu(unitIdx);
  307. theseSpikes = sp.st(sp.clu==goodUnits_mu(this_id));
  308. for pre_win_idx = 1:length(pre_win_starts)
  309. this_win = [pre_win_starts(pre_win_idx) pre_win_ends(pre_win_idx)];
  310. pre_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  311. pre_fr = length(pre_spikes) / (this_win(2) - this_win(1));
  312. all_pre_resp_mu(pre_win_idx,unitIdx) = pre_fr;
  313. end
  314. % create massive response matrix!
  315. %(syllable archetype x motif num x neuron)
  316. for motifIdx = 1:size(motifInfo,1)
  317. this_win = cell2mat(motifInfo(motifIdx, [1 3])) + resp_win;
  318. motif_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  319. resp_fr = length(motif_spikes) / (this_win(2) - this_win(1));
  320. all_motif_resp_mu(motifIdx, unitIdx) = resp_fr;
  321. end
  322. % for each motif, find the response to that motif (again allowing a
  323. % resp_win response window)
  324. for boutIdx = 1:length(bout_starts)
  325. this_win = cell2mat(bout_starts(boutIdx)) + resp_win;
  326. bout_spikes = find((theseSpikes > this_win(1)) & (theseSpikes < this_win(2)));
  327. resp_fr = length(bout_spikes) / (this_win(2) - this_win(1));
  328. all_bout_resp_mu(boutIdx, unitIdx) = resp_fr;
  329. end
  330. end
  331. %% eliminate low fr (do this for MU too)
  332. fr_thresh = 1/60; % 1 spike per minute
  333. % exclude low fr - dangerous because neuron may ONLY spike during pert
  334. low_fr = [];
  335. low_fr_mu = [];
  336. goodUnits = sp.cids(find(sp.cgs==2)); % 1 for MUs, 2 for isolated
  337. for unitIdx = 1:length(goodUnits)
  338. theseSpikes = sp.st(sp.clu==goodUnits(unitIdx));
  339. this_fr = length(theseSpikes) / (length(micData)/fs);
  340. if this_fr < fr_thresh
  341. low_fr = [low_fr; unitIdx];
  342. end
  343. end
  344. disp(['found ' num2str(length(low_fr)) ' low fr single units.'])
  345. for unitIdx = 1:length(goodUnits_mu)
  346. theseSpikes = sp.st(sp.clu==goodUnits_mu(unitIdx));
  347. this_fr = length(theseSpikes) / (length(micData)/fs);
  348. if this_fr < fr_thresh
  349. low_fr_mu = [low_fr_mu; unitIdx];
  350. end
  351. end
  352. disp(['found ' num2str(length(low_fr_mu)) ' low fr multiunits.'])
  353. %% eliminate units without auditory responses, also for multiunits
  354. % do this with pre-experiment time
  355. mean_iti = mean(all_pre_resp,1);
  356. sd_iti = std(all_pre_resp,1);
  357. mean_iti_mu = mean(all_pre_resp_mu,1);
  358. sd_iti_mu = std(all_pre_resp_mu,1);
  359. iti_floor = mean_iti - sd_iti; % bonferroni corrected bounds
  360. iti_ceil = mean_iti + sd_iti;
  361. iti_floor_mu = mean_iti_mu - sd_iti_mu; % bonferroni corrected bounds
  362. iti_ceil_mu = mean_iti_mu + sd_iti_mu;
  363. % just looking for syllable type that drives greatest response
  364. max_resp = max(all_motif_resp, [], 1);
  365. min_resp = min(all_motif_resp, [], 1);
  366. max_resp_mu = max(all_motif_resp_mu, [], 1);
  367. min_resp_mu = min(all_motif_resp_mu, [], 1);
  368. non_aud = find(iti_floor < min_resp & iti_ceil > max_resp);
  369. non_aud_mu = find(iti_floor_mu < min_resp_mu & iti_ceil_mu > max_resp_mu);
  370. disp(['found ' num2str(length(non_aud)) ' single non-aud'])
  371. disp(['found ' num2str(length(non_aud_mu)) ' multi non-aud'])
  372. %% eliminate units that drift significantly in space
  373. sd_win_size = 10*fs; % 10 second window
  374. sd_step_size = 2*fs; % 1 second
  375. spatial_drift_thresh = 30;
  376. high_spatial_drift = [];
  377. % deffo_bad = load('def_bad_210119b.mat');
  378. tape_length = round(max(round(spikeTimes*fs))+(5*fs), 5, 'significant');
  379. win_starts = 1:sd_step_size:(tape_length-sd_win_size)+1;
  380. win_ends = win_starts + sd_win_size - 1;
  381. depth_traces = zeros(length(goodUnits),length(win_starts));
  382. density_traces = depth_traces;
  383. ctr_samples = (sd_win_size/2):sd_step_size:(tape_length-(sd_win_size/2));
  384. depth_means = zeros(length(goodUnits),1);
  385. depth_sds = depth_means;
  386. for unitIdx = 1:length(goodUnits)
  387. theseDepths = spikeDepths(sp.clu==goodUnits(unitIdx));
  388. theseSpikes = spikeTimes(sp.clu==goodUnits(unitIdx));
  389. depth_means(unitIdx) = mean(theseDepths);
  390. depth_sds(unitIdx) = std(theseDepths);
  391. for winIdx = 1:length(win_starts)
  392. this_win_start = win_starts(winIdx)/fs;
  393. this_win_end = win_ends(winIdx)/fs;
  394. these_spike_ids = find(theseSpikes>this_win_start & theseSpikes<this_win_end);
  395. these_sds = theseDepths(these_spike_ids);
  396. depth_traces(unitIdx,winIdx) = mean(these_sds);
  397. density_traces(unitIdx,winIdx) = length(these_spike_ids)/(this_win_end-this_win_start);
  398. end
  399. end
  400. total_drift = range(depth_traces,2);
  401. high_spatial_drift = find(total_drift>=spatial_drift_thresh);
  402. depth_traces = zeros(length(goodUnits_mu),length(win_starts));
  403. density_traces = depth_traces;
  404. ctr_samples = (sd_win_size/2):sd_step_size:(tape_length-(sd_win_size/2));
  405. depth_means = zeros(length(goodUnits_mu),1);
  406. depth_sds = depth_means;
  407. for unitIdx = 1:length(goodUnits_mu)
  408. theseDepths = spikeDepths(sp.clu==goodUnits_mu(unitIdx));
  409. theseSpikes = spikeTimes(sp.clu==goodUnits_mu(unitIdx));
  410. depth_means(unitIdx) = mean(theseDepths);
  411. depth_sds(unitIdx) = std(theseDepths);
  412. for winIdx = 1:length(win_starts)
  413. this_win_start = win_starts(winIdx)/fs;
  414. this_win_end = win_ends(winIdx)/fs;
  415. these_spike_ids = find(theseSpikes>this_win_start & theseSpikes<this_win_end);
  416. these_sds = theseDepths(these_spike_ids);
  417. depth_traces(unitIdx,winIdx) = mean(these_sds);
  418. density_traces(unitIdx,winIdx) = length(these_spike_ids)/(this_win_end-this_win_start);
  419. end
  420. end
  421. total_drift = range(depth_traces,2);
  422. high_spatial_drift_mu = find(total_drift>=spatial_drift_thresh);
  423. disp(['found ' num2str(length(high_spatial_drift)) ' unstable single units'])
  424. disp(['found ' num2str(length(high_spatial_drift_mu)) ' unstable multiunits'])
  425. %% CHECK IN - HOW MANY NEURONS REMAIN? ARE THEY REASONABLE?
  426. bad_units = union(union(low_fr, non_aud), union(high_fr_drift, high_spatial_drift));
  427. good_unit_ids = setdiff(1:length(goodUnits), bad_units);
  428. bad_units_mu = union(union(low_fr_mu, non_aud_mu), union(high_fr_drift_mu, high_spatial_drift_mu));
  429. good_unit_ids_mu = setdiff(1:length(goodUnits_mu), bad_units_mu);
  430. disp(['there are ' num2str(length(good_unit_ids)) ' good single units'])
  431. disp(['there are ' num2str(length(good_unit_ids_mu)) ' good multiunits'])
  432. save(['D:\timing_expmts\pipelines\' dataset_name '.mat'])
  433. disp('early pipeline saved!')
  434. %% save pipeline!
  435. close all;
  436. save(['D:\\timing_expmts\pipelines\pipeline_' dataset_name '.mat'])
  437. disp('pipeline complete!')