annotate yeti/cqtkernel.yeti @ 6:3caae61fa53f

Sparse etc
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 25 Oct 2013 11:53:28 +0100
parents 6b59109469c4
children 3cbf89635f34
rev   line source
c@1 1
c@1 2 module cqtkernel;
c@1 3
c@3 4 vec = load may.vector;
c@3 5 bf = load may.vector.blockfuncs;
c@3 6 complex = load may.complex;
c@3 7 window = load may.signal.window;
c@3 8 fft = load may.transform.fft;
c@4 9 pl = load may.plot;
c@6 10 cm = load may.matrix.complex;
c@3 11
c@2 12 { pow, round, floor, ceil, nextPowerOfTwo } = load may.mathmisc;
c@1 13
c@1 14 fs = 48000;
c@1 15
c@1 16 fmax = fs/2;
c@1 17
c@1 18 bins = 24;
c@1 19
c@1 20 q = 1;
c@1 21
c@1 22 atomHopFactor = 0.25;
c@1 23
c@1 24 thresh = 0.0005;
c@1 25
c@1 26 fmin = (fmax/2) * (pow 2 (1/bins));
c@1 27
c@1 28 bigQ = q / ((pow 2 (1/bins)) - 1);
c@1 29
c@1 30 nk_max = round(bigQ * fs / fmin);
c@1 31
c@1 32 nk_min = round(bigQ * fs / (fmin * (pow 2 ((bins-1)/bins))));
c@1 33
c@1 34 atomHop = round(nk_min * atomHopFactor);
c@1 35
c@1 36 first_center = atomHop * Math#ceil(Math#ceil(nk_max/2) / atomHop);
c@1 37
c@1 38 fftLen = nextPowerOfTwo (first_center + Math#ceil(nk_max/2));
c@1 39
c@1 40 println "fs = \(fs), fmax = \(fmax), bins = \(bins), q = \(q), atomHopFactor = \(atomHopFactor), thresh = \(thresh)";
c@1 41
c@1 42 println "fmin = \(fmin), bigQ = \(bigQ), nk_max = \(nk_max), nk_min = \(nk_min), atomHop = \(atomHop), first_center = \(first_center), fftLen = \(fftLen)";
c@1 43
c@2 44 winNr = floor((fftLen - ceil(nk_max/2) - first_center) / atomHop) + 1;
c@2 45
c@2 46 last_center = first_center + (winNr - 1) * atomHop;
c@2 47
c@2 48 fftHop = (last_center + atomHop) - first_center;
c@2 49
c@2 50 fftOverlap = ((fftLen - fftHop) / fftLen) * 100; // as % -- why? just for diagnostics?
c@2 51
c@2 52 println "winNr = \(winNr), last_center = \(last_center), fftHop = \(fftHop), fftOverlap = \(fftOverlap)%";
c@2 53
c@3 54 fftFunc = fft.forward fftLen;
c@2 55
c@3 56 // Note the MATLAB uses exp(2*pi*1i*x) for a complex generating
c@3 57 // function. We can't do that here; we need to generate real and imag
c@3 58 // parts separately as real = cos(2*pi*x), imag = sin(2*pi*x).
c@2 59
c@3 60 kernels = map do k:
c@3 61
c@3 62 nk = round(bigQ * fs / (fmin * (pow 2 ((k-1)/bins))));
c@3 63 println "k = \(k) -> nk = \(nk)";
c@3 64
c@3 65 win = bf.divideBy nk (bf.sqrt (window.blackmanHarris nk));
c@3 66
c@3 67 fk = fmin * (pow 2 ((k-1)/bins));
c@3 68
c@3 69 println "fk = \(fk)";
c@3 70
c@3 71 genKernel f = bf.multiply win
c@3 72 (vec.fromList (map do i: f (2 * pi * fk * i / fs) done [0..nk-1]));
c@3 73
c@3 74 reals = genKernel cos;
c@3 75 imags = genKernel sin;
c@3 76
c@3 77 atomOffset = first_center - ceil(nk/2);
c@3 78
c@3 79 map do i:
c@3 80
c@3 81 shift = atomOffset + ((i-1) * atomHop);
c@3 82
c@4 83 println "shift = \(shift)";
c@4 84
c@6 85 shiftedReals = vec.concat [vec.zeros shift, reals];
c@6 86 shiftedImags = vec.concat [vec.zeros shift, imags];
c@6 87
c@6 88 // println "shiftedReals = \(vec.list shiftedReals)";
c@6 89 // println "shiftedImags = \(vec.list shiftedImags)";
c@6 90
c@3 91 specKernel = fftFunc
c@3 92 (complex.complexArray
c@3 93 (vec.concat [vec.zeros shift, reals])
c@3 94 (vec.concat [vec.zeros shift, imags]));
c@3 95
c@3 96 map do c:
c@6 97 if complex.magnitude c < thresh then complex.zero else c fi
c@3 98 done specKernel;
c@4 99
c@3 100 done [1..winNr];
c@3 101
c@3 102 done [1..bins];
c@3 103
c@6 104 kmat = cm.toSparse
c@6 105 (cm.scaled (1/fftLen)
c@6 106 (cm.newComplexMatrix (ColumnMajor()) (concat kernels))); // or row major?
c@2 107
c@6 108 println "density = \(cm.density kmat)";
c@1 109
c@6 110 kmat;
c@5 111
c@6 112
c@6 113