├── README.md ├── SaveAsOMETIFF.m ├── SimDecayPhotonCount_Multiple.m └── SimTCSPCimage.m /README.md: -------------------------------------------------------------------------------- 1 | # TCSPC-image-simulation 2 | This MATLAB code provides an easy way to simulate TCSPC image data which includes effect of the IRF, background after-pulsing and laser repetition rate. Images are saved as OME.tiff using Bioformat. 3 | 4 | The method uses a Monte-Carlo simulation of photon arrival times based on probability density functions of emission (exponential) and excitation (Gaussian). 5 | 6 | The OME.tiff save was kindly provided by Ian Munro from the Photonics Group at Imperial College, London. Thanks to the OME team OME team who maintains the Bio-Formats library. Contact: Sebastien Besson from Dundee. 7 | 8 | You need to download the Bio-formats Matlab plugin from 9 | http://downloads.openmicroscopy.org/bio-formats/ 10 | and set the path to it as shown in the file. 11 | -------------------------------------------------------------------------------- /SaveAsOMETIFF.m: -------------------------------------------------------------------------------- 1 | function SaveAsOMETIFF(Data, Folder, dt) 2 | % Adapted from code developped by Ian Munro "Munro, Ian" 3 | % 2017-05-10 4 | 5 | tic 6 | disp('Saving as OME-tif...'); 7 | % verify that enough memory is allocated 8 | bfCheckJavaMemory(); 9 | autoloadBioFormats = 1; 10 | 11 | % load the Bio-Formats library into the MATLAB environment 12 | status = bfCheckJavaPath(autoloadBioFormats); 13 | assert(status, ['Missing Bio-Formats library. Either add loci_tools.jar '... 14 | 'to the static Java path or add it to the Matlab path.']); 15 | 16 | % initialize logging 17 | loci.common.DebugTools.enableLogging('ERROR'); 18 | sizet = size(Data, 3); 19 | 20 | Data_OME = reshape(Data, size(Data,1), size(Data,2), 1,1, size(Data,3)); 21 | % NB this line has been found to be crucial 22 | java.lang.System.setProperty('javax.xml.transform.TransformerFactory', 'com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl'); 23 | 24 | metadata = createMinimalOMEXMLMetadata(Data_OME); 25 | modlo = loci.formats.CoreMetadata(); 26 | 27 | modlo.moduloT.type = loci.formats.FormatTools.LIFETIME; 28 | modlo.moduloT.unit = 'ps'; 29 | % replace with 'Gated' if appropriate 30 | modlo.moduloT.typeDescription = 'TCSPC'; 31 | modlo.moduloT.start = 0; 32 | 33 | modlo.moduloT.step = dt; 34 | modlo.moduloT.end = (sizet -1) * dt; 35 | 36 | OMEXMLService = loci.formats.services.OMEXMLServiceImpl(); 37 | OMEXMLService.addModuloAlong(metadata,modlo,0); 38 | 39 | % important to delete old versions before writing. 40 | outputPath = [Folder, '.ome.tif']; 41 | if exist(outputPath, 'file') == 2 42 | delete(outputPath); 43 | end 44 | bfsave(Data_OME, outputPath, 'metadata', metadata); 45 | toc 46 | 47 | 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /SimDecayPhotonCount_Multiple.m: -------------------------------------------------------------------------------- 1 | function [ t, Phot_number ] = SimDecayPhotonCount_Multiple( Sim_param, Tau, N, n_decay ) 2 | %SIMDECAYPHOTONCOUNT Summary of this function goes here 3 | % n_decay is the number of decay to simulate 4 | 5 | Display = 0; 6 | 7 | % IRF parameters 8 | t0 = Sim_param(1); % offset in ns 9 | s = Sim_param(2); % standard deviation of Gaussian function in ns 10 | 11 | % Acquisition parameters 12 | n = Sim_param(3); % number of bits coding the TAC n = 8 --> 256 bins 13 | T = Sim_param(4); % Acquisition window 0-T in ns 14 | R = Sim_param(5); % Repetition rate of the laser in MHz 15 | Ap = Sim_param(6); % Afterpulsing in % --> background in TCSPC 16 | 17 | 18 | % Generating the arrival times 19 | if Tau > 0 20 | u_f = rand(N,n_decay); 21 | t_f = Tau*log(1./(1-u_f)); 22 | else 23 | t_f = zeros(N,n_decay); 24 | end 25 | 26 | 27 | if t0 <= 0 || s <= 0 28 | t_irf = zeros(N,n_decay); 29 | else 30 | u_irf = rand(N,n_decay); 31 | t_irf = t0 - s*erfinv(erf(t0/s) - 2*u_irf); 32 | end 33 | 34 | 35 | t_tot = t_f + t_irf; 36 | 37 | % Incomplete decays 38 | T_rep = 1000/R; 39 | t_tot = mod(t_tot,T_rep); 40 | 41 | % Afterpulsing background 42 | N_bg = ceil(Ap/100*N); 43 | t_Ap = T*rand(N_bg,n_decay); 44 | t_tot = [t_tot; t_Ap]; 45 | 46 | % Histogramming 47 | t = linspace(0,T,2^n+1); 48 | t(end) = []; 49 | Phot_number = histc(t_tot,[t t(end)+t(2)-t(1)]); % histc works in columns 50 | Phot_number(end,:) = []; 51 | 52 | 53 | if Display == 1 54 | % Displaying 55 | figure('Color','white'); 56 | semilogy(t,Phot_number); 57 | xlabel 'Time (ns)' 58 | ylabel 'Photon counts' 59 | title(['N = ',num2str(N),' photons, Tau = ',num2str(Tau),' ns']) 60 | 61 | figure('Color','white'); 62 | plot(t,Phot_number); 63 | xlabel 'Time (ns)' 64 | ylabel 'Photon counts' 65 | title(['N = ',num2str(N),' photons, Tau = ',num2str(Tau),' ns']) 66 | end 67 | 68 | end 69 | 70 | -------------------------------------------------------------------------------- /SimTCSPCimage.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % TCSPC data simulator 3 | % This code generates TCSPC data with Gaussian IRF and multiexcitation 4 | % peaks, background (afterpulsing). Choose between photon scan, tau scan, uniform, or freestyle simulation options. 5 | % The data is saved as a TIFF stack via various methods. 6 | % 7 | % Laser Analytics Group: http://laser.ceb.cam.ac.uk/ 8 | % Dr Romain Laine rfl30@cam.ac.uk 9 | % 2017-05-11 10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11 | 12 | close all 13 | clear all 14 | clc 15 | 16 | % Set the size of image you want to simulate. This also relates to the number of repeats for each condition ------- 17 | n_repeats = 1024; % number of pixels in the vertical direction 18 | n_conditions = 1024; % number of pixels in the horizontal direction 19 | 20 | % Change acquisition parameters -------------------- 21 | R = 80; % Repetition rate of the laser in MHz units 22 | T = 12.5; % Acquisition window 0-T in ns units 23 | n = 8; % number of bits coding the TAC n = 8 --> 256 bins 24 | Ap = 5; % Afterpulsing in % --> background in TCSPC 25 | 26 | % Change parameters for IRF----------------------------- 27 | t0 = 1.5; % offset in ns units 28 | s = 0.15; % standard deviation of Gaussian function in ns units 29 | N_irf = 1e8; % MAXIMUM 10^8! (150,000 for 256 bins to get close to 16 bit histograms) 30 | 31 | % 4 different types of simulations can be generated below 32 | 33 | % 1. For Photon number scan ---------------------- 34 | % Here the photon counts are linearly spaced between N_min and N_max across 35 | % a number of n_conditions 36 | N_min = 100; % minimum number of photons 37 | N_max = 5000; % maximum number of photons 38 | Tau = 5; % in ns units 39 | 40 | % 2. For Tau scan ------------------------------- 41 | % Here the lifetimes are linearly spaced between Tau_min and Tau_max. 42 | % All pixels have the same number of photons N. 43 | Tau_min = 0.05; % minimum lifetime 44 | Tau_max = 6; % minimum lifetime 45 | N = 5000; % number of photons 46 | 47 | % 3. For Uniform -------------------------------- 48 | % Here a uniform lifetime and number of photons is generated using the 49 | % variables Tau and N set above 50 | 51 | % 4. For Freestyle ----------------------------- 52 | % Here the list of lifetimes and photon counts are defined below in the 53 | % code 54 | FolderNameFreestyle = '_2 lines no BG'; 55 | 56 | 57 | %Save files to folder 58 | Save_ON = 1; 59 | FileName_append = ''; 60 | Folder_for_Save = 'D:\F3-CMM\TCSPC-image-simulation-master\TCSPC-image-simulation-master\'; 61 | 62 | % Simulation type ----------------------------- 63 | str = cell(1,4); 64 | str{1} = 'Photon # scan'; 65 | str{2} = 'Tau scan'; 66 | str{3} = 'Uniform'; 67 | str{4} = 'Freestyle'; 68 | 69 | [Selection,ok] = listdlg('PromptString','Select a file:','SelectionMode','single','ListString',str); 70 | 71 | Sim_type = str{Selection}; 72 | if ~ok 73 | return 74 | end 75 | 76 | 77 | %% ------------------------------------------------------------------------------------------------------- 78 | FolderName = [Sim_type, ... 79 | ' n=',num2str(n),'_T=',num2str(T),'ns_R=',num2str(R),'MHz_Ap=',num2str(Ap),'%',... 80 | '_IRF t0=',num2str(t0),'ns_s=',num2str(s),'ns_Nirf=',num2str(N_irf),'phot',... 81 | '_',num2str(n_repeats),'x',num2str(n_conditions)]; 82 | 83 | if strcmp(Sim_type, 'Tau scan') 84 | FolderName = [FolderName, '_Tau=',num2str(Tau_min),'-', num2str(Tau_max),'ns_N=',num2str(N),'phot']; 85 | elseif strcmp(Sim_type, 'Photon # scan') 86 | FolderName = [FolderName, '_Phot=',num2str(N_min),'-', num2str(N_max),'phot_Tau=',num2str(Tau),'ns']; 87 | elseif strcmp(Sim_type, 'Freestyle') 88 | FolderName = [FolderName, FolderNameFreestyle]; 89 | end 90 | 91 | Folder_for_Save = [Folder_for_Save, FolderName]; 92 | 93 | % ------------------------------------------------------------------------- 94 | 95 | Sim_param = [t0, s, n, T, R, Ap]; 96 | h_wait = waitbar(0,'Wait for the data to be simulated...') ; 97 | 98 | disp('Simulating data...'); 99 | 100 | tic 101 | if strcmp(Sim_type,'Photon # scan') 102 | N_list = round(linspace(N_min,N_max,n_conditions)); 103 | Tau_list = Tau*ones(1,n_conditions); 104 | 105 | elseif strcmp(Sim_type,'Tau scan') 106 | N_list = N*ones(1,n_conditions); 107 | Tau_list = linspace(Tau_min,Tau_max,n_conditions); 108 | 109 | elseif strcmp(Sim_type,'Uniform') 110 | N_list = N*ones(1,n_conditions); 111 | Tau_list = Tau*ones(1,n_conditions); 112 | 113 | elseif strcmp(Sim_type,'Freestyle') 114 | % Here the list of photons and lifetime can be freely created. The vertical 115 | % line #i will be composed of repeats of a single conditions set by 116 | % Tau_list(i) and N_list(i) 117 | 118 | % N_list = 50*ones(1,n_conditions); 119 | % N_list(20:40) = N; 120 | % Tau_list = Tau*ones(1,n_conditions); 121 | 122 | % N_list = 50*ones(1,n_conditions); 123 | % X = -15:15; 124 | % CosIntensity = cos((pi/2)*X/15); 125 | % N_list(66:(66+30)) = N_list(66:(66+30)) - round(34*CosIntensity); 126 | % N_list(161:(161+30)) = N_list(161:(161+30)) + round(67*CosIntensity); 127 | % Tau_list = 1.5*ones(1,n_conditions); 128 | % Tau_list(66:(66+30)) = 0.5; 129 | % Tau_list(161:(161+30)) = 3.5; 130 | 131 | N_list = 50*ones(1,n_conditions); 132 | N_list(20) = 5000; 133 | N_list(40) = 50000; 134 | Tau_list = 2.5*ones(1,n_conditions); 135 | 136 | 137 | end 138 | 139 | % Generate the IRF curve ----------------------------------------------------- 140 | [ t, Phot_number_IRF ] = SimDecayPhotonCount_Multiple( Sim_param, 0, N_irf, 1); 141 | 142 | TCSPC_image = zeros(2^n, n_repeats, n_conditions); 143 | for i = 1:n_conditions 144 | waitbar(i / n_conditions); 145 | [ t, Phot_number ] = SimDecayPhotonCount_Multiple( Sim_param, Tau_list(i), N_list(i), n_repeats ); 146 | TCSPC_image(:,:,i) = Phot_number; 147 | end 148 | toc 149 | 150 | if max(Phot_number_IRF(:)) >= 2^16 151 | disp('IRF DATA RESCALED!!'); 152 | Phot_number_IRF = (2^16-1)*Phot_number_IRF/max(Phot_number_IRF(:)); 153 | end 154 | 155 | if max(TCSPC_image(:)) >= 2^16 156 | disp('IMAGE DATA RESCALED!!'); 157 | TCSPC_image = (2^16-1)*TCSPC_image/max(TCSPC_image(:)); 158 | end 159 | 160 | Phot_number_IRF = uint16(Phot_number_IRF); 161 | TCSPC_image = uint16(TCSPC_image); 162 | close(h_wait); 163 | 164 | % Save the data as tif stack 165 | dt = 1000*T/2^n; % in ps 166 | if Save_ON == 1 167 | if (exist(Folder_for_Save, 'dir') == 0) 168 | mkdir(Folder_for_Save); 169 | end 170 | SaveAsOMETIFF( permute(Phot_number_IRF,[2,3,1]), [Folder_for_Save, '\', 'IRF Stack', FileName_append], dt); 171 | SaveAsOMETIFF( permute(TCSPC_image,[2,3,1]), [Folder_for_Save, '\', 'Data Stack', FileName_append], dt); 172 | 173 | % SaveTIFFStack( Phot_number_IRF, ['IRF Stack',FileName_append], Folder_for_Save, SaveMethod, dt); 174 | % SaveTIFFStack( TCSPC_image, ['Data Stack', FileName_append], Folder_for_Save, SaveMethod, dt); 175 | end 176 | 177 | 178 | % ------------------------------------------------------------------------ 179 | 180 | Decay_display = reshape(TCSPC_image(:,1,:),2^n,n_conditions); 181 | 182 | figure('Color','white','Units','normalized','position',[0.2 0.1 0.5 0.8],'name','IRF decay plot'); 183 | subplot(2,1,1) 184 | plot(t,Phot_number_IRF); % display the first of all the repeats 185 | xlabel 'Time (ns)' 186 | ylabel 'Photon counts' 187 | subplot(2,1,2) 188 | semilogy(t,Phot_number_IRF); % display the first of all the repeats 189 | xlabel 'Time (ns)' 190 | ylabel 'Photon counts' 191 | 192 | figure('Color','white','Units','normalized','position',[0.2 0.1 0.5 0.8],'name','Decay plots'); 193 | subplot(2,1,1) 194 | plot(t,Decay_display); % display the first of all the repeats 195 | xlabel 'Time (ns)' 196 | ylabel 'Photon counts' 197 | 198 | subplot(2,1,2) 199 | semilogy(t,Decay_display); % display the first of all the repeats 200 | xlabel 'Time (ns)' 201 | ylabel 'Photon counts' 202 | 203 | disp('------------------------'); 204 | disp('All done.') 205 | 206 | --------------------------------------------------------------------------------