annotate tests/TestPhaseVocoder.cpp @ 115:f3c69325cca2 pvoc

Do actual phase unwrapping in the phase vocoder!
author Chris Cannam
date Wed, 02 Oct 2013 15:05:34 +0100
parents 3cb359d043f0
children 7f5b96734c83
rev   line source
Chris@112 1
Chris@112 2 #include "dsp/phasevocoder/PhaseVocoder.h"
Chris@112 3
Chris@112 4 #include "base/Window.h"
Chris@112 5
Chris@112 6 #define BOOST_TEST_DYN_LINK
Chris@112 7 #define BOOST_TEST_MAIN
Chris@112 8
Chris@112 9 #include <boost/test/unit_test.hpp>
Chris@112 10
Chris@112 11 BOOST_AUTO_TEST_SUITE(TestFFT)
Chris@112 12
Chris@112 13 #define COMPARE_CONST(a, n) \
Chris@112 14 for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
Chris@112 15 BOOST_CHECK_SMALL(a[cmp_i] - n, 1e-14); \
Chris@112 16 }
Chris@112 17
Chris@112 18 #define COMPARE_ARRAY(a, b) \
Chris@112 19 for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
Chris@112 20 BOOST_CHECK_SMALL(a[cmp_i] - b[cmp_i], 1e-14); \
Chris@112 21 }
Chris@112 22
Chris@112 23 #define COMPARE_ARRAY_EXACT(a, b) \
Chris@112 24 for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
Chris@112 25 BOOST_CHECK_EQUAL(a[cmp_i], b[cmp_i]); \
Chris@112 26 }
Chris@112 27
Chris@112 28 BOOST_AUTO_TEST_CASE(fullcycle)
Chris@112 29 {
Chris@115 30 // Cosine with one cycle exactly equal to pvoc hopsize. This is
Chris@115 31 // pretty much the most trivial case -- in fact it's
Chris@115 32 // indistinguishable from totally silent input (in the phase
Chris@115 33 // values) because the measured phases are zero throughout.
Chris@115 34
Chris@115 35 // We aren't windowing the input frame because (for once) it
Chris@115 36 // actually *is* just a short part of a continuous infinite
Chris@115 37 // sinusoid.
Chris@112 38
Chris@112 39 double frame[] = { 1, 0, -1, 0, 1, 0, -1, 0 };
Chris@112 40
Chris@115 41 PhaseVocoder pvoc(8, 4);
Chris@112 42
Chris@112 43 // Make these arrays one element too long at each end, so as to
Chris@112 44 // test for overruns. For frame size 8, we expect 8/2+1 = 5
Chris@112 45 // mag/phase pairs.
Chris@112 46 double mag[] = { 999, 999, 999, 999, 999, 999, 999 };
Chris@112 47 double phase[] = { 999, 999, 999, 999, 999, 999, 999 };
Chris@115 48 double unw[] = { 999, 999, 999, 999, 999, 999, 999 };
Chris@112 49
Chris@115 50 pvoc.process(frame, mag + 1, phase + 1, unw + 1);
Chris@112 51
Chris@112 52 double magExpected0[] = { 999, 0, 0, 4, 0, 0, 999 };
Chris@112 53 COMPARE_ARRAY_EXACT(mag, magExpected0);
Chris@112 54
Chris@112 55 double phaseExpected0[] = { 999, 0, 0, 0, 0, 0, 999 };
Chris@112 56 COMPARE_ARRAY_EXACT(phase, phaseExpected0);
Chris@112 57
Chris@115 58 double unwExpected0[] = { 999, 0, 0, 0, 0, 0, 999 };
Chris@115 59 COMPARE_ARRAY(unw, unwExpected0);
Chris@115 60
Chris@115 61 pvoc.process(frame, mag + 1, phase + 1, unw + 1);
Chris@112 62
Chris@112 63 double magExpected1[] = { 999, 0, 0, 4, 0, 0, 999 };
Chris@112 64 COMPARE_ARRAY_EXACT(mag, magExpected1);
Chris@112 65
Chris@115 66 double phaseExpected1[] = { 999, 0, 0, 0, 0, 0, 999 };
Chris@112 67 COMPARE_ARRAY(phase, phaseExpected1);
Chris@113 68
Chris@115 69 // Derivation of values:
Chris@115 70 //
Chris@115 71 // * Bin 0 (DC) always has phase 0 and expected phase 0
Chris@115 72 //
Chris@115 73 // * Bin 1 has expected phase pi (the hop size is half a cycle at
Chris@115 74 // its frequency), but measured phase 0 (because there is no
Chris@115 75 // signal in that bin). So it has phase error -pi, which is
Chris@115 76 // mapped into (-pi,pi] range as pi, giving an unwrapped phase
Chris@115 77 // of 2*pi.
Chris@115 78 //
Chris@115 79 // * Bin 2 has expected unwrapped phase 2*pi, measured phase 0,
Chris@115 80 // hence error 0 and unwrapped phase 2*pi.
Chris@115 81 //
Chris@115 82 // * Bin 3 is like bin 1: it has expected phase 3*pi, measured
Chris@115 83 // phase 0, so phase error -pi and unwrapped phase 4*pi.
Chris@115 84 //
Chris@115 85 // * Bin 4 (Nyquist) is like bin 2: expected phase 4*pi, measured
Chris@115 86 // phase 0, hence error 0 and unwrapped phase 4*pi.
Chris@115 87
Chris@115 88 double unwExpected1[] = { 999, 0, 2*M_PI, 2*M_PI, 4*M_PI, 4*M_PI, 999 };
Chris@115 89 COMPARE_ARRAY(unw, unwExpected1);
Chris@115 90
Chris@115 91 pvoc.process(frame, mag + 1, phase + 1, unw + 1);
Chris@113 92
Chris@113 93 double magExpected2[] = { 999, 0, 0, 4, 0, 0, 999 };
Chris@113 94 COMPARE_ARRAY_EXACT(mag, magExpected2);
Chris@113 95
Chris@115 96 double phaseExpected2[] = { 999, 0, 0, 0, 0, 0, 999 };
Chris@113 97 COMPARE_ARRAY(phase, phaseExpected2);
Chris@115 98
Chris@115 99 double unwExpected2[] = { 999, 0, 4*M_PI, 4*M_PI, 8*M_PI, 8*M_PI, 999 };
Chris@115 100 COMPARE_ARRAY(unw, unwExpected2);
Chris@112 101 }
Chris@112 102
Chris@115 103 //!!! signal that starts mid-phase
Chris@115 104
Chris@115 105
Chris@112 106 BOOST_AUTO_TEST_SUITE_END()
Chris@112 107