На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: RaD, nsh
  
> MFCC
    пожалуйста, дайте формулы по которым считается MFCC.
      формула обратного косинусоидального преобразования тут
      расскажу в двух словах один из способов, как они высчитываются
      1) Сигнал переводится в спектральную область с помощью БПФ (быстрого преобразоавания Фурье)
      2) Спектральные коэффициенты усредняются с использованием параметра количества каналов фильтра, которые представляют из себя гребенку треугольных окон, расположенных на мел-шкале (обычно треугольные фильтры перекрывают область частот от нуля и вплоть до частоты Найквиста ).
      3) Мел-частотные кепстральные коэффициенты вычисляются при помощи обратного косинусного преобразования (см. формулу по ссылке).
      Сообщение отредактировано: goodass -
        спасибо
          Хочу протестировать правильность нахождения мел-частотных кепстральных коэффициентов в моей программе.

          Может кто-нибудь выложить кусок звукового сигнала с выделенными из него MFCC?
            Я Вам настойчиво советую внимательно прочитать предыдущую ветку на эту тему:

            MFCC how????
              я не смог разобраться в логических переходах между сообщениями в этой ветке.

              если я правильно понял, http://htk.eng.cam.ac.uk/ - на этом сайте я могу скачать звуковые фрагменты с выделенным MFCC?
                Хм, ну попробую донести мысль всё-таки.

                Вычисленные коэффициенты MFCC зависят от большого числа параметров - числа фильтров, формы фильтров, числа точек в спектре, основания логарифма и т.д. Поэтому с вероятностью 100% две различные реализации MFCC дадут совершенно различные числа. Поэтому рекомендуется перейти по ссылке http://htk.eng.cam.ac.uk, зарегистрироваться там, и скачать уже скомпилированные под Windows приложения, в частности вычисляющие MFCC. Документация к HTK на русском языке доступна здесь:

                http://aprodeus.narod.ru/mmedia.htm#Rech

                Используя HCopy и HList для вычисления коэффициентов и сверяясь с исходым кодом HTK возможно проверить работу приложения.
                  спасибо огромное
                    Доброго всем дня.
                    Вопрос знатокам HTK по MFCC:
                    код написанный с использованием IPP и HList выдают разные результаты, с чем это может быть связано?
                    IPP:
                    01: -29.003057
                    02: -20.139099
                    03: -4.3270502
                    04: -13.346766
                    05: -18.708612
                    06: -5.8949571
                    07: 31.116928
                    08: 27.441202
                    09: 21.219500
                    10: 39.831188
                    11: 13.616776
                    12: -3.3898118
                    E: 9.6506577

                    HList:
                    ------------------------------------------------- Source: ru_0001.wav --------------------------------------------------
                    Sample Bytes: 2 Sample Kind: WAVEFORM
                    Num Comps: 1 Sample Period: 62.5 us
                    Num Samples: 257278 File Format: WAV
                    -------------------------------------------------------- Target --------------------------------------------------------
                    Sample Bytes: 52 Sample Kind: MFCC_E
                    Num Comps: 13 Sample Period: 10000.0 us
                    Num Samples: 1606 File Format: HTK
                    ------------------------------------------------ Observation Structure -------------------------------------------------
                    x: MFCC-1 MFCC-2 MFCC-3 MFCC-4 MFCC-5 MFCC-6 MFCC-7 MFCC-8 MFCC-9 MFCC-10 MFCC-11 MFCC-12 E
                    ---------------------------------------------------- Samples: 0->0 -----------------------------------------------------
                    0: -10.925 -10.630 -1.796 -8.355 -11.068 -5.632 19.115 14.508 12.260 21.412 7.453 -1.746 9.651
                    --------------------------------------------------------- END ----------------------------------------------------------

                    config:
                    # Coding parameters
                    SOURCEFORMAT = WAV
                    TARGETKIND = MFCC_E
                    TARGETRATE = 100000.0
                    WINDOWSIZE = 250000.0
                    USEHAMMING = T
                    PREEMCOEF = 0.97
                    NUMCHANS = 24
                    CEPLIFTER = 22
                    NUMCEPS = 12
                    ENORMALISE = F
                    LOFREQ = 100
                    HIFREQ = 4000
                    ESCALE = 1.0
                    SILFLOOR = 50.0
                    USEPOWER = T

                    код:
                    ExpandedWrap disabled
                          /* Initialize the structures */
                          ippsMelFBankInitAlloc_32f(&fbank, /* return the structure pointer */
                              &fft_order, /* return the FFT length */
                              400,    /* 25ms window/512 point FFT */
                              16000,  /* sample rate */
                              100,    /* lowest frequency of interest */
                              4000,   /* highest frequency of interest */
                              24,     /* number of filter banks */
                              1127, /* mel-scale factor 1 */
                              700,    /* mel-scale factor 2 */
                              (IppMelMode)(IPP_FBANK_MELWGT | IPP_POWER_SPECTRUM));
                          ippsDCTLifterInitAlloc_32f(&dctl, /* return the structure pointer */
                              24, /* filter bank channels */
                              12, /* number of MFCC coefficients */
                              22, /* liftering */
                              1.0f); /* no scaling */
                          fft_len=1<<fft_order;
                          frame_buffer=ippsMalloc_32f(fft_len);
                          fbank_buffer=ippsMalloc_32f(24);
                          tempmfccs=ippsMalloc_32f(13*(sample_num-400+160)/160);
                          mfcc_cur=tempmfccs;
                          /* Calculate MFCC features */
                          for (i=j=0; i+WindowSize<=sample_num; i+=StepSize,mfcc_cur+=13,j++) {
                              /* Organize the input wave data into a frame */
                              ippsCopyWithPadding_32f(&samples[i],400,frame_buffer,fft_len);
                              ippsDotProd_32f(frame_buffer,frame_buffer,fft_len,&LogEnergy);
                              /* Pre-emphasize the input signal with factor 0.97 */
                              ippsPreemphasize_32f(frame_buffer,400,0.97f);
                              frame_buffer[0]*=(1.0f-0.97f);
                              /* Add the hamming window to the input signal */
                              ippsWinHamming_32f_I(frame_buffer,WindowSize);
                              /* Perform the filter bank analysis */
                              ippsEvalFBank_32f(frame_buffer,fbank_buffer,fbank);
                              ippsThreshold_LTVal_32f_I(fbank_buffer, 24, 1.0f, 1.0f);
                              ippsLn_32f_I(fbank_buffer, 24);
                              /* Perform the DCT analysis and liftering */
                              ippsDCTLifter_32f(fbank_buffer,mfcc_cur,dctl);
                              mfcc_cur[12] = (float) log ((double) LogEnergy);
                          }
                          /* Normalize log energy */
                          //ippsNormEnergy_32f(tempmfccs+12,13,(sample_num-400+160)/160,50.0f,1.0f);
                      Нашёл на просторах интернета вот такой класс MFCC!
                      Каково мнение гуру?
                      По идее,я посмотрел,там есть всё!И БПФокно Хеммингалогарифмирование и DCT и на выходе массив кепстров!На входе должен быть массив double[].Я пока провожу "эксперимент"...

                      ExpandedWrap disabled
                        using System;
                        using System.Collections.Generic;
                        using System.Text;
                         
                        namespace speakerRecognition
                        {
                            class Mfcc
                            {
                                static int my_rint(double x)
                                {
                                    if (2 * x == (double)Math.Round(2 * x))
                                        x += 0.0001;
                         
                                    return ((int)Math.Round(x));
                                }
                         
                                static public double[] mfcc(ref double[] signal)
                                {
                                    double lowestFrequency = 133.3333;
                                    double linearFilters = 13;
                                    double linearSpacing = 66.66666666;
                                    double logFilters = 27;
                                    double logSpacing = 1.0711703;
                                    double fftSize = 512;
                                    double cepstralCoefficients = 13;
                                    double windowSize = 256;
                                    double samplingRate = 44100;
                                    double totalFilters;
                                    double[] mfccFilterWeights;
                                    double[] freqs;
                                    double[] triangleHeight;
                                    double[] lower;
                                    double[] upper;
                                    double[] center;
                                    double[] fftFreqs;
                                    double[] hamWindow;
                                    double[] mfccDCTMatrix;
                                    double[] preEmphasized;
                                    double first;
                                    double last;
                                    double[] fftData;
                                    double[] empreinte;
                                    double maxi;
                                    double[] earMag;
                                    double[] ceps;
                                    double loga;
                                    double windowStep;
                                    double cols;
                                    double frameRate = 100;
                                    double[] result;
                         
                                    int i, j, k;
                         
                         
                                    preEmphasized = new double[1024];
                         
                                    totalFilters = linearFilters + logFilters;
                                    freqs = new double[(int)totalFilters + 2];
                                    for (i = 0; i < linearFilters; i++)
                                        freqs[i] = lowestFrequency + i * linearSpacing;
                                    for (i = (int)linearFilters; i < (int)totalFilters + 2; i++)
                                        freqs[i] = freqs[(int)linearFilters - 1] * Math.Pow(logSpacing, i - linearFilters + 1);
                                    lower = new double[(int)totalFilters];
                                    upper = new double[(int)totalFilters];
                                    center = new double[(int)totalFilters];
                                    triangleHeight = new double[(int)totalFilters];
                                    fftData = new double[(int)fftSize];
                         
                                    for (i = 0; i < (int)totalFilters; i++)
                                        lower[i] = freqs[i];
                                    for (i = 1; i < (int)totalFilters + 1; i++)
                                        center[i - 1] = freqs[i];
                                    for (i = 2; i < (int)totalFilters + 2; i++)
                                        upper[i - 2] = freqs[i];
                                    hamWindow = new double[(int)windowSize];
                                    mfccFilterWeights = new double [(int)(totalFilters * fftSize)];
                                    for (i = 0; i < totalFilters; i++)
                                        triangleHeight[i] = 2 / (upper[i] - lower[i]);
                                    fftFreqs = new double[(int)fftSize];
                                    for (i = 0; i < fftSize; i++)
                                        fftFreqs[i] = (i / fftSize) * samplingRate;
                         
                                    for (i = 0; i < totalFilters; i++)
                                    {
                                        for (j = 0; j < (int)fftSize; j++)
                                        {
                                            if ((fftFreqs[j] > lower[i]) && (fftFreqs[j] <= center[i]))
                                                mfccFilterWeights[(int)fftSize * i + j] = triangleHeight[i] * (fftFreqs[j] - lower[i]) / (center[i] - lower[i]);
                                            if ((fftFreqs[j] > center[i]) && (fftFreqs[j] < upper[i]))
                                                mfccFilterWeights[(int)fftSize * i + j] = (triangleHeight[i] * (fftFreqs[j] - lower[i]) / (center[i] - lower[i])) + (triangleHeight[i] * (upper[i] - fftFreqs[j]) / (upper[i] - center[i]));
                                        }
                                    }
                         
                                    for (i = 0; i < windowSize; i++)
                                        hamWindow[i] = 0.54 - 0.46 * Math.Cos(2 * Math.PI * i / windowSize);
                                    mfccDCTMatrix = new double[(int)(cepstralCoefficients * totalFilters)];
                                    for (i = 0; i < cepstralCoefficients; i++)
                                        for (j = 0; j < totalFilters; j++)
                                            mfccDCTMatrix[j * (int)cepstralCoefficients + i] = 1 / Math.Sqrt(totalFilters / 2) * Math.Cos(i * (2 * j + 1) * Math.PI / 2 / totalFilters);
                                    for (i = 0; i < totalFilters; i++)
                                        mfccDCTMatrix[i * (int)cepstralCoefficients] *= 1 / Math.Sqrt(2);
                                    for (i = 1; i < 1024; i++)
                                        preEmphasized[i] = signal[i] + signal[i - 1] * -0.97;
                                    preEmphasized[0] = signal[0];
                         
                         
                                    earMag = new double[(int)totalFilters];
                                    windowStep = samplingRate / frameRate;
                                    cols = (int)((1024 - windowSize) / windowStep);
                                    ceps = new double[(int)(sizeof(double) * cols * linearFilters)];
                                    for (i = 0; i < cols; i++)
                                    {
                                        first = i * windowStep + 1;
                                        last = first + windowSize - 1;
                                        for (j = 0; j < fftSize; j++)
                                            fftData[j] = 0;
                                        for (j = 0; j < windowSize; j++)
                                            fftData[j] = preEmphasized[(int)my_rint(first + j - 1)] *  hamWindow[j];
                                        double[] fftMag = FourierTransform.FFT(ref signal);
                                        for (j = 0; j < totalFilters; j++)
                                        {
                                            loga = 0;
                                            for (k = 0; k < fftSize; k++)
                                                loga += fftMag[k] * mfccFilterWeights[k + j * (int)fftSize];
                         
                                            earMag[j] = Math.Log10(loga);
                                        }
                                        for (j = 0; j < linearFilters; j++)
                                        {
                                            loga = 0;
                                            for (k = 0; k < totalFilters; k++)
                                                loga +=
                                                  earMag[k] * mfccDCTMatrix[j + k * (int)linearFilters];
                                            ceps[j + i * (int)linearFilters] = loga;
                                        }
                                    }
                         
                         
                                    empreinte = new double[12];
                         
                                    for (i = 1; i < 13; i++)
                                        empreinte[i - 1] = (ceps[i] + ceps[i + 13] + ceps[i + 26] + ceps[i + 39] + ceps[i + 52] + ceps[i + 65]);
                         
                                    maxi = 0;
                                    for (i = 0; i < 12; i++)
                                    {
                                        if (maxi * maxi < empreinte[i] * empreinte[i])
                                            maxi = empreinte[i];  
                                    }
                                    for (i = 0; i < 12; i++) empreinte[i] = (empreinte[i] / Math.Abs(maxi)) * 2;
                                    
                                    return empreinte;
                         
                                }
                            }
                        }
                      Сообщение отредактировано: Dj_SheLL -
                        Насчёт БПФ.
                        Там вроде и прямое и обратное можно.
                        Брал вот этот модуль:
                        ExpandedWrap disabled
                          /// <license>
                          /// This is a port of the SciMark2a Java Benchmark to C# by
                          /// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
                          ///
                          /// For details on the original authors see http://math.nist.gov/scimark2
                          ///
                          /// This software is likely to burn your processor, bitflip your memory chips
                          /// anihilate your screen and corrupt all your disks, so you it at your
                          /// own risk.
                          /// </license>
                           
                          using System;
                           
                          namespace SciMark2
                          {
                              
                              /// <summary>Computes FFT's of complex, double precision data where n is an integer power of 2.
                              /// This appears to be slower than the Radix2 method,
                              /// but the code is smaller and simpler, and it requires no extra storage.
                              /// </P>
                              /// </summary>
                              ///
                              /// <author>
                              /// Bruce R. Miller bruce.miller@nist.gov,
                              /// Derived from GSL (Gnu Scientific Library),
                              /// GSL's FFT Code by Brian Gough bjg@vvv.lanl.gov
                              /// </author>
                              
                              public class FFT
                              {
                                  
                                  public static double num_flops(int N)
                                  {
                                      double Nd = (double) N;
                                      double logN = (double) log2(N);
                                      
                                      return (5.0 * Nd - 2) * logN + 2 * (Nd + 1);
                                  }
                                  
                                  
                                  /// <summary>
                                  /// Compute Fast Fourier Transform of (complex) data, in place.
                                  /// </summary>
                                  public static void  transform(double[] data)
                                  {
                                      transform_internal(data, - 1);
                                  }
                                  
                                  /// <summary>
                                  /// Compute Inverse Fast Fourier Transform of (complex) data, in place.
                                  /// </summary>
                                  public static void  inverse(double[] data)
                                  {
                                      transform_internal(data, + 1);
                                      // Normalize
                                      int nd = data.Length;
                                      int n = nd / 2;
                                      double norm = 1 / ((double) n);
                                       for (int i = 0; i < nd; i++)
                                          data[i] *= norm;
                                  }
                                  
                                  /// <summary>
                                  /// Accuracy check on FFT of data. Make a copy of data, Compute the FFT, then
                                  /// the inverse and compare to the original.  Returns the rms difference.
                                  /// </summary>
                                  public static double test(double[] data)
                                  {
                                      int nd = data.Length;
                                      // Make duplicate for comparison
                                      double[] copy = new double[nd];
                                      Array.Copy(data, 0, copy, 0, nd);
                                      // Transform & invert
                                      transform(data);
                                      inverse(data);
                                      // Compute RMS difference.
                                      double diff = 0.0;
                                       for (int i = 0; i < nd; i++)
                                      {
                                          double d = data[i] - copy[i];
                                          diff += d * d;
                                      }
                                      return Math.Sqrt(diff / nd);
                                  }
                                  
                                  /// <summary>
                                  /// Make a random array of n (complex) elements.
                                  /// </summary>
                                  public static double[] makeRandom(int n)
                                  {
                                      int nd = 2 * n;
                                      double[] data = new double[nd];
                                      System.Random r = new System.Random();
                                      for (int i = 0; i < nd; i++)
                                          data[i] = r.NextDouble();
                                      return data;
                                  }
                                  
                                  protected internal static int log2(int n)
                                  {
                                      int log = 0;
                                       for (int k = 1; k < n; k *= 2, log++)
                                          ;
                                      if (n != (1 << log))
                                          throw new ApplicationException("FFT: Data length is not a power of 2!: " + n);
                                      return log;
                                  }
                                  
                                  protected internal static void  transform_internal(double[] data, int direction)
                                  {
                                      if (data.Length == 0)
                                          return ;
                                      int n = data.Length / 2;
                                      if (n == 1)
                                          return ;
                                      // Identity operation!
                                      int logn = log2(n);
                                      
                                      /* bit reverse the input data for decimation in time algorithm */
                                      bitreverse(data);
                                      
                                      /* apply fft recursion */
                                      /* this loop executed log2(N) times */
                                       for (int bit = 0, dual = 1; bit < logn; bit++, dual *= 2)
                                      {
                                          double w_real = 1.0;
                                          double w_imag = 0.0;
                                          
                                          double theta = 2.0 * direction * Math.PI / (2.0 * (double) dual);
                                          double s = Math.Sin(theta);
                                          double t = Math.Sin(theta / 2.0);
                                          double s2 = 2.0 * t * t;
                                          
                                          /* a = 0 */
                                           for (int b = 0; b < n; b += 2 * dual)
                                          {
                                              int i = 2 * b;
                                              int j = 2 * (b + dual);
                                              
                                              double wd_real = data[j];
                                              double wd_imag = data[j + 1];
                                              
                                              data[j] = data[i] - wd_real;
                                              data[j + 1] = data[i + 1] - wd_imag;
                                              data[i] += wd_real;
                                              data[i + 1] += wd_imag;
                                          }
                                          
                                          /* a = 1 .. (dual-1) */
                                           for (int a = 1; a < dual; a++)
                                          {
                                              /* trignometric recurrence for w-> exp(i theta) w */
                                              {
                                                  double tmp_real = w_real - s * w_imag - s2 * w_real;
                                                  double tmp_imag = w_imag + s * w_real - s2 * w_imag;
                                                  w_real = tmp_real;
                                                  w_imag = tmp_imag;
                                              }
                                               for (int b = 0; b < n; b += 2 * dual)
                                              {
                                                  int i = 2 * (b + a);
                                                  int j = 2 * (b + a + dual);
                                                  
                                                  double z1_real = data[j];
                                                  double z1_imag = data[j + 1];
                                                  
                                                  double wd_real = w_real * z1_real - w_imag * z1_imag;
                                                  double wd_imag = w_real * z1_imag + w_imag * z1_real;
                                                  
                                                  data[j] = data[i] - wd_real;
                                                  data[j + 1] = data[i + 1] - wd_imag;
                                                  data[i] += wd_real;
                                                  data[i + 1] += wd_imag;
                                              }
                                          }
                                      }
                                  }
                                  
                                  
                                  protected internal static void  bitreverse(double[] data)
                                  {
                                      /* This is the Goldrader bit-reversal algorithm */
                                      int n = data.Length / 2;
                                      int nm1 = n - 1;
                                      int i = 0;
                                      int j = 0;
                                       for (; i < nm1; i++)
                                      {
                                          
                                          //int ii = 2*i;
                                          int ii = i << 1;
                                          
                                          //int jj = 2*j;
                                          int jj = j << 1;
                                          
                                          //int k = n / 2 ;
                                          int k = n >> 1;
                                          
                                          if (i < j)
                                          {
                                              double tmp_real = data[ii];
                                              double tmp_imag = data[ii + 1];
                                              data[ii] = data[jj];
                                              data[ii + 1] = data[jj + 1];
                                              data[jj] = tmp_real;
                                              data[jj + 1] = tmp_imag;
                                          }
                                          
                                          while (k <= j)
                                          {
                                              //j = j - k ;
                                              j -= k;
                                              
                                              //k = k / 2 ;
                                              k >>= 1;
                                          }
                                          j += k;
                                      }
                                  }
                              }
                          }
                        Сообщение отредактировано: Dj_SheLL -
                          Dj_SheLL, спасибо за информацию. Поделись пожалуйста впечатлениями от использования класса MFCC. Просто я начал писать свой класс, но столкнулся с некоторыми сложностями, так что возможно буду использовать тот, который ты нашел. Как вообще проверить, правильные ли результаты выдает MFCC или нет?
                            Внешне всё вроде реализованно верно,НО!
                            Я так и не добился получения кепстров-у меня при вычислениях +/- "бесконечность" получается.Проблемы с длинной чисел.
                            Если что, данные я получал с буфера с помощью NAudio.По идее с других библиотек данные не должны отличаться ни чем!
                            Так что надо допиливать класс под "народные нужды",чтобы всем пригодилось...либо пользоваться другими инструментами!
                              Насчет +/- "бесконечности" ничего не могу посоветовать) Я проверил алгоритм и сравнил с теми, которые реализованы на других языках и лежат на просторах интернета. В целом он не вызывает подозрений.
                              Что касается кепстров, то у меня они получились в интервале [2;-1]. NAudio я не использовал.
                              У меня вопрос: перед тем, как записывать звук, мне нужно указать AudioFrameSize. Я так понимаю, что в этот параметр записывается сколько милисекунд будет длится каждый сэмпл. Вляет ли этот параметр на значение кепстров и если да, то сколько мс там указывать?
                                Цитата Lohoboishe @
                                Что касается кепстров, то у меня они получились в интервале [2;-1]

                                А вообще какой диапозон должен быть? :)
                                Цитата Lohoboishe @
                                У меня вопрос: перед тем, как записывать звук, мне нужно указать AudioFrameSize. Я так понимаю, что в этот параметр записывается сколько милисекунд будет длится каждый сэмпл. Вляет ли этот параметр на значение кепстров и если да, то сколько мс там указывать?

                                Ну все берут от 20 до 30.Насчёт влияния-не знаю.
                                  Я, кажется, поторопился с выводами. Ответьте пожалуйста на вопрос: мы посылаем в mfcc(ref double[] signal) весь исходный сигнал или разбиваем его на кадры и посылаем туда? Просто я в литературе и на форуме прочитал, что в итоге должен получиться не один массив(из 12 элементов) коэффициентов кепстра для всего входного сигнала, а якобы мы должны получить массив кепстров для каждого кадра входящего сигнала. Как правильно?
                                    На кадры.
                                      Цитата goodass @
                                      2) Спектральные коэффициенты усредняются с использованием параметра количества каналов фильтра, которые представляют из себя гребенку треугольных окон, расположенных на мел-шкале (обычно треугольные фильтры перекрывают область частот от нуля и вплоть до частоты Найквиста ).

                                      Не очень понятен данный шаг... Под гребёнку треугольных окон нашёл формулу: http://en.wikipedia.org/wiki/Window_functi...angular_windows
                                      сама формула: http://upload.wikimedia.org/wikipedia/en/m...14e8418a54a.png

                                      а как далее её применять? На первом шаге мы берём ФФТ от некоторого сигнала. Получаем распределение частот. Далее мы проходим окнами с перекрытиями по нему или нет? Откуда берётся понятие "количество каналов фильтра"? Что это за каналы?)
                                      Сообщение отредактировано: Black*Eternal -
                                        mel шкала выглядет так:

                                        user posted image

                                        зависимость шкалы - логарифмическая
                                        в результате при выборке например 512 значений фурье для определения частоты, после прохождения через mel фильтр, получим например около 40 значений
                                        если затем отобразить полученный спектр, то визуально распределение энергии будет выглядеть гораздо нагляднее чем в чистном спектре после преборазования фурье
                                        всё заключается в том что чем выше частота тем больше может быть разброс по частоте
                                        человеческое ухо адаптировалось к этому и не улавливает разброс в высоких частотах
                                        mel фильтр эмулирует восприятие сигнала человеческим ухом

                                        http://people.ece.cornell.edu/land/courses...j355/index.html
                                          Цитата zamir @
                                          в результате при выборке например 512 значений фурье для определения частоты, после прохождения через mel фильтр, получим например около 40 значений

                                          Я как раз вот этого момента и не понимаю :)
                                          У нас есть 512 значений. Изначально мы переводим наши частоты в шкалу Мела, по логарифмической формуле как указано в Вашей статье:
                                          m = 2595 * log10(1 + f./700);

                                          После этого у нас же опять получается 512 значений. Далее мы применяем к этим 512 значениям - обратное косинусное преобразование? (по формуле:
                                          http://www1.icsi.berkeley.edu/Speech/docs/.../node64_mn.html )
                                          40 - это и есть у нас NUMCHANS (N) из нашей формулы?
                                          Сообщение отредактировано: Black*Eternal -
                                            Смотрите рисунок сверху
                                            Это фильтр гребёнка
                                            Каждый треугольник - это одно значение
                                            Поэтому если у вас значений будет 512 или 1024, то проходя через этот фильто вы всё равно получите столько значенией - сколько изображено треугольников

                                            p.s.
                                            дискретное преобразование по косинусу - это следующий шаг для сжания энегрии и сокращения размерности
                                              Для наглядности

                                              Вот спектр
                                              user posted image

                                              Вот спектр после прохождения mel фильтра с 20ю контейнерами
                                              user posted image

                                              Вот спектр после прохождения mel фильтра с 40 контейнерами
                                              user posted image

                                              Сравните как выглядят выскоие частоты
                                                Цитата zamir @
                                                Для наглядности

                                                Вот спектр
                                                user posted image

                                                Вот спектр после прохождения mel фильтра с 20ю контейнерами
                                                user posted image

                                                Вот спектр после прохождения mel фильтра с 40 контейнерами
                                                user posted image

                                                Сравните как выглядят выскоие частоты

                                                Я не понимаю как выбирается количество вот этих контейнеров и какая вообще формула этой гребёнки... :(
                                                  Цитата
                                                  Я не понимаю как выбирается количество вот этих контейнеров

                                                  можно выбирать на глаз (для начала придётся научиться читать спектрограммы)
                                                  можно использовать устоявшиеся значения
                                                  31 для сигнала sample rate 8000

                                                  Цитата
                                                  и какая вообще формула этой гребёнки...

                                                  сначала по формуле m = 2595 * log10(1 + f./700) делате mel шкалу - визуально получаете треугольники
                                                  обходите каждый треуголник и умножаете частоту на коэфициент в треугольнике соответвествующей этой частоте и складываете в контейнер

                                                  задача не сложная, интерпритируя иначе:
                                                  надо уменьшить высоту картинки - но не линейно а по mel шкале
                                                  Сообщение отредактировано: zamir -
                                                    Цитата zamir @
                                                    сначала по формуле m = 2595 * log10(1 + f./700) делате mel шкалу - визуально получаете треугольники

                                                    f - это мои частоты после FFT? 1hz, 2hz, 3hz...? :) Тогда получается просто логарифм без треугольников :)

                                                    user posted image

                                                    Если же в формулу подставлять мои результаты из FFT:
                                                    m = 2595 * log10(1 + FFT[i]/700)

                                                    то получается просто немного "сглаженный" тот же самый график...

                                                    Проблема у меня вот в чём: У меня есть формула треугольного окна: http://upload.wikimedia.org/wikipedia/en/m...14e8418a54a.png
                                                    Я могу пробежаться по FFT (сигналу после FFT) разбить его на определённое количество окон (можно с перекрытиями) и в каждом домножить сигнал на треугольное окно. Но проблема в том, что шкала от этого не измениться по ОХ, то бишь - размер каждого окна будет одинаковый, а на этих графиках (как и на Вашем), размеры окон разные, увеличивающиеся к концу. Не понимаю как это достигается...
                                                    Сообщение отредактировано: Black*Eternal -
                                                      Треугольное окно относится к преобразованиию фурье
                                                      Для этого преобразования это не лучшее решение
                                                      После пребразования вы получите спектр
                                                      значения после преобразования это не совсем частоты это отсчеты частот
                                                      А в формулу надо подставлять именно частоты
                                                      для начала просто получите спектр и попробуйте его сжать по шкале частоты
                                                        Цитата zamir @
                                                        После пребразования вы получите спектр
                                                        значения после преобразования это не совсем частоты это отсчеты частот

                                                        Попробую поэтапно свериться и рассказать, что я делаю на этом этапе :) У меня после Фурье на выходе получается, скажем 3000 точек. Это просто упорядоченные отсчёты. Сигнал у меня в формате 11025герц, поэтому после Фурье я получу набор частот от 0 до 5512гц.

                                                        По пропорции получаем, что частота определённого отсчёта вычисляется так: 5512 * порядковый_номер_отсчёта / 3000

                                                        Затем подставляем эту формулу вместо символа f в формулу перевода в мел-шкалу и получаем:

                                                        m = 2595 * log10( 1 + ( 5512 * порядковый_номер_отсчёта / 3000 ) / 700 )

                                                        Это пока что верно или уже здесь напортачил? :)
                                                        Сообщение отредактировано: Black*Eternal -
                                                          Похоже на правду
                                                          Вам ещё в процессе потребуется обратное преобраззование из mel шкалы
                                                          Выглядит оно так:
                                                          f = 700 * (pow(10, m / 2595.0) - 1)

                                                          прежде чем подставлять значение после пребразования Фурье, лучше создать банк фильтров той самой гребёнки из например 40 значений
                                                          каждое значение будет определять диапазон часто для данного банка/треугольника
                                                          для линейной зависимости просто делим вашу ось частоты 5512 на 40 и получаем 40 диапазонов частот
                                                          для логарифмической зависимости придётся проделать чуть больше арифметических вычислений
                                                          Полагаю вы суть уловили :)

                                                          Забегая немного вперёд:
                                                          При работе с фильтром определяются так же диапазоны частот
                                                          Например человеческая речь находится приблизитетельно в диапазоне частот от 80 до 9000Гц
                                                          Поэтому для фильтра берут например отрезок от 100 до 4000Гц и деляет его на контейнеры. Частоты выше и ниже отбрасывают.
                                                            Цитата zamir @
                                                            прежде чем подставлять значение после пребразования Фурье, лучше создать банк фильтров той самой гребёнки из например 40 значений

                                                            А как это делается? :lol: Я вот этого никак и не могу понять как эти гребёнки делать :lol:
                                                              Цитата
                                                              для линейной зависимости просто делим вашу ось частоты 5512 на 40 и получаем 40 диапазонов частот
                                                              для логарифмической зависимости придётся проделать чуть больше арифметических вычислений

                                                              я полагал вот тут вы суть уловите :)
                                                              если я не ошибаюсь то делал это так (поправьте меня если я не прав):
                                                              сначала работаем в mel шкале - делим участок частот на равные отрезки
                                                              затем переводим наши отрезки на реальную плоскость частот и получаем пасположение углов треугольника
                                                              зарисуйте на бумажке - всё должно сойтись примерно с тем что изозражено на графике
                                                                Народ а подскажите в чем смысл DCT. Читал про MFCC там на графиках показано что LPC, MFCC после DCT это коэффициенты которые огибают спектр что-то типа усреднения. Экспериментировал у себя по всякому после гребенки фильтров DCT, получается либо какой-то градиент, либо просто коэффициенты не похожие на спектр огибания. Да и примеры сколько не скачивал по DCT тоже спектр там не получается всегда квантуется или фильтруется и потом инверсное DCT.
                                                                В чем проблема нужно делать квантование после DCT и потом инверсное DCT ? Чтобы получить как бы сжатые данные, информации о спектре?

                                                                А если LPC и MFCC коэффициенты это упрощение и усреднение спектра для уменьшения данных, то почему не сделать просто скользящее среднее по спектру получится таже самая огибиющая спектра?
                                                                Я правильно мыслю?




                                                                Вот картинка от сюда ->
                                                                Aldebaro Klautau - 11/22/05
                                                                How are MFCCs used in speech recognition
                                                                Прикреплённый файлПрикреплённый файлCoeffs.JPG (71,56 Кбайт, скачиваний: 608)
                                                                Сообщение отредактировано: TViT -
                                                                  Квантование - вами выбрано правильное слово
                                                                  Задача DCT сделать квантование
                                                                  Получаем например 13 коэффициентов квантования
                                                                  Если будем смотреть только первый коэффициент - видим изменение большого кванта энергии
                                                                  Следующий коэффициент - квант энергии меньшего размера (второй наиболее значимый признак)
                                                                  и т.д.

                                                                  MFCC часто сравнивают с PCA - т.е. в обоих случаях выделяются главные компоненты которые упорядочены в порядке уменьшения их значимости

                                                                  Упорядоченные признаки нужны системе распознавания
                                                                  Сообщение отредактировано: zamir -
                                                                    zamir ну тык инверсное DCT делать нужно??? Чтобы обратно к спектру вернуться, только с потерей информации. А если инверсное DCT не делать, то огибающей спектра не получится, будут просто коэффициенты косинусного преобразования.
                                                                    Первый самый значащий коэффициент, а остальные менее значащие, если обнулить, то будет соответственно уровень сжатия с потерей начальных спектральных данных. И всегда коэффициент первый самый главный, а остальные можно обнулять это влияет на сжатие и потерю информации о спектре. Это же не огибающая спектра получится. Вот инверсное DCT вернет обратно в спектр и получится спектральная информация, только сжатая с потерей качества.

                                                                    А 13 первых коэффициентов, это при условии что 20 фильтров во временном окне, например слово делиться тоже на 20 временных окон, тайм слотов? Если фильтров например 30 то нужно первые 20 коэффициентов брать? Иначе потери информации о спектре будут сильными при сжатии.
                                                                    Сообщение отредактировано: TViT -
                                                                      Цитата
                                                                      ну тык инверсное DCT делать нужно??? Чтобы обратно к спектру вернуться, только с потерей информации.

                                                                      Если хотите визуализировать или синтезировать, можно сделать
                                                                      Но для распознавания - не нужно

                                                                      Цитата
                                                                      А если инверсное DCT не делать, то огибающей спектра не получится, будут просто коэффициенты косинусного преобразования.

                                                                      да, просто коэфициенты, которые являются упорядоченными принципиальными компонентами - это именно то что нужно системе распознавания

                                                                      Цитата
                                                                      А 13 первых коэффициентов, это при условии что 20 фильтров во временном окне, например слово делиться тоже на 20 временных окон, тайм слотов? Если фильтров например 30 то нужно первые 20 коэффициентов брать


                                                                      13 принципиальных компонент берётся потому что практикой доказано, что остальные (маленькие кванты энергии) не несут существенной информации
                                                                      13 коэффициентов берётся на окно например в 30мс.
                                                                      Как влияет число фильтров на необходимое количество DCT коэффициентов не скажу.
                                                                        Вопрос мб немного не в тему но все же
                                                                        нужно ли обрезать сигнал во временной области перед обработкой в частотной?

                                                                        Прикреплённый файлПрикреплённый файлFIgure1.jpg (24,05 Кбайт, скачиваний: 675)
                                                                        то что есть

                                                                        Прикреплённый файлПрикреплённый файлFIgure1___копия.jpg (40,75 Кбайт, скачиваний: 622)
                                                                        полезная часть

                                                                        если да то как?(ведь размерность должна оставаться одинаковой что в базе( эталонов) что в входном сигнале который сравнивается и эталонами)
                                                                          если вы будете делать преобразование Фурье то вам всё равно нужны все отчёты
                                                                          поэтому удаление надо интерпретировать как фильтрацию (убрать аплитуду там где вы считаете сигнала нет) - тогда я не вижу препятстивий для вашей задумки
                                                                          1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                                          0 пользователей:


                                                                          Рейтинг@Mail.ru
                                                                          [ Script execution time: 0,0851 ]   [ 17 queries used ]   [ Generated: 17.07.25, 23:26 GMT ]