A 分帧

A1 简单分帧

A1-1 帧数目计算与补零

A1-2 帧划分实现

A1-3 从采样点位置倒推帧位置

A2 有重叠窗

A2-1 帧数目计算与补零

A2-2 帧划分实现

A2-3 从采样点位置倒推帧位置

A2-4 从所有帧逐段合成所有采样点数据

另一种方法就是为每帧的数据叠加上一个汉明窗后,并一段段地加到空白序列上。唯一可惜的地方就是各采样点之间没有标准化。还是得靠每个采样点位置的汉明窗之和来进行标准化。

samples_num = (len(frames) - 1) * hop_length + frame_length
h_signal = np.zeros(samples_num, dtype=np.float64)
hamming_window = np.hamming(frame_length)
for m in range(len(frames)):
    begin_sample = m * hop_length
    oend_sample = begin_sample + frame_length
    h_signal[begin_sample:oend_sample] += h_frames[m] * hamming_window
# if standardation needed
for n in range(samples_num):
    h_signal[n] /= frame_profile_of_samples[n]['hamming'].sum()

A3 中心窗口

# 此方法使用 ChatGPT o1-mini 模型辅助产出。
def get_center_frames(x: np.ndarray, start_sample: int, hop_sample: int, half_frame_len: int, pad_type: str='zero', axis: int=-1):
    """
    提取信号 x 以 start_sample 为起点、hop_sample 为跳距、half_frame_len 为半长度的帧。对超出部分进行必要的填充。

    支持 x 为多维信号,这时将在指定的第 axis 轴进行切割。

    参数:
    - x (np.ndarray): 输入的多维信号数组。
    - start_sample (int): 第一个帧的中心位置索引。
    - hop_sample (int): 帧之间的跳距。
    - half_frame_len (int): 窗口半长度,窗口长度为 2 * half_frame_len + 1。
    - pad_type (str): 填充类型,'zero' 表示补零,'mirror' 表示镜像填充。
    - axis (int): 要切帧的轴,默认为最后一轴。

    返回:
    - frames (np.ndarray): 提取的帧,形状为 x.shape[:axis] + (n_frames, 2 * half_frame_len + 1) + x.shape[axis+1:]。
    """
    if not isinstance(x, np.ndarray):
        raise TypeError("输入 x 必须是 NumPy 数组。")
    if x.ndim < 1:
        raise ValueError("输入 x 至少应为一维。")
    if pad_type not in ['zero', 'mirror']:
        raise ValueError("pad_type 必须是 'zero' 或 'mirror'。")
    if not (-x.ndim <= axis < x.ndim):
        raise ValueError(f"axis 必须在 {-x.ndim} 到 {x.ndim - 1} 之间,当前为 {axis}。")
    if start_sample < 0:
        raise ValueError(f"start_sample 必须大于等于 0,当前为 {start_sample}。")
    if hop_sample <= 0:
        raise ValueError(f"hop_sample 必须大于 0,当前为 {hop_sample}。")

    # 规范化 axis
    axis = axis % x.ndim

    # 计算帧宽度
    frame_length = 2 * half_frame_len + 1

    # 计算帧总数
    num_frames = (x.shape[axis] - start_sample + hop_sample - 1) // hop_sample
    if num_frames <= 0:
        raise ValueError("给定参数下没有可提取的帧。")

    # 计算填充宽度
    pad_width = [(0, 0)] * x.ndim
    pad_width[axis] = (half_frame_len, half_frame_len)

    # 选择填充模式
    if pad_type == 'zero':
        x_padded = np.pad(x, pad_width, mode='constant', constant_values=0)
    elif pad_type == 'mirror':
        x_padded = np.pad(x, pad_width, mode='symmetric')

    slicer = [slice(None)] * x.ndim
    slicer[axis] = slice(start_sample, start_sample + hop_sample * (num_frames-1) + frame_length)
    slicer = tuple(slicer)

    x_neated = x_padded[slicer]
    
    frames = np.lib.stride_tricks.as_strided(
        x_neated,
        shape = x_neated.shape[:axis] + (num_frames, frame_length) + x_neated.shape[axis+1:],
        strides = tuple(x_neated.strides[:axis] + (hop_sample * x_neated.strides[axis], x_neated.strides[axis]) + x_neated.strides[axis+1:])
    )
    
    return frames

B 加窗

B1 汉明窗、汉宁窗

C 光滑函数