/// <summary> /// Transforms one window of MFCCs. The following steps are /// performed: <br> /// <br> /// (1) normalized power fft with hanning window function<br> /// (2) convert to Mel scale by applying a mel filter bank<br> /// (3) convertion to db<br> /// (4) finally a DCT is performed to get the mfcc<br> ///<br> /// This process is mathematical identical with the process described in [1]. /// </summary> /// <param name="window">double[] data to be converted, must contain enough data for /// one window</param> /// <param name="start">int start index of the window data</param> /// <returns>double[] the window representation in Sone</returns> public double[] ProcessWindow(double[] window, int start) { //number of unique coefficients, and the rest are symmetrically redundant int fftSize = (windowSize / 2) + 1; //check start if(start < 0) throw new Exception("start must be a positive value"); //check window size if(window == null || window.Length - start < windowSize) throw new Exception("the given data array must not be a null value and must contain data for one window"); //just copy to buffer for (int j = 0; j < windowSize; j++) buffer[j] = window[j + start]; //perform power fft normalizedPowerFFT.Transform(buffer, null); //use all coefficient up to the nequist frequency (ceil((fftSize+1)/2)) Matrix x = new Matrix(buffer, windowSize); x = x.GetMatrix(0, fftSize-1, 0, 0); //fftSize-1 is the index of the nyquist frequency //apply mel filter banks x = melFilterBanks.Times(x); //to db double log10 = 10 * (1 / Math.Log(10)); // log for base 10 and scale by factor 10 x.ThrunkAtLowerBoundary(1); x.LogEquals(); x.TimesEquals(log10); //compute DCT x = dctMatrix.Times(x); return x.GetColumnPackedCopy(); }
// Solve A*X = B // @param B A Matrix with as many rows as A and any number of columns. // @return X so that L*U*X = B(piv,:) // @exception ArgumentException Matrix row dimensions must agree. // @exception Exception Matrix is singular. public Matrix Solve (Matrix B) { if (B.GetRowDimension() != m) { throw new ArgumentException("Matrix row dimensions must agree."); } if (!this.IsNonsingular()) { throw new Exception("Matrix is singular."); } // Copy right hand side with pivoting int nx = B.GetColumnDimension(); Matrix Xmat = B.GetMatrix(piv,0,nx-1); double[][] X = Xmat.GetArray(); // Solve L*Y = B(piv,:) for (int k = 0; k < n; k++) { for (int i = k+1; i < n; i++) { for (int j = 0; j < nx; j++) { X[i][j] -= X[k][j]*LU[i][k]; } } } // Solve U*X = Y; for (int k = n-1; k >= 0; k--) { for (int j = 0; j < nx; j++) { X[k][j] /= LU[k][k]; } for (int i = 0; i < k; i++) { for (int j = 0; j < nx; j++) { X[i][j] -= X[k][j]*LU[i][k]; } } } return Xmat; }
/// <summary> /// Generates the DCT matrix for the known number of filters (input vector) and /// for the known number of used coefficients (output vector). Therfore the /// DCT matrix has the dimensions (numberCoefficients x numberFilters). /// If useFirstCoefficient is set to false the matrix dimensions are /// (numberCoefficients-1 x numberFilters). This matrix is a submatrix of the /// full matrix. Only the frist row is missing. /// </summary> /// <returns>Matrix the appropriate DCT matrix</returns> public Matrix GetDCTMatrix() { //compute constants double k = Math.PI/numberFilters; double w1 = 1.0/(Math.Sqrt(numberFilters)); double w2 = Math.Sqrt(2.0/numberFilters); //create new matrix Matrix matrix = new Matrix(numberCoefficients, numberFilters); //generate dct matrix for(int i = 0; i < numberCoefficients; i++) { for(int j = 0; j < numberFilters; j++) { if(i == 0) matrix.Set(i, j, w1 * Math.Cos(k*i*(j + 0.5d))); else matrix.Set(i, j, w2 * Math.Cos(k*i*(j + 0.5d))); } } //adjust index if we are using first coefficient if(!useFirstCoefficient) matrix = matrix.GetMatrix(1, numberCoefficients-1, 0, numberFilters-1); return matrix; }