在复合周期信号的周期开始时找到样本

时间:2011-11-15 17:04:27

标签: c signal-processing

我的信号由许多正弦波的总和组成。这些间隔为100Hz,最低分量频率为200Hz(200Hz,300Hz ......等)。所有分量正弦波都在相位= 0的同一点开始。在我的DSP软件中,我要将这个信号相乘通过其他几个信号,我需要找到一个点,在该点上所有原始信号的分量信号都再次处于相位= 0。

如果我只使用一个正弦波,我可以简单地寻找从负到正的符号变化。然而,如果信号具有200Hz和300Hz的分量,则有三个过零点,其中符号从负变为正,但只有一个表示周期的开始,并且这随着更多的分量波而增加。在初始启动序列中,我确实可以控制每个分量频率的幅度。如果这些波是严格谐波(200Hz,400Hz,800Hz等),我可以简单地删除除最低频率以外的所有波,找到其周期的开始,并将其用作我的零样本。但是,我没有这个带宽。任何人都可以提供替代方法吗?

编辑:

(我已将此编辑内容澄清并整合到问题正文中。)

编辑2:

此图片应说明问题。这里的频率两个分量是n和3n / 2。如果没有滤除除最低频率以外的所有频率,或者按照@hotpaw的建议采用FFT,那么只查找符号从负正变化的零交叉的算法将落在三个中的一个上,我必须找到第一个三(这是每个分量信号处于相位= 0的一个点)。我意识到采用FFT会起作用,但我处理的处理能力非常有限,并且想知道是否有更简单的方法。

Sample waveform

3 个答案:

答案 0 :(得分:3)

看看信号的衍生物!

你的信号是正弦的总和(抱歉,我不确定如何正确格式化公式)

S = sum(a_n * sin(k_n * t)) ... over all n

a_n是正幅度,k_n是正频率。信号的导数(你可以很容易地用数字计算)是

dS/dt = sum(a_n * k_n * cos(k_n * t)) ... over all n

在t = 0(您正在寻找的)时,导数具有最大值,因为所有余弦项都是同时的。

一些补充: 对于实际实现,您需要考虑导数可能有噪声,因此可能需要某种简单的一阶滤波。

答案 1 :(得分:1)

我假设所有正弦波都是某些基频的精确谐波,在某个时间点相对于同一参考点都具有零相位,并且这是您希望找到的时间点。

您可以使用光圈长度为基频周期(100 Hz)的精确倍数的FFT。如果噪声为零,则可以使用1个周期。使用FFT估算所有正弦曲线的某个参考点(FFT孔径开始或中心)的相位。然后使用在FFT中显示为有效的最低频率正弦波的相位来计算目标时间范围内的所有过零点。与所有其他正弦曲线的最近零交叉相比较(使用FFT相位来估计它们的相位),并找到低频零交叉点,其中所有其他频率的所有最近零交叉点的偏移的总最小平方误差。 / p>

您可以返回时域以确认最小二乘估计的交叉点作为实际过零点和/或消除一些数字噪声。

答案 2 :(得分:0)

我会选择一阶或二阶低通滤波器来移除分量频率。 100赫兹与“噪音”之间的差异造成了相当大的差距。从低频开始,消除所有噪声并增加,直到您对信号感到满意为止。

之后,您有信号,可以注意标志的变化。

二阶实施:

 static float a1 = 0;
 static float a2 = 0;
 static float b1 = 0;
 static float b2 = 0;

 static float y = 0;
 static float y_old = 0;
 static float u_old = 0;

 void
 init_lp_filter(float cutoff_freq, float sample_time) 
 {
   float wc = cutoff_freq;
   float h = sample_time;

   float epsilon = 1.0f/sqrt(2.0f);
   float omega = wc * sqrt(0.5f);
   float alpha = exp(-epsilon*wc*h);
   float beta = cos(omega*h);
   float gamma = sin(omega*h);

   b1 = 1.0f - alpha * (beta + epsilon * wc * gamma / omega);
   b2 = alpha * alpha + alpha * (epsilon * wc * gamma / omega - beta);
   a1 = -2.0f * alpha * beta;
   a2 = alpha * alpha;
 }

 float
 getOutput() {
   return y;
 }

 void
 update_filter(float input)
 {
   float tmp = y;
   y = b1 * input + b2 * u_old - a1 * y - a2 * y_old;
   y_old = tmp;
   u_old = input;
 }

由于滤波后的输出仅取决于旧值,这意味着滤波后的输出可以在循环开始时直接使用。然后可以在周期性循环结束时使用测量样本更新滤波器。请注意,如果您有任何可能影响信号的输出(即物理过程中的执行器),您必须在输出之前对信号进行采样。)

祝你好运!