1 // feat/feature-sdc-test.cc
3 // Copyright 2014 David Snyder
5 // See ../../COPYING for clarification regarding multiple authors
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
15 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
16 // MERCHANTABLITY OR NON-INFRINGEMENT.
17 // See the Apache 2 License for the specific language governing permissions and
18 // limitations under the License.
21 #include <iostream>
23 #include "feat/feature-mfcc.h"
24 #include "base/kaldi-math.h"
25 #include "matrix/kaldi-matrix-inl.h"
26 #include "feat/wave-reader.h"
28 using namespace kaldi;
30 static void UnitTestCompareWithDeltaFeatures(Matrix<BaseFloat> &raw_features, int32 window) {
31 std::cout << "=== UnitTestSDCCompareWithDeltaFeatures() ===\n";
32 DeltaFeaturesOptions deltas_opts;
33 deltas_opts.window = window;
34 ShiftedDeltaFeaturesOptions shifted_deltas_opts;
35 shifted_deltas_opts.window = window;
36 Matrix<BaseFloat> deltas_features;
37 Matrix<BaseFloat> shifted_deltas_features;
38 ComputeDeltas(deltas_opts,
39 raw_features,
40 &deltas_features);
41 ComputeShiftedDeltas(shifted_deltas_opts,
42 raw_features,
43 &shifted_deltas_features);
45 int32 dd_num_rows = deltas_features.NumRows();
46 int32 sdc_num_rows = shifted_deltas_features.NumRows();
47 int32 num_features = raw_features.NumCols();
49 // Number of rows will be equal, but not
50 // columns, in general.
51 KALDI_ASSERT(dd_num_rows == sdc_num_rows);
53 // The raw mfcc features and the first first-order delta features
54 // will be identical in the SDC and Delta-Deltas.
55 for (int32 i = 0; i < dd_num_rows; i++) {
56 for (int32 j = 0; j < 2 * num_features; j++) {
57 BaseFloat a = deltas_features(i, j), b = shifted_deltas_features(i, j);
58 KALDI_ASSERT(std::abs(b - a) < 0.001);
59 }
60 }
61 }
63 static void UnitTestParams(Matrix<BaseFloat> &raw_features, int32 window,
64 int32 shift, int32 n_blocks) {
65 std::cout << "=== UnitTestSDCParams() ===\n";
66 ShiftedDeltaFeaturesOptions shifted_deltas_opts;
67 shifted_deltas_opts.window = window;
68 shifted_deltas_opts.num_blocks = n_blocks;
69 shifted_deltas_opts.block_shift = shift;
71 Matrix<BaseFloat> shifted_deltas_features;
72 ComputeShiftedDeltas(shifted_deltas_opts,
73 raw_features,
74 &shifted_deltas_features);
76 int32 raw_num_cols = raw_features.NumCols();
77 int32 sdc_num_rows = shifted_deltas_features.NumRows();
78 int32 sdc_num_cols = shifted_deltas_features.NumCols();
80 KALDI_ASSERT(sdc_num_cols == raw_num_cols * (n_blocks + 1));
82 /* For every coefficient in the raw feature vector a
83 delta is calculated and appended to the new feature vector,
84 as is done normally in a delta-deltas computation.
85 In addition, n_blocks delta in advance are also appended.
86 Somewhere in advance of the current position, say at
87 t + l these additional delta are the first order deltas
88 at that position (t + l). The following code works out a
89 mapping from these additional deltas to where they would
90 appear in a delta-deltas computation and verfies these
91 values' equality. */
92 for (int32 i = 0; i < sdc_num_rows; i++) {
93 for (int32 j = 2 * raw_num_cols; j < sdc_num_cols; j += raw_num_cols) {
94 for (int32 k = 0; k < raw_num_cols; k++) {
95 int32 row = i + (j/raw_num_cols - 1) * shift;
96 if (row < sdc_num_rows) {
97 BaseFloat a = shifted_deltas_features(i, j + k);
98 BaseFloat b = shifted_deltas_features(row, raw_num_cols + k);
99 KALDI_ASSERT(std::abs(a - b) < 0.001);
100 }
101 }
102 }
103 }
104 }
106 static void UnitTestEndEffects(Matrix<BaseFloat> &raw_features, int32 window,
107 int32 shift, int32 n_blocks) {
108 std::cout << "=== UnitTestSDCEndEffects() ===\n";
109 ShiftedDeltaFeaturesOptions shifted_deltas_opts;
110 shifted_deltas_opts.window = window;
111 shifted_deltas_opts.num_blocks = n_blocks;
112 shifted_deltas_opts.block_shift = shift;
114 Matrix<BaseFloat> shifted_deltas_features;
115 ComputeShiftedDeltas(shifted_deltas_opts,
116 raw_features,
117 &shifted_deltas_features);
118 int32 raw_num_cols = raw_features.NumCols();
119 int32 sdc_num_rows = shifted_deltas_features.NumRows();
120 int32 sdc_num_cols = shifted_deltas_features.NumCols();
122 // If the entire window is out-of-bounds the delta should be zero.
123 for (int32 i = sdc_num_rows - n_blocks + 1; i < sdc_num_rows; i++) {
124 for (int32 j = 2 * raw_num_cols; j < sdc_num_cols; j += raw_num_cols) {
125 for (int32 k = 0; k < raw_num_cols; k++) {
126 if (i + (j/raw_num_cols - 1) * shift - window/2 > sdc_num_rows)
127 KALDI_ASSERT(shifted_deltas_features(i, j + k) <= 0.00001);
128 }
129 }
130 }
131 }
133 int main() {
134 std::ifstream is("test_data/test.wav", std::ios_base::binary);
135 WaveData wave;
136 wave.Read(is);
137 KALDI_ASSERT(wave.Data().NumRows() == 1);
138 SubVector<BaseFloat> waveform(wave.Data(), 0);
140 // mfcc with default configuration...
141 MfccOptions op;
142 op.frame_opts.dither = 0.0;
143 op.frame_opts.preemph_coeff = 0.0;
144 op.frame_opts.window_type = "hamming";
145 op.frame_opts.remove_dc_offset = false;
146 op.frame_opts.round_to_power_of_two = true;
147 op.mel_opts.low_freq = 0.0;
148 op.use_energy = false;
149 Mfcc mfcc(op);
150 Matrix<BaseFloat> raw_features;
151 mfcc.Compute(waveform, 1.0, &raw_features);
153 try {
154 for (int32 window = 1; window < 4; window++) {
155 UnitTestCompareWithDeltaFeatures(raw_features, window);
156 for (int32 shift = 1; shift < 10; shift++) {
157 for (int32 n_blocks = 1; n_blocks < 20; n_blocks += 3) {
158 UnitTestParams(raw_features, window, shift, n_blocks);
159 UnitTestEndEffects(raw_features, window, shift, n_blocks);
160 }
161 }
162 }
163 return 0;
164 } catch (const std::exception &e) {
165 static_cast<void>(e);
166 return 1;
167 }
169 }