【问题标题】:Detect last zero-crossing检测最后的过零
【发布时间】:2022-11-18 03:03:50
【问题描述】:

我正在使用以下函数生成指数扫描:

@jit(nopython=True)
def generate_exponential_sweep(time_in_seconds, sr):
    time_in_samples = time_in_seconds * sr
    exponential_sweep = np.zeros(time_in_samples, dtype=np.double)
    for n in range(time_in_samples):
        t = n / sr
        exponential_sweep[n] = np.sin(
            (2.0 * np.pi * starting_frequency * sweep_duration)
            / np.log(ending_frequency / starting_frequency)
            * (np.exp((t / sweep_duration) * np.log(ending_frequency / starting_frequency)) - 1.0))
    
    number_of_samples = 50
    exponential_sweep[-number_of_samples:] = fade(exponential_sweep[-number_of_samples:], 1, 0)

    return exponential_sweep

现在正弦波并没有在零交叉处结束,所以为了避免这个问题,我设法制作了一个淡入淡出函数,它只是将音量淡化为零:

@jit(nopython=True)
def fade(data, gain_start,
         gain_end):
    gain = gain_start
    delta = (gain_end - gain_start) / (len(data) - 1)
    for i in range(len(data)):
        data[i] = data[i] * gain
        gain = gain + delta

    return data

问题是:

  1. 检测阵列中的最后一个过零并使正弦波在那里结束会更好/更快吗?
  2. 如果更好,怎么做?

【问题讨论】:

    标签: python audio acoustics


    【解决方案1】:

    由于 time_in_secondssrstarting_frequencyending_frequency 都是未知的,我们不能保证它会达到任何零甚至跨越它,而不给它们任何约束。正确执行此操作的唯一方法是使用具有已知频率行为的窗口(或淡入/淡出)。

    这排除了 1。我们可以继续 2。


    我会为这个任务建议一个锥形余弦窗口 - scipy.signal.windows.tukey - 它提供从 0 到 1 和 vv 的淡入/淡出,并且是音频任务的一个非常常见的选择。

    这方面的一个例子可以实现为 -

    import numpy as np
    import scipy
    
    def fade(data: np.ndarray, fade_time: float, sr: float) -> np.ndarray:
      alpha = sr * 2 * fade_time / len(data)
      window = scipy.signal.windows.tukey(len(data), alpha)
    
      return data * window
    

    生成的过滤器 - 淡入淡出时间为 0.1 秒 - 看起来像this

    要将其添加到您现有的代码中并简化它 -

    import numpy as np
    
    def generate_exponential_sweep(
        time_in_seconds: float, sr: float, starting_frequency: float, 
        ending_frequency: float, fade_time: float) -> np.ndarray:
      t = np.arange(0, time_in_seconds, 1/sr)
      
      exponential_sweep = np.sin(2 * np.pi * (
          starting_frequency * time_in_seconds * (
              (ending_frequency / starting_frequency) ** (t / time_in_seconds) - 1
              ) / np.log(starting_frequency / ending_frequency)
          )
      )
    
      exponential_sweep = fade(exponential_sweep, fade_time, sr)
    
      return exponential_sweep
    

    我们可以用 scipy.signal.chirp 替换创建扫描的整个块,它的作用完全相同 -

    import numpy as np
    import scipy
    
    def generate_exponential_sweep(
        time_in_seconds: float, sr: float, starting_frequency: float, 
        ending_frequency: float, fade_time: float) -> np.ndarray:
      t = np.arange(0, time_in_seconds, 1/sr)
      
      exponential_sweep = scipy.signal.chirp(
          t, f0=starting_frequency, f1=ending_frequency, 
          t1=time_in_seconds, method='logarithmic')
    
      exponential_sweep = fade(exponential_sweep, fade_time, sr)
    
      return exponential_sweep
    

    只是一般性评论 - 不要将变量作为参数和不混合。请全部包含在

    def generate_exponential_sweep(time_in_seconds, sr, starting_frequency, ending_frequency):
    ...
    

    【讨论】:

      猜你喜欢
      • 2016-10-23
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      • 2016-10-09
      • 1970-01-01
      • 1970-01-01
      • 2021-08-16
      相关资源
      最近更新 更多