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.
|
dicklyon@619
|
12 window_size = layer_struct.window_width;
|
dicklyon@619
|
13 n_window_pos = layer_struct.n_window_pos;
|
dicklyon@619
|
14 % Windows are always (approx) 50% overlapped:
|
dicklyon@619
|
15 d_win = window_size / 2;
|
dicklyon@619
|
16
|
dicklyon@619
|
17 after_samples = layer_struct.future_lags;
|
dicklyon@619
|
18
|
dicklyon@619
|
19 window_range = (1:window_size) + ...
|
dicklyon@619
|
20 (n_buffer_times - window_size) - after_samples - ...
|
dicklyon@619
|
21 floor((n_window_pos - 1) * d_win);
|
dicklyon@619
|
22 window = sin((1:window_size)' * pi / window_size);
|
dicklyon@619
|
23 % This should not go negative!
|
dicklyon@619
|
24 offset_range = (1:width) + ...
|
dicklyon@619
|
25 (n_buffer_times - width - window_size) - floor((n_window_pos - 1) * d_win);
|
dicklyon@619
|
26 % CHECK
|
dicklyon@619
|
27 if any(offset_range < 0)
|
dicklyon@619
|
28 error;
|
dicklyon@619
|
29 end
|
dicklyon@619
|
30
|
dicklyon@619
|
31 % smooth across channels; more in later layers
|
dicklyon@619
|
32 smoothed_buffer = smooth1d(nap_buffer', layer_struct.channel_smoothing_scale)';
|
dicklyon@619
|
33
|
dicklyon@619
|
34 % For each buffer column (channel), pick a trigger and align into SAI_frame
|
dicklyon@619
|
35 for ch = 1:n_ch
|
dicklyon@619
|
36 smooth_wave = smoothed_buffer(:, ch); % for the trigger
|
dicklyon@619
|
37
|
dicklyon@619
|
38 % Do several window positions and triggers
|
dicklyon@619
|
39 for w = 1:n_window_pos
|
dicklyon@619
|
40 % move the window to later and go aggain
|
dicklyon@619
|
41 [peak_val, trigger_time] = max(smooth_wave(window_range + ...
|
dicklyon@619
|
42 floor((w - 1) * d_win)) .* window);
|
dicklyon@619
|
43 nap_wave = nap_buffer(:, ch); % for the waveform
|
dicklyon@619
|
44 if peak_val <= 0 % just use window center instead
|
dicklyon@619
|
45 [peak_val, trigger_time] = max(window);
|
dicklyon@619
|
46 end
|
dicklyon@619
|
47 % TODO(dicklyon): alpha blend here.
|
dicklyon@619
|
48 trigger_time = trigger_time + floor((w - 1) * d_win);
|
dicklyon@619
|
49 alpha = (0.025 + peak_val) / (0.5 + peak_val); % alpha 0.05 to near 1.0
|
dicklyon@619
|
50 frame(ch, :) = alpha * nap_wave(trigger_time + offset_range)' + ...
|
dicklyon@619
|
51 (1 - alpha) * frame(ch, :);
|
dicklyon@619
|
52 end
|
dicklyon@619
|
53 end
|
dicklyon@619
|
54
|
dicklyon@619
|
55 layer_struct.frame = frame;
|