检测手机加速度计的周期性数据

sim*_*dam 4 algorithm android signal-processing accelerometer

我正在开发一个Android应用程序,我需要检测用户上下文(如果步行或驾驶最小)

我正在使用加速度计和所有轴的总和来检测加速度矢量.它在行走时能看到一些周期性值的方式非常好.但我需要以编程方式检测这些poeriods.

请问是否有任何类型的数学函数来检测值集的周期?我听说傅里叶变换可用于此,但我真的不知道如何实现它.看起来很复杂:)

请帮忙

LiK*_*Kao 8

检测数据周期性的最简单方法是自相关.这也很容易实现.要获得自相关,i只需将数据的每个数据点与移动的每个数据点相乘i.这是一些伪代码:

for i = 0 to length( data ) do
  autocorrel[ i ] = 0;
  for j = 0 to length( data ) do
     autocorrel[ i ] += data( j ) * data( ( j + i ) mod length( data ) )
  done
done
Run Code Online (Sandbox Code Playgroud)

这将为您提供一系列值.最高的"周期性"在具有高值的索引处.通过这种方式,您可以提取任何周期性部分(通常不止一个).

另外我建议你不要在应用程序中尝试实现自己的FFT.虽然这个算法非常适合学习,但是很多人可以做错,很难测试,而且你的实现也可能比现有的慢得多.如果你的系统有可能,我会建议你使用FFTW,这在FFT实现方面是不可能的.

编辑:

解释,为什么它甚至可以在不重复的值上工作:

计算自相关的通常和完全正确的方法是从数据中减去均值.让我们说你有[1, 2, 1.2, 1.8 ].然后你可以从每个样本中提取1.5,留下你[-.5, .5, -.3, .3 ].现在,如果你将它与自身乘以零,则负数将乘以负数,正数乘以正数,产生(-.5)^2 + (.5)^2 + (-.3)^2 + (.3)^2=.68.在一个负数的偏移量将乘以正数产生(-.5)*(.5) + (.5)*(-.3) + (-.3)*(.3) + (.3)*(-.5)=-.64.在偏移量为2时,负数将乘以负数,正数乘以正数.在偏移三个类似于一个偏移的情况再次发生.如您所见,在0和2(周期)的偏移处获得正值,在1和4处获得负值.

现在只检测周期,没有必要减去平均值.如果您按原样保留样品,则每次添加时都会添加suqared mean.由于将为每个计算的系数添加相同的值,因此比较将产生与您首先减去平均值相同的结果.在最坏的情况下,您的数据类型可能会运行(如果您使用某种类型的整数类型),或者您可能会在值开始变大时解决错误(如果您使用float,通常这不是问题).如果发生这种情况,首先减去均值并尝试结果是否会好转.

使用自相关与某种快速傅里叶变换的最大缺点是速度.自动关联O(n^2)只需要FFT O(n log(n)).如果您需要经常计算非常长的序列的周期,自动复原可能不适用于您的情况.

如果你想知道傅立叶变换是如何工作的,以及所有关于实部和虚部,幅度和相位的东西(看看Manu发布的代码)的意思,我建议你看看这个书.

EDIT2:

在大多数情况下,数据既不是完全周期性的,也不是完全混乱和非周期性的.通常,您的数据将由几个不同强度的周期性组成.句点是一个时差,您可以通过它来移动数据以使其与自身相似.如果将数据移动一定量,则自相关计算数据的相似程度.因此,它为您提供所有可能时期的力量.这意味着,没有"重复值索引",因为当数据完全周期性时,所有索引都将重复.具有最强值的索引为您提供数据与自身最相似的移位.因此,此索引提供时间偏移,而不是数据的索引.为了理解这一点,重要的是要理解时间序列如何被认为是由完美周期函数(正弦基函数)的总和组成.

如果您需要在很长时间内检测到这一点,通常最好在您的数据上滑动一个窗口,然后检查这个较小数据帧的周期.但是,您必须注意,您的窗口将为您的数据添加额外的句点,您必须注意这些句点.

更多在我上次编辑中发布的链接中.


wil*_*ett 7

还有一种方式来计算使用FFT从降低复杂数据的自相关O(n^2)O(n log n).基本思路是您获取周期性样本数据,使用FFT对其进行变换,然后通过将每个FFT系数乘以其复共轭来计算功率谱,然后采用功率谱的逆FFT.您可以找到预先存在的代码来毫不费力地计算功率谱.例如,看看Moonblink android库.该库包含FFTPACK(一个很好的FFT库)的JAVA转换,它还有一些用于计算功率谱的DSP类.我已经成功使用的自相关方法是McLeod的节距法(MPM),Java源代码是可用的,其在这里.我在类中编辑了一个方法McLeodPitchMethod,允许它使用FFT优化的自相关算法计算音高:

private void normalizedSquareDifference(final double[] data) {
    int n = data.length;
    // zero-pad the data so we get a number of autocorrelation function (acf)
    // coefficients equal to the window size
    double[] fft = new double[2*n];
        for(int k=0; k < n; k++){
        fft[k] = data[k];
    }
    transformer.ft(fft);
    // the output of fft is 2n, symmetric complex
    // multiply first n outputs by their complex conjugates
    // to compute the power spectrum
    double[] acf = new double[n];
    acf[0] = fft[0]*fft[0]/(2*n);
    for(int k=1; k <= n-1; k++){
        acf[k] = (fft[2*k-1]*fft[2*k-1] + fft[2*k]*fft[2*k])/(2*n);
    }
    // inverse transform
    transformerEven.bt(acf);
    // the output of the ifft is symmetric real
    // first n coefficients are positive lag acf coefficients
    // now acf contains acf coefficients
    double[] divisorM = new double[n];
    for (int tau = 0; tau < n; tau++) {
        // subtract the first and last squared values from the previous divisor to get the new one;
        double m = tau == 0 ? 2*acf[0] : divisorM[tau-1] - data[n-tau]*data[n-tau] - data[tau-1]*data[tau-1];
        divisorM[tau] = m;
        nsdf[tau] = 2*acf[tau]/m;
    }
}
Run Code Online (Sandbox Code Playgroud)

java FFTPACK转换transformer中的FFTTransformer类的私有实例在哪里,并且transformerEvenFFTTransformer_Even该类的私有实例.通过调用McLeodPitchMethod.getPitch()您的数据可以非常有效地估算频率.