【问题标题】:Efficient Rational Resampling with lazy semantics具有惰性语义的高效理性重采样
【发布时间】:2015-01-11 07:40:54
【问题描述】:

要改变信号的采样率,需要先上采样、滤波,然后下采样。天真地这样做意味着在输入信号中插入零,与滤波器的脉冲响应相关,然后丢弃除卷积的每个nth 样本之外的所有样本。

天真的方法的问题是有很多无用的计算。与滤波器进行卷积时,大部分滤波器抽头都乘以零,计算在下采样阶段将丢弃的样本值是无用的。这就是为什么高效的理性重采样使用多相滤波器组,其中只执行需要的计算。

我想知道是否可以使用惰性计算来避免无用的乘法,同时也避免显式构建多相滤波器组。我的理想解决方案类似于简单的方法(上采样,然后关联,然后下采样),但执行与显式多相滤波器方法相同的计算。

下采样很容易,因为不需要的值不会被计算。但我不知道如何避免相关部分中的零乘法。我想出的最好的方法是使用 Maybe 类型并使用 Nothing(而不是零)进行上采样:

upsample n xs = upsample2' n xs 0
    where upsample' _ [] _ = []
          upsample' _ (x:_) 0 = Just x : upsample' n xs n
          upsample' n xs counter = Nothing : upsample' n xs (counter - 1)

correlate xs ys = sum $ catMaybes $ zipWith (fmap . (*)) xs ys

firFilter taps signal = map (correlate taps) (tails signal)

downsample _ [] = []
downsample n (x:xs) = x : downsample n (drop (n-1) xs)

upfirdn up down taps = (downsample down).(fir_filter taps).(upsample up)

upfirdn 函数确实只是简单的方法,下采样中的惰性避免了计算,但我认为处理器仍然需要在相关步骤中检查值是否为Nothing

有没有办法利用惰性来节省与多相滤波器方法相同的计算量?如果不是,有什么根本原因不能做吗?

【问题讨论】:

    标签: haskell signal-processing lazy-evaluation resampling


    【解决方案1】:

    不需要上采样和下采样来重新采样。

    如果效率和性能不重要,您可以在新的等间距样本数组中的每个样本点通过简单的插值重新采样,然后重新计算(低通/抗锯齿)插值所需的相位或值每个新插值点的多项式(而不是预先计算和缓存在多相表中)。

    这也允许通过仅根据需要计算新样本来进行“延迟重采样”。

    在我的 DSP 博客上,有一个“快速而简单”的示例,说明如何使用基本计算的 von-Hann-Windowed-Sinc 插值内核来执行此操作: http://www.nicholson.com/rhn/dsp.html#3
    由于这只是在每个新样本点上的数组函数计算,因此将这个过程式 Basic 转换为函数式 Haskell 应该不会太难。

    【讨论】:

      【解决方案2】:

      我认为懒惰对这类问题没有帮助,原因有两个:

      • 在 Haskell 中,懒惰是通过在内存中构建未评估的 thunk 来实现的。这意味着惰性并不是完全免费的:您仍然需要承担创建 thunk 的成本。如果 thunk 的评估成本很高,则此成本可以忽略不计。

        但是,在您的情况下,对于每个 thunk,您都在为自己节省一个乘法和一个加法,这只是几个 CPU 指令。创建一个 thunk 的成本可能是相同的数量级。

      • 当您先验不知道将使用哪些元素时,惰性会很有帮助——通常是因为选择以某种复杂或未知的方式取决于输入/环境,所以您宁愿推迟以后再做决定。

        在您的情况下,您确切地知道将使用哪些元素:元素必须具有可被n 整除的索引。因此,仅遍历 [0, n, 2 * n, 3 * n, ...] 会更有效。


      添加惰性的一种天真的方法是定义一个惰性乘加操作:

      (+*) :: Num a => a -> (a, a) -> a
      z +* (_, 0) = z
      z +* (x, y) = z + x * y
      

      该操作有偏差,因此如果y 为零,则跳过计算。

      现在,当通过upsample 生成掩码时,无需使用Maybe:只需生成零而不是Nothing。然后,要计算总和,只需使用:

      correlate xs ys = foldl' (+*) 0 (zip xs ys)
      

      【讨论】:

      • 明白了。看起来使用惰性永远不会像自己构建多相滤波器组那样有效。但我仍然想知道是否可以使用懒惰,就像学术好奇心一样。
      • 添加了一种通过懒惰实现它的幼稚方式。
      猜你喜欢
      • 2014-08-02
      • 1970-01-01
      • 2022-11-16
      • 2022-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      • 2018-05-15
      相关资源
      最近更新 更多