不久前,我尝试了不同的方法来绘制数字波形,而我尝试做的一件事是,将幅度包络显示得更像示波器,而不是幅度包络的标准轮廓。这是示波器上正弦波和方波的样子:



天真的方法是:


在输出图像的每个水平像素中将音频文件划分为一个块
计算每个块的采样幅度直方图
通过亮度将直方图绘制为像素列

>它会生成如下内容:


如果每个块中有很多样本,并且信号的频率与采样频率无关,则此方法很好。例如,如果信号频率恰好是采样频率的整数倍,则采样将始终在每个周期中以完全相同的幅度发生,并且直方图将只是几个点,即使在这些点之间存在实际的重构信号也是如此。该正弦脉冲应与左上角一样平滑,但这不是因为它正好是1 kHz,并且采样始终出现在同一点附近:



尝试通过升采样来增加点数,但这并不能解决问题,只能在某些情况下帮助解决问题。连续重建信号的数字样本(幅度与时间)的关系(概率与幅度)。我不知道该使用什么算法。通常,函数的PDF是其逆函数的派生。

sin(x)的PDF:$ \ frac {d} {dx} \ arcsin x = \ frac {1} { \ sqrt {1-x ^ 2}} $

但是我不知道如何计算逆函数是多值函数的波,或者如何快速进行计算。将其分解为分支,计算每个的逆,取导数并将它们加在一起?但这很复杂,而且可能还有一种更简单的方法。它应该是环形的,但是因为它仅查看样本,而不考虑样本之间的插值点,所以KDE看起来更像是一个驼峰而不是一个圆环。如果样本是我们所知道的,那就是我们所能做的最好的。但是样本并不是我们所知道的。我们也知道样本之间有一条路径。对于GPS,没有像带限音频那样完美的Nyquist重建,但是基本思想仍然适用,插值函数有些猜测。

评论

您是否有感兴趣的多值函数示例?您可能必须沿着最适合您的物理数据的分支切割对其进行评估。

您对绘制此类图的方式是否更感兴趣,还是该图只是有关计算PDF的动机?

@yoda:好吧,上面的正弦波函数是通过仅取半个周期,求反并取导数来找到的,因为每个半周期的PDF与下一个相同。但是,要获得整个任意音频信号的值,您不能做那个假设。我认为您需要将其划分为“分支剪切”,依次获取每个PDF并将它们汇总在一起?

@datageist:嗯。我对绘制这种图的方式很感兴趣,但是这种图是PDF。产生相同或非常相似结果的快捷方式是可以的。

@endolith,哦,是的,我明白。真的只是一个关于强调的问题(即哪种捷径是合理的)。

#1 楼

内插至原始速率的几倍(例如8倍过采样)。这使您可以假设分段线性信号。与无限分辨率,波形的连续sin(x)/ x插值相比,此信号的误差很小。使用之间的所有值。这为您提供了一个从y1到y2的细水平切片,可以将其累积为任意分辨率PDF。每个矩形概率片都必须缩放到1 / nsamples区域。

即使在采样周期和波形之间存在基本关系的情况下,使用样本之间的线条而不是样本本身也可以防止出现“ spikey” PDF。

评论


$ \ begingroup $
我已经为线性插值直方图编写了一个函数,但这很狡猾。您知道与此相关的现有代码吗?
$ \ endgroup $
– Endolith
2011年10月7日,下午2:33

$ \ begingroup $
即使没有过采样,线性内插对于大多数波形也有很大的不同。现在,1 kHz正弦看上去最像997 Hz正弦。现在,采样值不再只是水平线,而是它们之间的水平色带。通过过采样,也可以平滑条带。通过FFT重采样以及与相邻块的一些重叠,我应该能够使其达到真实的采样间峰值。不过,我需要使内插直方图代码更快。
$ \ endgroup $
– Endolith
2011年10月10日18:00



$ \ begingroup $
为此,我完全重写了我的脚本,并且我认为这次我得到了直方图和抗锯齿:gist.github.com/endolith/652d3ba1a68b629ed328
$ \ endgroup $
– Endolith
15年7月16日在2:28

$ \ begingroup $
最新版本位于github.com/endolith/scopeplot
$ \ endgroup $
– Endolith
19年7月26日在13:59

#2 楼

实际上,我要用的是Jason R的“随机重采样器”,它依次是yoda随机采样的基于预采样信号的实现。
每两个样本。对于原始的合成声音(从饱和的,无带宽限制的方形信号+偶次谐波衰减到正弦),它看起来像这样:更高采样率的版本,



和具有相同采样率但没有插值的怪异版本。 />这种方法的显着伪像是方形区域中的过冲,但这实际上是经过正弦滤波的信号(如我所说,我的信号没有带宽限制)的PDF也会看起来像并且代表感知到的响度如果是音频信号,则比峰值好得多。

代码(Haskell):

cubInterpolate vll vl v vr vrr vrrr x
    = v*lSpline x + vr*rSpline x
      + ((vr-vl) - (vrr-vll)/4)*ldSpline x
      + ((vrr-v) - (vrrr-vl)/4)*rdSpline x
     where lSpline x = rSpline (1-x)
           rSpline x = x*x * (3-2*x)
           ldSpline x = x * (1 + x*(x-2))
           rdSpline x = -ldSpline (1-x)

                   --  rand list   IN samples  OUT samples
stochasticAntiAlias :: [Double] -> [Double] -> [Double]
stochasticAntiAlias rs (lsll:lsl:lsc:lsr:lsrr:[]) = []
stochasticAntiAlias (r:rLst) (lsll:lsl:lsc:lsr:lsrr:lsrrr:t)
    = ( cubInterpolate lsll lsl lsc lsr lsrr lsrrr r )
          : stochasticAntiAlias rLst (lsll:lsl:lsc:lsr:lsrr:lsrrr:t)


rand list是随机变量列表范围[0,1]。

评论


$ \ begingroup $
看起来很棒。 +1为Haskell代码。
$ \ endgroup $
–datageist♦
2011年9月12日15:09

$ \ begingroup $
是的,它应该超出样本值。我实际上还计划为每个像素列都设置一个峰值,可能基于最大的样本间峰值而不是仅基于最大的样本而绘制不同。 flic.kr/p/7QAScX之类的波形说明了为什么这样做是必要的。
$ \ endgroup $
– Endolith
2011年9月12日在20:37

$ \ begingroup $
“高采样版本”是指它已经被高采样了,但是仍然被统一采样了?那就是蓝点?
$ \ endgroup $
– Endolith
2011年9月16日在16:05



$ \ begingroup $
@endolith首先,它只是以较高的采样率计算出的原始波形。本质上,像蓝点一样,代表以192 kHz采样的声音,而最下层的黄点则代表天真地完成24 kHz的降采样。上面的黄点是此点的随机AntiAlias。但是,在两种情况下,较高采样率的版本确实是统一速率。
$ \ endgroup $
–leftaround关于
2011-09-16 23:21

#3 楼

尽管您的方法在理论上是正确的(并且对于非单调函数需要稍作修改),但是很难计算泛型函数的逆函数。正如您所说,您必须处理分支点和分支剪切,这是可行的,但您真的不想这么做。

正如您已经提到的,常规采样对相同的点集进行采样,因此,在不采样的区域(即使满足奈奎斯特标准),很容易受到估计不佳的影响。在这种情况下,较长时间的采样也无济于事。

通常,在处理概率密度函数和直方图时,从随机抽样的角度考虑要比常规抽样的想法要好得多(请参阅链接的答案以获取简介)。通过随机抽样,可以确保每个点被“命中”的可能性均等,并且是估计pdf的更好方法。

下面是一个示例:考虑函数$ f(x)= \ sin(20 \ pi x)+ \ sin(100 \ pi x)$。现在,如果我使用采样频率$ f_s = 1000 $ Hz(奈奎斯特频率,$ f_N = 100 $ Hz)对此进行采样,则得到的概率密度为左侧的图(-2和2之间的401个等距间隔)。我采样10秒还是100都没关系。它仍然保持不变。另一方面,以每秒$ 1000 $个样本(均匀分布)的速率随机采样(我在这里不使用Hz,因为这意味着不同的含义),持续30秒可以得出右侧的图(相同的合并)。

您可以轻松地看到,尽管它很吵,但它比实际的PDF更好,比右边的PDF更近似,后者在多个间隔中显示零,而在另一些间隔中显示大错误。通过延长观察时间,您可以减小右侧观察值中的差异,最终在大观察值的范围内收敛到精确的PDF(黑色虚线)。



评论


$ \ begingroup $
“很难计算一个泛型函数的逆”嗯,这不是一个函数,而是一系列样本,因此找到逆只是在交换样本的x和y坐标,然后然后重新采样以适应新的坐标系。反正我无法更改采样。我们正在谈论使用统一采样创建的预先存在的数据。
$ \ endgroup $
– Endolith
2011-09-10 3:39



#4 楼

内核密度估计

估计波形PDF的一种方法是使用内核密度估计器。

这将获取所有样本$ x(n)$和一个内核函数(例如高斯函数),$ K(\ mathrm {x})$并将其与$ \ delta(\ mathrm {x}-x(n))$(狄拉克三角洲)卷积以得出PDF的估算值, $ \ hat {P} $:

$$ \ hat {P}(\ mathrm {x})= \ sum_ {n = 0} ^ NK(\ mathrm {x}-x(n ))$$


更新:有趣的附加信息。

假设您有信号$ x(n)$为$ n = 0,1,...,N-1 $,那么---正如您所说的---您也可以其DFT $ X(k)$:

$$ X(k)= \ sum_ {n = 0} ^ {N-1} x(n)e ^ {-\ jmath 2 \ pi nk / N} $$

所以$ X(k)$是$ e ^ {\ jmath 2 \ pi nk / N} $的系数:

$ $ x(n)= \ frac {1} {N} \ sum_ {k = 0} ^ {N-1} X(k)e ^ {\ jmath 2 \ pi nk / N} $$

因此,您可能会想到将每个Fourier组件的所有PDF一起卷积:

$$ | X(k)| \ frac {1} {\ sqrt {1-x ^ 2}} $$

但是,这并未考虑$ X(k)$的相位对(或不)贡献的方式。 $ x(n)$中的加法。

需要更多思考!

评论


$ \ begingroup $
我想到了这一点,但是密度估计用于估计未知的概率密度函数。由于有奈奎斯特采样定理,因此整个波形是准确已知的,确切的概率密度函数也应该是已知的。如果可以在速度与准确性之间进行权衡,我可以估算一下,但是必须有一种方法可以从中获得实际的PDF。类似地,可以通过在每个样本上放置一个Sinc函数并将它们相加来生成重构波形。可以使用sinc函数的PDF作为内核来创建PDF吗?我认为它不是那样的。
$ \ endgroup $
– Endolith
2011-09-8 20:26



$ \ begingroup $
就像,我不认为这可以解决信号采样是采样频率的整数倍的问题。它没有考虑样本之间的重构波形,对吗?它只是模糊了PDF中的每个点以尝试填补空白。尝试对GPS轨迹进行内核密度估算时,我遇到了类似的问题,因为它没有考虑样本之间的值。
$ \ endgroup $
– Endolith
2011年9月8日在20:34

#5 楼

正如您在评论中指出的那样,能够仅使用样本和内插带限信号的sinc函数的PDF来计算重构信号的直方图将很有吸引力。不幸的是,我认为这是不可能的,因为Sinc的直方图并没有信号本身具有的所有信息。遇到每个值的时域位置上的所有信息都会丢失。这使得无法对Sinc的缩放和延时版本的总和建模,这是您想要的,以便在不实际执行信号的情况下计算信号的“连续”或上采样版本的直方图向上采样。

我认为插值是最好的选择。您确实指出了几个使您不想这样做的问题,我认为可以解决:计算费用:当然,这始终是一个相对的问题,具体取决于您要用于此的特定应用程序。根据您发布到已收集的效果图库的链接,我假设您要执行此操作以可视化音频信号。无论您是对实时应用程序还是脱机应用程序感兴趣,我都建议您为高效的插值器设计原型,并查看它是否真的太昂贵。多相重采样是一种灵活的好方法(您可以使用任何理性因子)。
对与采样频率有合理关系的周期性成分的偏见:虽然无法完全消除这一点,但您应该能够通过“奇怪”因子进行插值来缓解这种情况:代替以4进行上采样,请尝试71/18(只是一个例子)。这将是一个稍微复杂的结构,但是仍然可以有效地实现。这将使您在具有与采样率相关的频率的各个分量周期中的采样分布更加均匀。或者,使用重采样方案,该方案允许您选择任意的重采样比率,然后按(大约)无理数重新采样,例如$ \ pi $。可以使用Farrow插值器(使用多项式插值)有效地完成此操作。


评论


$ \ begingroup $
但是,如果波形为44.1 /πkHz,该怎么办? :)不过,这是个好建议。是否有随机重采样之类的东西?或说真的,我想最好的方法是对样本进行不均匀的重新采样,以使新样本完全适合y维度的分箱,而不是均匀地分布于x维度。不确定是否有办法
$ \ endgroup $
– Endolith
2011年9月11日14:22

$ \ begingroup $
您可以使用Farrow结构轻松实现“随机”重采样器。这种方案允许通过使用多项式(通常为三次)进行插值来实现任意小数采样延迟。您可以维护一个样本间相位累加器,类似于NCO中使用的累加器,对于每个输出(重采样)样本,该采样累加器会以采样间隔的伪随机分数递增。累加器的值用作Farrow插值器的输入,定义每个输出的分数延迟量。
$ \ endgroup $
–Jason R
2011年9月12日下午0:05

$ \ begingroup $
嗯,要澄清一下,Farrow只是常规旧多项式插值的处理器/内存优化版本?
$ \ endgroup $
– Endolith
2011年9月12日20:57在

$ \ begingroup $
是的。这只是实现基于多项式的任意分数延迟的有效结构。
$ \ endgroup $
–Jason R
2011年9月13日下午2:31

$ \ begingroup $
但是,三次插值只是一个近似值。我想知道真实的样本间峰值,但在极端峰值下似乎无法正常工作:stackoverflow.com/questions/1851384/…实际上,似乎是一个具有[...,-1, 1,-1,1,1,-1,1,-1,...]会产生一个无限的采样间峰值,所以我不确定这在实际中有多重要。
$ \ endgroup $
– Endolith
2011年10月3日,下午1:46

#6 楼

您需要平滑直方图(这将产生与使用核方法相似的结果)。究竟如何执行平滑操作需要进行实验。也许也可以通过插值来完成。我相信,除了平滑以外,如果以某种方式对波形进行上采样,以使采样频率“显着高于”输入中的最高频率,那么您还将获得更好的结果。在正弦波与采样频率相关的“棘手”情况下,这应该会有所帮助,使得直方图中只有几个bin会被填充。如果极端的话,足够高的采样率应该可以使您获得良好的曲线而无需平滑。因此,将上采样与某种平滑方式结合起来可以产生更好的曲线图。这是我的建议(Matlab /八度代码)

pixels_vertical = 100;
% This needs to be tuned to your configuration and acceptance
upsampling_factor = 16*(pixels_vertical/100); 
fs_original = 48000;
fsine = 1000; % in Hz
fs_up = upsampling_factor*fs_original;
duration = 1; % in seconds
x = sin(2*pi*fsine*[0:duration*fs_up]/fs_up);
period_in_samples = fs_up/fsine;
hist_points = linspace(-1,1,pixels_vertical);
istart = 1;
iend   = period_in_samples;
pixel_values = hist(x(istart:iend), hist_points);
% smooth pixel values
[b,a] = butter(2,0.2);
pixel_values_smooth = filtfilt(b,a,pixel_values);
figure;hold on;
plot(hist_points, pixel_values);
plot(hist_points, pixel_values_smooth,'r');


对于1000Hz音频,您会得到此


要做的是根据您的喜好调整upsampling_factor表达式。

仍不能100%确切地确定您的要求是什么。但是使用上面的上采样和平滑原理,您将获得1kHz音调(由Matlab制作)。请注意,在原始直方图中,有许多零命中的bin。



评论


$ \ begingroup $
是的,它确实需要某种类型的插值作为算法的一部分。仅对直方图进行平滑处理是无法做到的,因为直方图是离散点,而不是重构波形。进行上采样的唯一方法是,如果采样到的像素数大于垂直像素的采样数,那将是很费力的方法,需要很长时间。
$ \ endgroup $
– Endolith
2011-09-8 20:37



$ \ begingroup $
或计算插值对输出的影响,而无需实际插值
$ \ endgroup $
– Endolith
2011年9月8日20:43在