dicklyon@619
|
1 function layer_struct = SAI_StabilizeLayer(layer_struct)
|
dicklyon@619
|
2 % Pick trigger points in buffer, shift rows to offset_from_end,
|
dicklyon@619
|
3 % and blend into frame
|
dicklyon@619
|
4
|
dicklyon@619
|
5 frame = layer_struct.frame;
|
dicklyon@619
|
6
|
dicklyon@619
|
7 nap_buffer = real(layer_struct.nap_buffer);
|
dicklyon@619
|
8 n_buffer_times = size(nap_buffer, 1);
|
dicklyon@619
|
9 [n_ch, width] = size(frame);
|
dicklyon@619
|
10
|
dicklyon@619
|
11 % Make the window to use for all the channels at this layer.
|
ronw@675
|
12 window_width = layer_struct.window_width;
|
dicklyon@619
|
13 n_window_pos = layer_struct.n_window_pos;
|
dicklyon@619
|
14 % Windows are always (approx) 50% overlapped:
|
ronw@675
|
15 window_hop = window_width / 2;
|
dicklyon@619
|
16
|
ronw@675
|
17 window = sin((1:window_width)' * pi / window_width);
|
ronw@675
|
18 window_start = (n_buffer_times - window_width) - ...
|
ronw@675
|
19 floor((n_window_pos - 1) * window_hop);
|
ronw@675
|
20 window_range = (1:window_width) + window_start - layer_struct.future_lags;
|
dicklyon@619
|
21 % This should not go negative!
|
ronw@675
|
22 offset_range = (1:width) + window_start - width;
|
dicklyon@619
|
23 % CHECK
|
dicklyon@619
|
24 if any(offset_range < 0)
|
dicklyon@619
|
25 error;
|
dicklyon@619
|
26 end
|
dicklyon@619
|
27
|
dicklyon@619
|
28 % smooth across channels; more in later layers
|
ronw@700
|
29 smoothed_buffer = smooth1d(nap_buffer', layer_struct.channel_smoothing_scale)';
|
dicklyon@619
|
30
|
dicklyon@619
|
31 % For each buffer column (channel), pick a trigger and align into SAI_frame
|
dicklyon@619
|
32 for ch = 1:n_ch
|
dicklyon@619
|
33 smooth_wave = smoothed_buffer(:, ch); % for the trigger
|
dicklyon@619
|
34
|
dicklyon@619
|
35 % Do several window positions and triggers
|
dicklyon@619
|
36 for w = 1:n_window_pos
|
ronw@675
|
37 % move the window to later and go again
|
ronw@675
|
38 current_window_offset = floor((w - 1) * window_hop);
|
ronw@675
|
39 [peak_val, trigger_time] = ...
|
ronw@675
|
40 max(smooth_wave(window_range + current_window_offset) .* window);
|
dicklyon@619
|
41 nap_wave = nap_buffer(:, ch); % for the waveform
|
dicklyon@619
|
42 if peak_val <= 0 % just use window center instead
|
dicklyon@619
|
43 [peak_val, trigger_time] = max(window);
|
dicklyon@619
|
44 end
|
ronw@675
|
45 trigger_time = trigger_time + current_window_offset;
|
dicklyon@619
|
46 alpha = (0.025 + peak_val) / (0.5 + peak_val); % alpha 0.05 to near 1.0
|
dicklyon@619
|
47 frame(ch, :) = alpha * nap_wave(trigger_time + offset_range)' + ...
|
dicklyon@619
|
48 (1 - alpha) * frame(ch, :);
|
dicklyon@619
|
49 end
|
dicklyon@619
|
50 end
|
dicklyon@619
|
51
|
dicklyon@619
|
52 layer_struct.frame = frame;
|