//-------------------------------------------------------------------------- //constant Q transform static Complex[,] constantQ_transform(double[] wavdata) { double[] new_wavdata; Complex[,] kernel; Complex[,] output; int wav_length = wavdata.Length; int T_step; int F_step; int fft_step; int fft_start_point; int hop; double[] freqs = get_freqs(fmin, get_freq_num(fmin, fmax, fratio), fratio); kernel = calcKernel_matrix(freqs); hop = (int)(Math.Round(0.01 * fs)); //100 frames per 1 sec T_step = wav_length / hop; F_step = freqs.Length; fft_step = (int)(Math.Pow(2, Math.Ceiling((Math.Log(fs * Q / freqs[0], 2))))); //greater than Max of N[k] new_wavdata = new double[wav_length + fft_step]; output = new Complex[F_step, T_step]; for (int i = 0; i < wav_length; i++) { new_wavdata[i + fft_step / 2] = wavdata[i]; } for (int t = 0; t < T_step; t++) { fft_start_point = hop * t; Complex[] partial_data = new Complex[fft_step]; for (int i = 0; i < fft_step; i++) { partial_data[i] = new Complex(new_wavdata[fft_start_point + i], 0); } Complex[] fft = Nm.FastFourierTransform(partial_data, true); Complex[] cq = new Complex[F_step]; for (int i = 0; i < F_step; i++) { for (int j = 0; j < fft.Length; j++) //fft.Length = fft_step { cq[i] += fft[j] * kernel[i, j]; } } for (int f = 0; f < F_step; f++) { output[f, t] = cq[f]; } } return(output); }
//-------------------------------------------------------------------------- //Kernel行列の計算 static Complex[,] calcKernel_matrix(double[] freqs) { //窓幅N[k]の最大値 int fftlen = (int)(Math.Pow(2, Math.Ceiling((Math.Log(fs * Q / freqs[0], 2))))); Complex[,] kernel = new Complex[freqs.Length, fftlen]; Complex[] tmp_kernel = new Complex[fftlen]; for (int k = 0; k < freqs.Length; k++) { double freq = freqs[k]; int N_k = (int)((double)(fs * Q) / freq); //窓幅 int start_win = (fftlen - N_k) / 2; //FFT窓の中心を解析部分に合わせる double[] hamming = new double[N_k]; for (int i = 0; i < N_k; i++) { hamming[i] = 1; } Nm.Windowing(hamming, Nm.DataWindowType.Hamming); for (int i = start_win; i < start_win + N_k; i++) { tmp_kernel[i] = hamming[i - start_win] / N_k * Complex.Exp(2 * Math.PI * Complex.ImaginaryOne * Q * (i - start_win) / N_k); } tmp_kernel = Nm.FastFourierTransform(tmp_kernel, false); //sw==falseでfftlenで割る double[] d = new double[tmp_kernel.Length]; for (int i = 0; i < tmp_kernel.Length; i++) { d[i] = tmp_kernel[i].Magnitude; } double max = d.Max(); for (int i = 0; i < fftlen; i++) { //if (tmp_kernel[i].Magnitude <= 0.0054) // kernel[k, i] = Complex.Zero; //else kernel[k, i] = Complex.Conjugate(tmp_kernel[i]); } } return(kernel); }