dicklyon@608: function layer_struct = SAI_StabilizeLayer(layer_struct) dicklyon@608: % Pick trigger points in buffer, shift rows to offset_from_end, dicklyon@608: % and blend into frame dicklyon@608: dicklyon@608: frame = layer_struct.frame; dicklyon@608: dicklyon@608: nap_buffer = real(layer_struct.nap_buffer); dicklyon@608: n_buffer_times = size(nap_buffer, 1); dicklyon@608: [n_ch, width] = size(frame); dicklyon@608: dicklyon@608: % Make the window to use for all the channels at this layer. dicklyon@608: window_size = layer_struct.window_width; dicklyon@608: n_window_pos = layer_struct.n_window_pos; dicklyon@608: % Windows are always (approx) 50% overlapped: dicklyon@608: d_win = window_size / 2; dicklyon@608: dicklyon@608: after_samples = layer_struct.future_lags; dicklyon@608: dicklyon@608: window_range = (1:window_size) + ... dicklyon@608: (n_buffer_times - window_size) - after_samples - ... dicklyon@608: floor((n_window_pos - 1) * d_win); dicklyon@608: window = sin((1:window_size)' * pi / window_size); dicklyon@608: % This should not go negative! dicklyon@608: offset_range = (1:width) + ... dicklyon@608: (n_buffer_times - width - window_size) - floor((n_window_pos - 1) * d_win); dicklyon@608: % CHECK dicklyon@608: if any(offset_range < 0) dicklyon@608: error; dicklyon@608: end dicklyon@608: dicklyon@608: % smooth across channels; more in later layers dicklyon@608: smoothed_buffer = smooth1d(nap_buffer', layer_struct.channel_smoothing_scale)'; dicklyon@608: dicklyon@608: % For each buffer column (channel), pick a trigger and align into SAI_frame dicklyon@608: for ch = 1:n_ch dicklyon@608: smooth_wave = smoothed_buffer(:, ch); % for the trigger dicklyon@608: dicklyon@608: % Do several window positions and triggers dicklyon@608: for w = 1:n_window_pos dicklyon@608: % move the window to later and go aggain dicklyon@608: [peak_val, trigger_time] = max(smooth_wave(window_range + ... dicklyon@608: floor((w - 1) * d_win)) .* window); dicklyon@608: nap_wave = nap_buffer(:, ch); % for the waveform dicklyon@608: if peak_val <= 0 % just use window center instead dicklyon@608: [peak_val, trigger_time] = max(window); dicklyon@608: end dicklyon@608: % TODO(dicklyon): alpha blend here. dicklyon@608: trigger_time = trigger_time + floor((w - 1) * d_win); dicklyon@608: alpha = (0.025 + peak_val) / (0.5 + peak_val); % alpha 0.05 to near 1.0 dicklyon@608: frame(ch, :) = alpha * nap_wave(trigger_time + offset_range)' + ... dicklyon@608: (1 - alpha) * frame(ch, :); dicklyon@608: end dicklyon@608: end dicklyon@608: dicklyon@608: layer_struct.frame = frame;