-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcombine_input.m
455 lines (314 loc) · 12.6 KB
/
combine_input.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
%
% combine_input.m
%
% White noise input can be used to show that an oscillatory network of LIF
% neurones will tend to respond best when, by chance, there is an
% oscillatory component to the random input. In other words, the
% integration kernel, or transfer function is revealed. This can be seen in
% the spike-triggered average of the input.
%
% Here, we test the hypothesis that different STA patterns might tell us
% about how two distinct sources of input are combined by a population of
% neurones. Three mechanisms are considered:
%
% 1) Non-overlapping input. Each input targets a unique set of excitatory
% neurones.
% 2) Summation. The average of the two inputs is fed to all excitatory
% neurones.
% 3) Multiplication. The geometric average of the two inputs is fed to
% all excitatory neurones.
%
% In addition to varying the mechanism that the network uses to combine
% input, we can also vary what type of input is provided:
%
% A) Uniformly distributed white noise. Two independent streams of noise
% are generated. Each is sampled from a uniform distribution.
% B) Gaussian distributed white noise. Each input stream is independently
% sampled from a Gaussian distribution.
% C) Sinusoidal. Each input is a sine wave. We can systematically vary
% the relative phase of the two inputs.
% D) Combination. One input is sinusoidal, the other is white noise.
%
% Each type of input is tested using each method of combination. Every
% unique pairing of type and method results in a set of STA plots in a 3 by
% 3 arrangement of panels. Each panel plots STAs. Each row of panels show
% STAs for different methods of combination (1-3). Columns show STAs
% computed from different combinations of the input. Col 1 shows STAs
% separately for each input, Col 2 shows the STA of the averaged input, and
% Col 3 shows the STA of the geometric mean of the input. For row 1, non-
% overlapping input, separate STAs are computed for each sub-set of
% excitatory neurones.
%
% LIF Network parameters aim to replicate those used in Lewis CM, Ni
% J, Wunderle T, Jendritza P, Lazar A, Diester I, & Fries P. (2020).
% "Cortical resonance selects coherent input." bioRxiv:
% 2020.2012.2009.417782.
%
% Written by Jackson Smith - April 2021 - ESI (Fries Lab)
%
%%% CONSTANTS %%%
% Output directory
OUTDIR = 'C:\Users\smithj\Analysis\Modelling\STA\' ;
% Save figures to PDF file flag, true for save and false for no save.
PDFFLG = true ;
% Duration of input current, in milliseconds
DURONI_MS = 500000 ;
% Half-width of STA, in milliseconds
STAWID_MS = 100 ;
% Input combination method names
INCOMB = { 'Non-overlapping' , 'Summation' , 'Multiplication' } ;
%%% Preparation %%%
% Generate a default network
N = lif( 'network' ) ;
% Point to constants
C = N.C ;
% Convert simulation length from ms to samples
DURONI = ceil( DURONI_MS / C.dt ) ;
% Convert half STA width from ms to samples
STAWID = ceil( STAWID_MS / C.dt ) ;
% Time bin locations in STA at network's sampling rate
timsta = ( -STAWID : +STAWID )' .* C.dt ;
% Allocate matrix of input currents. Each row is a separate time series.
% Columns span time bins.
I = zeros( 2 , DURONI ) ;
%%% Uniform white noise %%%
% Input name
iname = 'Uniform white noise' ;
% Generate two input currents
[ I( 1 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'noise' , [ ] ) ;
[ I( 2 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'noise' , [ ] ) ;
% Evaluate using each method of input combination
sta = runsim( INCOMB , STAWID_MS , iname , N , I ) ;
% Plot and save result
plotsta( OUTDIR , PDFFLG , INCOMB , iname , timsta , sta )
%%% Gaussian white noise %%%
% Input name
iname = 'Gaussian white noise' ;
% Generate two input currents
[ I( 1 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'norm' , [ ] ) ;
[ I( 2 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'norm' , [ ] ) ;
% Evaluate using each method of input combination
sta = runsim( INCOMB , STAWID_MS , iname , N , I ) ;
% Plot and save result
plotsta( OUTDIR , PDFFLG , INCOMB , iname , timsta , sta )
%%% Orthogonal sinusoids %%%
% Input name
iname = 'Sinusoids orthogonal' ;
% Common input parameters, initialise for input 1
par = [ 0 , 1.5 , 40 , 0 ] ;
% Generate input current 1
[ I( 1 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'sine' , par ) ;
% Advance input 2 by pi/2 i.e. 90 degrees
par( 4 ) = pi / 2 ;
[ I( 2 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'sine' , par ) ;
% Evaluate using each method of input combination
sta = runsim( INCOMB , STAWID_MS , iname , N , I ) ;
% Plot and save result
plotsta( OUTDIR , PDFFLG , INCOMB , iname , timsta , sta )
%%% Inverted sinusoids %%%
% Input name
iname = 'Inverted sinusoids' ;
% Common input parameters, initialise for input 1
par = [ 0 , 1.5 , 40 , 0 ] ;
% Generate input current 1
[ I( 1 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'sine' , par ) ;
% Advance input 2 by pi i.e. 180 degrees
par( 4 ) = pi ;
[ I( 2 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'sine' , par ) ;
% Evaluate using each method of input combination
sta = runsim( INCOMB , STAWID_MS , iname , N , I ) ;
% Plot and save result
plotsta( OUTDIR , PDFFLG , INCOMB , iname , timsta , sta )
%%% Sinusoid plus uniform white noise %%%
% Input name
iname = 'Sine plus uni noise' ;
% Generate input current 1 - Default sinusoid
[ I( 1 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'sine' , [ ] ) ;
% Generate input 2 - Uniform white noise
[ I( 2 , : ) , N ] = lif( 'input' , N , 0 , DURONI_MS , 'noise' , [ ] ) ;
% Evaluate using each method of input combination
sta = runsim( INCOMB , STAWID_MS , iname , N , I ) ;
% Plot and save result
plotsta( OUTDIR , PDFFLG , INCOMB , iname , timsta , sta )
%%% DONE %%%
% Clear workspace
clearvars
%%% Script-specific functions %%%
% Compute full set of STAs for each combination method using this network
% and set of input. Returns sta, a 3 x 3 cell array containig STAs. Each
% cell contains a Time x Type array of STA values, with rows spanning time
% bins and columns spanning type of STA. In column 1 of sta, nested arrays
% always have column order [ input 1 STA , input 2 STA ]. All others are
% column vectors averaged across all excitatory neurones, except in row 1,
% where the column order is [ input 1 population , input 2 population ]
% containing STAs computed separately for each set of neurones with
% non-overlapping input (between sets).
function sta = runsim( INCOMB , w , iname , N , I )
% Report
fprintf( 'Running simulations for input type: %s\n' , iname )
% Point to network constants
C = N.C ;
% Allocate sta to accumulate output
sta = cell( 3 ) ;
% Row counter
row = 0 ;
% Input combination mechanisms
for M = INCOMB , m = M{ 1 } ; row = row + 1 ;
% Report
fprintf( ' %s:' , m )
% Set STA flag saying we should group neurones by type
avgflg = 'type' ;
% Combine input, returns combination in c.
switch m
case 'Non-overlapping'
% Compute STA separately for each neurone
avgflg = 'each' ;
% Allocate a separate input current time series for each neurone in
% the network
c = zeros( C.N , size( I , 2 ) ) ;
% Copy input 1 to set 1, and input 2 to set 2
for n = 1 : 2 : C.N , c( n , : ) = I( 1 , : ) ; end
for n = 2 : 2 : C.N , c( n , : ) = I( 2 , : ) ; end
% I* triggers their computation
Isum = [ ] ;
Igeo = [ ] ;
case 'Summation'
% Take the average of the two inputs
c = mean( I , 1 ) ;
% Point to this for STA, empty Igeo triggers its computation
Isum = c ;
Igeo = [ ] ;
case 'Multiplication'
% Geometric mean of two inputs
c = sqrt( prod( I , 1 ) ) ;
% Point to this for STA, empty Isum signals its computation
Isum = [ ] ;
Igeo = c ;
end % combo input
% Run simulation
S = lif( 'sim' , N , c , false ) ;
%- Compute STA for each input -%
% Separately for each input
fprintf( ' Separate' )
sta{ row , 1 } = [ getsta( N , I( 1 , : ) , S , w , avgflg ) , ...
getsta( N , I( 2 , : ) , S , w , avgflg ) ] ;
% Compute summation of inputs?
if isempty( Isum ) , Isum = mean( I , 1 ) ; end
% Take STA from average input
fprintf( ', Average' )
sta{ row , 2 } = getsta( N , Isum , S , w , avgflg ) ;
% Compute product of inputs?
if isempty( Igeo ) , Igeo = sqrt( prod( I , 1 ) ) ; end
% Take STA from geo mean input
fprintf( ', GeoMean\n' )
sta{ row , 3 } = getsta( N , Igeo , S , w , avgflg ) ;
end % mechanisms
end % runsim
% Calculate STA across all excitatory units, or separately for each sub-set
function A = getsta( N , I , S , w , avgflg )
% Compute STAs
A = lif( 'sta' , N , I , S , w , avgflg ) ;
% Extract STA from A
switch avgflg
% Across all excitatory
case 'type' , A = A( 1 , : )' ;
% Separately for each sub-set of neurones
case 'each'
A = [ mean( A( N.e( 1 : 2 : end ) , : ) , 1 ) ;
mean( A( N.e( 2 : 2 : end ) , : ) , 1 ) ]' ;
end % extract
end % getsta
% Generates plot of the STAs
function plotsta( OUTDIR , PDFFLG , INCOMB , iname , t , sta )
% Axes parameters
AXPARS = { 'XTick' , -60 : 20 : +60 , 'XTickLabel' , [ ] } ;
% Type of STA
STATYP = { 'Input 1 & 2' , 'Average input' , 'Geo.mean input' } ;
% Find data points to throw away when computing y-axis limits
nyi = abs( t ) <= 0.5 ;
% Allocate axis limits
ylims = cell( size( sta ) ) ;
% Rows
for r = 1 : size( sta , 1 )
% Concatenate all STAs together
X = [ sta{ r , : } ] ;
% Discard data points
X( nyi , : ) = [ ] ;
% Turn into a vector
X = X( : ) ;
% Determine y-limit based on max and min values
y = [ min( X ) , max( X ) ] ;
% Expand range by 10%, equally up and down
y = 1.1 * diff( y ) .* [ -0.5 , +0.5 ] + mean( y ) ;
% Copy into accumulator
ylims( r , : ) = repmat( { y } , 1 , size( sta , 2 ) ) ;
end % y-lims
% Thanks to column-major linear indexing, we need to take the transpose
% of sta and ylims so that we progress along each row.
sta = sta' ;
ylims = ylims' ;
% Determine name of PDF file
fignam = fullfile( OUTDIR , [ iname , '.pdf' ] ) ;
% Pre-configured figure that is approximately A4
fig = makfig( -0.95 ) ;
% Panels
for pix = 1 : numel( sta )
% New panel
ax = makax( subplot( 3 , 3 , pix ) , AXPARS{ : } ) ;
% Use default x-axis limit
ax.XLim = [ -60 , +60 ] ;
% Use measured y-axis limits
ax.YLim = ylims{ pix } ;
% Plot STAs
h = plot( ax , t , sta{ pix } , 'k' , 'LineWidth' , 1 ) ;
%- Special cases -%
% Computed for each sub-set of units, and for each set of inputs.
if pix == 1
% Make each input a different colour.
set( h( 3 : 4 ) , 'Color' , ax.ColorOrder( 1 , : ) )
% And then make population 2 a different texture
set( h( [ 2 , 4 ] ) , 'LineWidth' , 0.5 )
% Computed separately for each subset of neurones
elseif pix <= 3
% And then make population 2 a different texture
set( h( 2 ) , 'LineWidth' , 0.5 )
% Computed for each separate input
elseif numel( h ) == 2
% Make each input a different colour.
set( h( 2 ) , 'Color' , ax.ColorOrder( 1 , : ) )
end % special cases
% Labels
% Top panels tell us what type of STA it is
if pix <= 3 , title( ax , STATYP{ pix } ) , end
% Bottom, left panel has axis labels
if pix == 2 * 3 + 1
ax.XTickLabel = ax.XTick ;
xlabel( 'Time from spike (ms)' )
ylabel( 'STA (nA)' )
end
% Not end of row, to next panel
if mod( pix , 3 ) , continue , end
% Row number
r = pix / 3 ;
% Add label that tells us the combination mechanism
text( ax , ax.XLim( 2 ) , mean( ax.YLim ) , INCOMB{ r } , ...
'FontSize' , 12 , 'Rotation' , 90 , ...
'HorizontalAlignment' , 'center' , ...
'VerticalAlignment' , 'top' )
end % panels
% Switch focus to top-left panel
ax = subplot( 3 , 3 , 1 ) ;
% Get title object
h = ax.Title ;
% Bottom location of string
y = sum( h.Extent( [ 2 , 4 ] ) ) ;
% Print type of input
text( ax , ax.XLim( 1 ) , y , iname , 'FontSize' , 14 , ...
'VerticalAlignment' , 'bottom' )
% Show progress
drawnow
% Print figure to PDF file
if PDFFLG
print( fig , '-bestfit' , '-dpdf' , '-painters' , fignam )
end
end % plotsta