

2 % write a genkern like genkern.c for a const Q trans (?? genkern was for transform from fft)
3 % %
4 % % Example: [kerncos, kernsin, freqs ] = genlgftkern( 174.6141 , 1.0293022366 , 11025 , 120 , 1102 );
5 %
6 % nfreqs and windsizmax optional but must input 0 if not a value
7 % will choose 100 ms max and nfreqs up to Nyq
8 % minfreq = 440 / ( 2 ^ ( 1 / 12 )) ^ 16 ; % F3 174.6141 G3 = 195.9977
9 % nfreqs = 60 ;
10 % freqrat = 2 ^ ( 1 / 12 ); % 2 ^ ( 1 / 24 ) = 1.0293022366
11 % SR = 11025 ;
12 % windsizmax = fix(. 1 * SR); % take a 100 ms max
13
14 function [kerncos, kernsin, freqs] = genlgftkern(minfreq, freqrat, SR, nfreqs, windsizmax, winnam, constwind);
15
16 if (exist( ' constwind ' ) & constwind ~= 0 ), fprintf( ' genlgftkern; Calculating kernels with constant windowsiz = %.0f\n ' , constwind);
17 elseif ~ exist( ' constwind ' ), constwind = 0;
18 end
19 % Put these steps back in if want to run this prog indep of logftS
20 % if (nargin < 5 | windsizmax == 0) % no input windsizmax
21 % if windsizmax == 0
22 % windsizmax = floor( . 1 * SR); % take a 100 ms max
23 % fprintf( ' No input maximum window size. Taking 100 ms max.\n ' );
24 % end
25 % if (nargin < 4 | nfreqs == 0) % no nfreqs either
26 % if nfreqs == 0
27 % nfreqs = fix( log(SR / ( 2 * minfreq)) / log(freqrat) ); % to give highest freq at the Nyq
28 % fprintf( ' No input number of freqs; taking freqs from minfreq to Nyquist = %.0f freq bins\n ' , nfreqs);
29 % end
30
31 % winnam = ' hamming ' ;
32 if ~ exist( ' winnam ' ), winnam = ' hamming ' ;
33 fprintf( ' Using default window Hamming\n ' );
34 else , fprintf( ' Input window %s \n ' , winnam);
35 end
36 if winnam( 1 : 4 ) == ' rect ' , winnam = ' boxcar ' ; end
37
38 Q = 1 / (freqrat - 1 );
39 TWOPI = 2 * pi;
40 mindigfreq = TWOPI * minfreq / SR;
41 freqs = minfreq * (freqrat . ^ [(0: 1 :nfreqs - 1 )]);
42 pos = find(freqs < SR / 2 );
43 freqs = freqs(pos);
44 nfreqs = length(freqs);
45 digfreq = freqs * TWOPI / SR;
46 % shouldn ' t need the following since fixed up freqs
47 if sum(find(digfreq > pi)) ~= 0, error( ' freq over Nyq ' ); end
48
49 flag = 1 ;
50 if constwind == 0
51 windsizOk = fix (TWOPI * Q . / digfreq); % period in samples time Q
52 % arg = (pi / 2 ) * ones(nfreqs, windsiz);
53 windsizmax;
54 windsizOk( 1 );
55 if (windsizmax > windsizOk( 1 )),
56 windsizmax = windsizOk( 1 );
57 flag = 0;
58 end
59 pos = find(windsizOk > windsizmax);
60 % if windsizmax < windsizOk( 1 ) so get some windows not as long as necess for that Q
61 if (flag)
62 fprintf( ' genlgftkern: Const window %.0f up to freq position %.0f and frequency %.0f out of %.0f frequencies. windsizMinfreq = %.0f Q=%.1f\n ' , ...
63 windsizmax, max(pos), digfreq(max(pos)) * SR / ( 2 * pi), length(digfreq), windsizOk( 1 ), Q);
64 else
65 fprintf( ' genlgftkern: No const window; windsizmax = %.0f = windsizMinfreq = %.0f Q=%.1f\n ' , ...
66 windsizmax, windsizOk( 1 ), Q);
67 end
68 fprintf( ' \n ' );
69 windsizOk(pos) = windsizmax;
70
71 kerncos = zeros(nfreqs, windsizOk( 1 ) );
72 kernsin = zeros(nfreqs, windsizOk( 1 ) );
73 numzeros = windsizOk( 1 ) - windsizOk;
74 numzerosO2 = round(numzeros / 2 );
75
76 else
77 kerncos = zeros(nfreqs, constwind );
78 kernsin = zeros(nfreqs, constwind );
79 end
80
81 % Get kaiser number if window is kaiser
82 if length(winnam) > 5
83 if winnam( 1 : 6 ) == ' kaiser '
84 if length(winnam) == 7 , kaiserno = winnam( 7 );
85 elseif length(winnam) == 8 , kaiserno = winnam( 7 : 8 );
86 else , kaiserno = ' 8 ' ; % default is 8 for no input kaiser number
87 end
88 winnam = ' kaiser ' ;
89 end
90 end
91
92 if constwind == 0,
93 for k = 1 :nfreqs
94 sz = windsizOk(k);
95 switch(winnam)
96 case ' kaiser '
97 winstr = [ winnam ' ( ' num2str(sz) ' , ' kaiserno ' ) ' ];
98 otherwise
99 winstr = [ winnam ' ( ' num2str(sz) ' ) ' ];
100 end
101 % fprintf( ' calc window %s \n ' , winstr);
102 wind = eval(winstr);
103 wind = wind ' ;
104
105 % wind = boxcar(windsizOk(k)) ' ;
106 numz = 1 ;
107 if numzerosO2(k) ~= 0, numz = numzerosO2(k); end;
108 kerncos(k, numz: numz + windsizOk(k) - 1 ) = ( 1 / windsizOk(k)) * ...
109 cos(digfreq(k) * ( - sz / 2 : sz / 2 - 1 )). * wind;
110 % cos(digfreq(k) * (0:windsizOk(k) - 1 )). * wind;
111
112 % cos(digfreq(k) * (0:windsizOk(k) - 1 )). * wind(( 1 :windsizOk(k)));
113 kernsin(k, numz: numz + windsizOk(k) - 1 ) = ( 1 / windsizOk(k)) * ...
114 sin(digfreq(k) * ( - sz / 2 : sz / 2 - 1 )). * wind;
115 % sin(digfreq(k) * (0:windsizOk(k) - 1 )). * wind;
116 % sin(digfreq(k) * (0:windsizOk(k) - 1 )). * wind(( 1 :windsizOk(k)));
117 end
118 else
119 for k = 1 :nfreqs
120 sz = constwind;
121 switch(winnam)
122 case ' kaiser '
123 winstr = [ winnam ' ( ' num2str(sz) ' , ' kaiserno ' ) ' ];
124 otherwise
125 winstr = [ winnam ' ( ' num2str(sz) ' ) ' ];
126 end
127 % fprintf( ' calc window %s \n ' , winstr);
128 wind = eval(winstr);
129 wind = wind ' ;
130
131 % wind = boxcar(windsizOk(k)) ' ;
132
133 kerncos(k, 1 : constwind) = (cos(digfreq(k) * ( - constwind / 2 : constwind / 2 - 1 ))). * wind;
134 % kerncos(k, 1 : constwind) = (cos(digfreq(k) * (0:constwind - 1 ))). * wind;
135
136 % cos(digfreq(k) * (0:windsizOk(k) - 1 )). * wind(( 1 :windsizOk(k)));
137 kernsin(k, 1 : constwind) = (sin(digfreq(k) * ( - constwind / 2 : constwind / 2 - 1 ))). * wind;
138 % kernsin(k, 1 :constwind) = (sin(digfreq(k) * (0:constwind - 1 ))). * wind;
139 end
140 end
141
142 % fprintf( ' nfreqs = %.0f ; windsizmax = %.0f \n ' ,nfreqs, windsizmax);
143 ...
http://www.elec.qmul.ac.uk/people/anssik/cqt/smc2010.pdf
http://www.elec.qmul.ac.uk/people/anssik/cqt/
CQT
CQT把时域信号转换到时频域,使得频率下标的中心频率是成几何间隔排列的,并且Q因子相等。这意味着在低频域有这很好的频率分辨率,在高频域有好的时间分辨率。
CQT本质上是一种小波变换,但是我们考虑相对高Q因子的变换,等效于每八度音阶12-96个下标。很多传统的小波变换不满足这些要求,例如基于迭代滤波器组的方法要求对输入信号进行几百次滤波。
西方音乐
十二平均律
F0s
从听觉的角度看,从20khz到500hz,外围听觉系统的频率分辨率是近似常Q的,低于这个范围Q值减小。从感知音频编码的角度看,最短的变换窗长必须是3ms为了保证高的质量,然而,在低频率编码需要更高的频率分辨率。
传统的DFT是线性间隔的频率下标,因此在可听见频率的范围内,不能满足变化的时间和频率分辨率的要求。
三个关键问题,使得目前在音频信号处理中,CQT没有广泛地代替DFT
高的计算代价
没有逆变换能够从变换系数,完美地重建原始信号
在连续的时间帧里很难处理时频矩阵。不同的频率下标的抽样是不同步的。
Brown and Puckette提出一个计算有效的带有高品质因子的常Q变换,基于FFT和一个频域核。CQT实现的缺点是没有逆变换。
FitzGerald提出一个好的近似逆变换的,如果反转的信号在DFT域有稀疏的表达。但,一般地说,这对乐音信号是不准确的。
k=1,2,…,K
是下标k的中心频率
指示了采样率
是连续窗函数,在
范围外是0.
最低的中心频率,B每八度音阶的下标数目,是CQT最重要的参数,确定了时频分辨率
是原子
频率响应的-3db带宽,并且
是窗函数频谱主瓣-3db带宽,
。
理想的Q尽可能大,为了使带宽
尽可能小,因此引入了最小频率拖尾。
是一个尺度因子,典型地q=1.
q值越小,则时间分辨率越好,但频率分辨率降低。
q=0.5和B=48与q=1和B=24获得一样的时频分辨率,但是前者每八度音阶包含两倍的频率下表。q<1可以堪称频率轴的过采样,类似于DFT时的补零。例如q=0.5对应于过采样因子2,有效的频率分辨率等于每八度音阶B/2个下标,尽管计算了B个下标。
与
无关
为了达到合理的信号重建,
3.1 Algorithm of Brown and Puckette
X(j)是x(n)的DFT,并且A(j)是a(n)的DFT.Parsecal’s
theorem
Ak(j)是n点ak(n)变换基的DFT,ak(n)是N/2变换帧的中心。Ak(j)是谱核,是稀疏的,作为A的一列。 ak(n)是时域核。