web-dev-qa-db-fra.com

Bibliothèque FFT dans Android Sdk

Je travaille avec le projet Android. J'ai besoin d'un algorithme FFT pour traiter les données de l'accéléromètre Android. Y a-t-il une bibliothèque FFT disponible dans Android sdk?

33
stefy abraham

Vous pouvez utiliser cette classe, qui est suffisamment rapide pour une analyse audio en temps réel

public class FFT {

  int n, m;

  // Lookup tables. Only need to recompute when size of FFT changes.
  double[] cos;
  double[] sin;

  public FFT(int n) {
      this.n = n;
      this.m = (int) (Math.log(n) / Math.log(2));

      // Make sure n is a power of 2
      if (n != (1 << m))
          throw new RuntimeException("FFT length must be power of 2");

      // precompute tables
      cos = new double[n / 2];
      sin = new double[n / 2];

      for (int i = 0; i < n / 2; i++) {
          cos[i] = Math.cos(-2 * Math.PI * i / n);
          sin[i] = Math.sin(-2 * Math.PI * i / n);
      }

  }

  public void fft(double[] x, double[] y) {
      int i, j, k, n1, n2, a;
      double c, s, t1, t2;

      // Bit-reverse
      j = 0;
      n2 = n / 2;
      for (i = 1; i < n - 1; i++) {
          n1 = n2;
          while (j >= n1) {
              j = j - n1;
              n1 = n1 / 2;
          }
          j = j + n1;

          if (i < j) {
              t1 = x[i];
              x[i] = x[j];
              x[j] = t1;
              t1 = y[i];
              y[i] = y[j];
              y[j] = t1;
          }
      }

      // FFT
      n1 = 0;
      n2 = 1;

      for (i = 0; i < m; i++) {
          n1 = n2;
          n2 = n2 + n2;
          a = 0;

          for (j = 0; j < n1; j++) {
              c = cos[a];
              s = sin[a];
              a += 1 << (m - i - 1);

              for (k = j; k < n; k = k + n2) {
                  t1 = c * x[k + n1] - s * y[k + n1];
                  t2 = s * x[k + n1] + c * y[k + n1];
                  x[k + n1] = x[k] - t1;
                  y[k + n1] = y[k] - t2;
                  x[k] = x[k] + t1;
                  y[k] = y[k] + t2;
              }
          }
      }
  }
}

Attention: ce code semble dériver de ici , et possède une licence GPLv2.

40
EricLarch

Utilisation de la classe sur: https://www.ee.columbia.edu/~ronw/code/MEAPsoft/doc/html/FFT_8Java-source.html

Brève explication: appelez fft () fournissant x comme vous les données d'amplitude, y comme tableau de tous les zéros, après le retourne votre première réponse sera un [0] = x [0] ^ 2 + y [0] ^ 2.

Explication complète: [~ # ~] fft [~ # ~] est une transformation complexe, il faut [~ # ~] n [~ # ~] nombres complexes et produit [~ # ~] n [~ # ~] nombres complexes. Donc x [0] est la partie réelle du premier nombre, y [0] est la partie complexe. Cette fonction calcule sur place, donc lorsque la fonction retourne x et y aura les parties réelles et complexes de la transformation.

Une utilisation typique consiste à calculer le spectre de puissance de l'audio. Vos échantillons audio n'ont qu'une partie réelle, votre partie complexe est 0. Pour calculer le spectre de puissance, vous ajoutez le carré des parties réelle et complexe P [0] = x [0] ^ 2 + y [0] ^ 2.

Il est également important de noter que la transformée de Fourier, lorsqu'elle est appliquée sur des nombres réels, donne un résultat symétrique (x [0] == x [x.lenth-1]). Les données à x [x.length/2] ont les données de la fréquence f = 0Hz. x [0] == x [x.length-1] a les données pour une fréquence égale à avoir la fréquence d'échantillonnage (par exemple, si vous échantillonnez était à 44000 Hz, cela signifie que f [0] se réfère à 22 kHz).

Procédure complète:

  1. créer un tableau p [n] avec 512 échantillons avec des zéros
  2. Collectez 1024 échantillons audio, écrivez-les sur x
  3. Définissez y [n] = 0 pour tout n
  4. calculer fft (x, y)
  5. calculer p [n] + = x [n + 512] ^ 2 + y [n + 512] ^ 2 pour tous n = 0 à 512
  6. aller 2 pour prendre un autre lot (après 50 lots, passer à l'étape suivante)
  7. parcelle p
  8. aller à 1

Ensuite, ajustez le nombre fixe à votre goût.

Le nombre 512 définit la fenêtre d'échantillonnage, je ne l'expliquerai pas. Évitez simplement de le réduire trop.

Le nombre 1024 doit toujours être le double du dernier nombre.

Le nombre 50 définit votre taux de mise à jour. Si votre taux d'échantillonnage est de 44000 échantillons par seconde, votre taux de mise à jour sera: R = 44000/1024/50 = 0,85 seconde.

11

kissfft est une bibliothèque suffisamment décente qui se compile sur Android. Il a une licence plus polyvalente que FFTW (même si FFTW est certes meilleure).

Vous pouvez trouver une liaison Android pour kissfft dans libgdx https://github.com/libgdx/libgdx/blob/0.9.9/extensions/gdx-audio/src/com /badlogic/gdx/audio/analysis/KissFFT.Java

Ou si vous souhaitez une pure Java essayez jTransforms https://sites.google.com/site/piotrwendykier/software/jtransforms

7
Matt Esch

Utilisez ceci classe (celui dont la réponse d'EricLarch est dérivée).

Notes d'utilisation

Cette fonction remplace vos tableaux d'entrées par la sortie FFT.

Entrée

  • N = le nombre de points de données (la taille de votre tableau d'entrée, doit être une puissance de 2)
  • X = la partie réelle de vos données à transformer
  • Y = la partie imaginaire des données à transformer

c'est-à-dire si votre entrée est (1 + 8i, 2 + 3j, 7-i, -10-3i)

  • N = 4
  • X = (1, 2, 7, -10)
  • Y = (8, 3, -1, -3)

Sortie

  • X = la partie réelle de la sortie FFT
  • Y = la partie imaginaire de la sortie FFT

Pour obtenir votre graphique FFT classique, vous souhaiterez calculer la magnitude des parties réelles et imaginaires.

Quelque chose comme:

public double[] fftCalculator(double[] re, double[] im) {
    if (re.length != im.length) return null;
    FFT fft = new FFT(re.length);
    fft.fft(re, im);
    double[] fftMag = new double[re.length];
    for (int i = 0; i < re.length; i++) {
       fftMag[i] = Math.pow(re[i], 2) + Math.pow(im[i], 2);
    }
    return fftMag;
}

Voir aussi cette réponse StackOverflow pour savoir comment obtenir des fréquences si votre entrée d'origine était la magnitude en fonction du temps.

4
J Wang

Oui, il y a JTransforms qui est maintenu sur githubici et disponible en tant que plugin Mavenici .

Utiliser avec:

compile group: 'com.github.wendykierp', name: 'JTransforms', version: '3.1'

Mais avec les versions plus récentes de Gradle, vous devez utiliser quelque chose comme:

dependencies {
    ... 
    implementation 'com.github.wendykierp:JTransforms:3.1'
}
1
not2qubit

@J Wang Votre magnitude de sortie semble meilleure que la réponse donnée sur le fil que vous avez lié, mais qui est toujours au carré ... la magnitude d'un nombre complexe

z = a + ib

est calculé comme

|z|=sqrt(a^2+b^2)

la réponse dans le fil de discussion suggère que pour les entrées réelles pures, les sorties devraient utiliser n2 ou a pour la sortie car les valeurs de

a_(i+N/2) = -a_(i),

avec b_(i) = a_(i+N/2) signifiant que la partie complexe de leur tableau se trouve dans la seconde moitié du tableau de sortie.

c'est-à-dire que la seconde moitié du tableau de sortie pour un tableau d'entrée de réels est le conjugué du réel ...

donc z = a-ia donnant une magnitude

|z|=sqrt(2a^2) = sqrt(2)a

il vaut donc la peine de noter les facteurs d'échelle ... Je recommanderais de regarder tout cela dans un livre ou sur wiki pour être sûr.

1
david nash