/* * Copyright 1999-2002 Carnegie Mellon University. * Portions Copyright 2002 Sun Microsystems, Inc. * Portions Copyright 2002 Mitsubishi Electric Research Laboratories. * All Rights Reserved. Use is subject to license terms. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * */ package edu.cmu.sphinx.frontend.feature; import edu.cmu.sphinx.frontend.*; /** * Computes the delta and double delta of input cepstrum (or plp or ...). The delta is the first order derivative and * the double delta (a.k.a. delta delta) is the second order derivative of the original cepstrum. They help model the * speech signal dynamics. The output data is a {@link FloatData} object with a float array of size three times the * original cepstrum, formed by the concatenation of cepstra, delta cepstra, and double delta cepstra. The output is the * feature vector used by the decoder. Figure 1 shows the arrangement of the output feature data array: * <p> * <img alt="Layout of features" src="doc-files/feature.jpg"> <br> <b>Figure 1: Layout of the returned features. </b> * <p> * Suppose that the original cepstrum has a length of N, the first N elements of the feature are just the original * cepstrum, the second N elements are the delta of the cepstrum, and the last N elements are the double delta of the * cepstrum. * <p> * Figure 2 below shows pictorially the computation of the delta and double delta of a cepstrum vector, using the last 3 * cepstra and the next 3 cepstra. <img alt="Delta computation" src="doc-files/deltas.jpg"> <br> <b>Figure 2: Delta and double delta vector * computation. </b> * <p> * Referring to Figure 2, the delta is computed by subtracting the cepstrum that is two frames behind of the current * cepstrum from the cepstrum that is two frames ahead of the current cepstrum. The computation of the double delta is * similar. It is computed by subtracting the delta cepstrum one time frame behind from the delta cepstrum one time * frame ahead. Replacing delta cepstra with cepstra, this works out to a formula involving the cepstra that are one and * three behind and after the current cepstrum. */ public class DeltasFeatureExtractor extends AbstractFeatureExtractor { public DeltasFeatureExtractor(int window) { super(window); } public DeltasFeatureExtractor( ) { } /** * Computes the next feature. Advances the pointers as well. * * @return the feature Data computed */ @Override protected Data computeNextFeature() { int jp1 = (currentPosition - 1 + cepstraBufferSize) % cepstraBufferSize; int jp2 = (currentPosition - 2 + cepstraBufferSize) % cepstraBufferSize; int jp3 = (currentPosition - 3 + cepstraBufferSize) % cepstraBufferSize; int jf1 = (currentPosition + 1) % cepstraBufferSize; int jf2 = (currentPosition + 2) % cepstraBufferSize; int jf3 = (currentPosition + 3) % cepstraBufferSize; DoubleData currentCepstrum = cepstraBuffer[currentPosition]; double[] mfc3f = cepstraBuffer[jf3].getValues(); double[] mfc2f = cepstraBuffer[jf2].getValues(); double[] mfc1f = cepstraBuffer[jf1].getValues(); double[] current = currentCepstrum.getValues(); double[] mfc1p = cepstraBuffer[jp1].getValues(); double[] mfc2p = cepstraBuffer[jp2].getValues(); double[] mfc3p = cepstraBuffer[jp3].getValues(); float[] feature = new float[current.length * 3]; currentPosition = (currentPosition + 1) % cepstraBufferSize; // CEP; copy all the cepstrum data int j = 0; for (double val : current) { feature[j++] = (float)val; } // System.arraycopy(current, 0, feature, 0, j); // DCEP: mfc[2] - mfc[-2] for (int k = 0; k < mfc2f.length; k++) { feature[j++] = (float) (mfc2f[k] - mfc2p[k]); } // D2CEP: (mfc[3] - mfc[-1]) - (mfc[1] - mfc[-3]) for (int k = 0; k < mfc3f.length; k++) { feature[j++] = (float) ((mfc3f[k] - mfc1p[k]) - (mfc1f[k] - mfc3p[k])); } return (new FloatData(feature, currentCepstrum.getSampleRate(), currentCepstrum.getFirstSampleNumber())); } }