ฉันจะใช้หน้าต่างชวเลขสำหรับ "ฟังก์ชั่นหน้าต่าง"
ด้วยเสียงการประมวลผลใด ๆ ที่สร้างสิ่งที่คล้ายกับเสียงกริ่งหรือเสียงก้องล่วงหน้าจะให้เสียงที่ลื่นเหมือน MP3 ที่อัตราบิตต่ำ สิ่งนี้เกิดขึ้นเมื่อพลังงานที่ถูกแปลของพลังงานชั่วคราวหรือแรงกระตุ้นถูกกระจายไปข้างหลังในเวลาตัวอย่างเช่นโดยการดัดแปลงข้อมูลสเปกตรัมในการแปลงแบบ lapped เช่นการแปลงโคไซน์ที่ไม่ต่อเนื่องแบบดัดแปลง ในการประมวลผลเช่นนั้นเสียงจะถูกเรียงซ้อนโดยหน้าต่างการวิเคราะห์ที่ซ้อนทับกันแปลงประมวลผลในโดเมนความถี่ (เช่นบีบอัดข้อมูลเป็นบิตเรตที่เล็กกว่า) หน้าต่างอีกครั้งด้วยหน้าต่างการสังเคราะห์และรวมกลับมารวมกัน ผลิตภัณฑ์ของหน้าต่างการวิเคราะห์และการสังเคราะห์ต้องเป็นหน้าต่างที่ซ้อนทับกันเพื่อรวมเป็นหนึ่ง
แต่เดิมฟังก์ชั่นหน้าต่างที่ใช้มีความสมมาตรและความกว้างของมันได้รับการประนีประนอมระหว่างการเลือกความถี่ (หน้าต่างยาว) และการหลีกเลี่ยงสิ่งประดิษฐ์โดเมนเวลา (หน้าต่างสั้น) ยิ่งหน้าต่างกว้างมากเท่าไรเวลาที่การประมวลผลก็จะสามารถแพร่สัญญาณได้มากขึ้น วิธีแก้ปัญหาล่าสุดคือการใช้หน้าต่างอสมมาตร หน้าต่างสองบานที่ใช้สามารถสะท้อนภาพของกันและกัน หน้าต่างการวิเคราะห์จะลดลงจากจุดสูงสุดเป็นศูนย์อย่างรวดเร็วเพื่อไม่ให้มีการตรวจพบแรงกระตุ้นล่วงหน้าและหน้าต่าง syntheis จะเพิ่มขึ้นจากศูนย์ถึงจุดสูงสุดอย่างรวดเร็วดังนั้นผลของการประมวลผลใด ๆ จะไม่กระจายไปด้านหลังมากนัก ข้อดีอีกอย่างของความล่าช้านี้คือ หน้าต่างแบบอสมมาตรสามารถเลือกความถี่ได้ดีและสามารถแทนที่หน้าต่างแบบสมมาตรขนาดแปรผันในการบีบอัดสัญญาณเสียงได้เหมือนวิธีรักษาแบบทั้งหมด ดูM. Schnell, M. Schmidt, M. Jander, T. Albert, R. Geiger, V. Ruoppila, P. Ekstrand, M. Lutzky, B. Grill, “ MPEG-4 Enhanced Low Delay AAC - มาตรฐานใหม่สำหรับความแรงสูง การสื่อสารที่มีคุณภาพ” , การประชุม AES ครั้งที่ 125, ซานฟรานซิสโก, แคลิฟอร์เนีย, สหรัฐอเมริกา, พิมพ์ล่วงหน้า 7503, ต.ค. 2551และเอกสารการประชุมอีกฉบับหนึ่งที่แสดงถึงขนาดของการแปลงฟูริเยร์ที่หน้าต่าง: Schnell, M. , et al. 2550. AAC ที่เพิ่มความล่าช้าต่ำระดับ MPEG-4 - การสื่อสารคุณภาพสูงบิตเรตต่ำ ในการประชุม 122th AES
รูปที่ 1 ภาพประกอบการใช้หน้าต่างอสมมาตรในการวิเคราะห์การประมวลผลแบบ lapped ผลิตภัณฑ์ (เส้นประสีดำ) ของหน้าต่างการวิเคราะห์ (สีน้ำเงิน) และหน้าต่างการสังเคราะห์ (สีส้มเหลือง) จะรวมเป็นหนึ่งกับหน้าต่างจากกรอบก่อนหน้า (เส้นประสีเทา) จำเป็นต้องมีข้อ จำกัด เพิ่มเติมเพื่อรับประกันการสร้างใหม่ที่สมบูรณ์แบบเมื่อใช้ MDCT
การแปลงฟูริเยร์แบบไม่ต่อเนื่อง (DFT, FFT) สามารถนำมาใช้แทน MDCT ได้ แต่ในบริบทดังกล่าวจะให้ข้อมูลสเปกตรัมซ้ำซ้อน เมื่อเทียบกับ DFT MDCT จะให้ข้อมูลสเปกตรัมเพียงครึ่งเดียวในขณะที่ยังคงสามารถสร้างใหม่ได้อย่างสมบูรณ์แบบหากเลือกหน้าต่างที่เหมาะสม
นี่คือการออกแบบหน้าต่างอสมมาตรของฉันเอง (รูปที่ 2) เหมาะสำหรับการสังเคราะห์การประมวลผลการวิเคราะห์แบบ lapped โดยใช้ DFT แต่ไม่ใช่ MDCT ซึ่งไม่ได้สร้างขึ้นมาใหม่อย่างสมบูรณ์แบบ หน้าต่างพยายามลดผลิตภัณฑ์ของแบนด์วิดท์เวลาเฉลี่ยและความถี่แบนด์วิดท์ (คล้ายกับหน้าต่าง Gaussian ที่ จำกัด ) ในขณะที่ยังคงรักษาคุณสมบัติโดเมนเวลาที่มีประโยชน์: nonnegative, unimodal กับจุดสูงสุดที่ "time zero" ซึ่งการวิเคราะห์และสังเคราะห์ windows เป็นภาพสะท้อนของกันและกันฟังก์ชันและความต่อเนื่องของอนุพันธ์อันดับแรกศูนย์ - ค่าเฉลี่ยเมื่อฟังก์ชันสี่เหลี่ยมของหน้าต่างถูกตีความว่าเป็นฟังก์ชันความหนาแน่นของความน่าจะเป็นแบบผิดปกติ หน้าต่างที่ได้รับการเพิ่มประสิทธิภาพการใช้วิวัฒนาการค่า
รูปที่ 2 ด้านซ้าย: หน้าต่างการวิเคราะห์แบบอสมมาตรเหมาะสำหรับการวิเคราะห์การประมวลผลและการสังเคราะห์ซ้ำที่ซ้อนทับกันพร้อมกับหน้าต่างการสังเคราะห์คู่ที่กลับด้านเวลา ขวา: หน้าต่างโคไซน์โดยมีเวลาแฝงเท่ากับหน้าต่างอสมมาตร
รูปที่ 3 ขนาดของการแปลงฟูริเยร์ของหน้าต่างโคไซน์ (สีฟ้า) และหน้าต่างอสมมาตร (สีส้ม) ของรูปที่ 2. หน้าต่างอสมมาตรแสดงการเลือกความถี่ที่ดีขึ้น
นี่คือซอร์สโค้ดของ Octave สำหรับพล็อตและสำหรับหน้าต่างอสมมาตร รหัสพล็อตมาจากวิกิพีเดีย บน Linux ผมขอแนะนำให้ติดตั้งgnuplot
, epstool
, pstoedit
, transfig
ครั้งแรกและสำหรับการดูการใช้librsvg2-bin
display
pkg load signal
graphics_toolkit gnuplot
set (0, "defaultaxesfontname", "sans-serif")
set (0, "defaultaxesfontsize", 12)
set (0, "defaultaxeslinewidth", 1)
function plotWindow (w, wname, wfilename = "", wspecifier = "", wfilespecifier = "")
M = 32; % Fourier transform size as multiple of window length
Q = 512; % Number of samples in time domain plot
P = 40; % Maximum bin index drawn
dr = 130; % Maximum attenuation (dB) drawn in frequency domain plot
N = length(w);
B = N*sum(w.^2)/sum(w)^2 % noise bandwidth (bins)
k = [0 : 1/Q : 1];
w2 = interp1 ([0 : 1/(N-1) : 1], w, k);
if (M/N < Q)
Q = M/N;
endif
figure('position', [1 1 1200 600])
subplot(1,2,1)
area(k,w2,'FaceColor', [0 0.4 0.6], 'edgecolor', [0 0 0], 'linewidth', 1)
if (min(w) >= -0.01)
ylim([0 1.05])
set(gca,'YTick', [0 : 0.1 : 1])
else
ylim([-1 5])
set(gca,'YTick', [-1 : 1 : 5])
endif
ylabel('amplitude')
set(gca,'XTick', [0 : 1/8 : 1])
set(gca,'XTickLabel',[' 0'; ' '; ' '; ' '; ' '; ' '; ' '; ' '; 'N-1'])
grid('on')
set(gca,'gridlinestyle','-')
xlabel('samples')
if (strcmp (wspecifier, ""))
title(cstrcat(wname,' window'), 'interpreter', 'none')
else
title(cstrcat(wname,' window (', wspecifier, ')'), 'interpreter', 'none')
endif
set(gca,'Position',[0.094 0.17 0.38 0.71])
H = abs(fft([w zeros(1,(M-1)*N)]));
H = fftshift(H);
H = H/max(H);
H = 20*log10(H);
H = max(-dr,H);
k = ([1:M*N]-1-M*N/2)/M;
k2 = [-P : 1/M : P];
H2 = interp1 (k, H, k2);
subplot(1,2,2)
set(gca,'FontSize',28)
h = stem(k2,H2,'-');
set(h,'BaseValue',-dr)
xlim([-P P])
ylim([-dr 6])
set(gca,'YTick', [0 : -10 : -dr])
set(findobj('Type','line'),'Marker','none','Color',[0.8710 0.49 0])
grid('on')
set(findobj('Type','gridline'),'Color',[.871 .49 0])
set(gca,'gridlinestyle','-')
ylabel('decibels')
xlabel('bins')
title('Fourier transform')
set(gca,'Position',[0.595 0.17 0.385 0.71])
if (strcmp (wfilename, ""))
wfilename = wname;
endif
if (strcmp (wfilespecifier, ""))
wfilespecifier = wspecifier;
endif
if (strcmp (wfilespecifier, ""))
savetoname = cstrcat('Window function and frequency response - ', wfilename, '.svg');
else
savetoname = cstrcat('Window function and frequency response - ', wfilename, ' (', wfilespecifier, ').svg');
endif
print(savetoname, '-dsvg', '-S1200,600')
close
endfunction
N=2^17; % Window length, B is equal for Triangular and Bartlett from 2^17
k=0:N-1;
w = -cos(2*pi*k/(N-1));
w .*= w > 0;
plotWindow(w, "Cosine")
freqData = [0.66697133904805994131, -0.20556692772918355727, 0.49267389481655493588, -0.25062332863369246594, -0.42388422228212319087, 0.42317609537724842905, -0.03930334287740060856, -0.11936153294075849129, 0.30201210285940127687, -0.15541616804857899536, -0.16208119255594669039, 0.12843871362286504723, -0.04470810646117385351, -0.00521885027256757845, 0.07185811583185619522, -0.02835116723496184862, -0.01393644785822748498, 0.00780746224568363342, -0.00748496824751256583, 0.00119325723511989282, 0.00194602547595042175];
freqData(1) /= 2;
scale = freqData(1) + sum(freqData.*not(mod(1:length(freqData), 2)));
freqData /= scale;
w = freqData(1)*ones(1, N);
for bin = 1:(length(freqData)/2)
w += freqData(bin*2)*cos(2*pi*bin*((1:N)-1)/N);
w += freqData(bin*2+1)*sin(2*pi*bin*((1:N)-1)/N);
endfor
w(N/4+1:N/2+1) = 0;
w(N/8+2:N/4) = (1 - w(N/8:-1:2).*w(7*N/8+2:N))./w(7*N/8:-1:6*N/8+2);
w = shift(w, -N/2);
plotWindow(w, "Asymmetrical");
คุณอาจต้องการใช้ตัวอย่างหน้าต่างทุกวินาทีเท่านั้นเนื่องจากหน้าต่างจะเริ่มต้นและสิ้นสุดที่ศูนย์ รหัส C ++ ต่อไปนี้เป็นเช่นนั้นสำหรับคุณดังนั้นคุณจะไม่ได้รับตัวอย่างใด ๆ เป็นศูนย์ยกเว้นในหนึ่งในสี่ของหน้าต่างที่เป็นศูนย์ทุก สำหรับหน้าต่างการวิเคราะห์นี่เป็นไตรมาสแรกและสำหรับหน้าต่างการสังเคราะห์นี่เป็นไตรมาสสุดท้าย ช่วงครึ่งหลังของหน้าต่างการวิเคราะห์ควรจัดชิดกับครึ่งแรกของหน้าต่างการสังเคราะห์เพื่อคำนวณผลิตภัณฑ์ รหัสยังทดสอบค่าเฉลี่ยของหน้าต่าง (เป็นฟังก์ชันความหนาแน่นของความน่าจะเป็น) และนำเสนอความเรียบของการสร้างที่ซ้อนทับกัน
#include <stdio.h>
#include <math.h>
int main() {
const int windowSize = 400;
double *analysisWindow = new double[windowSize];
double *synthesisWindow = new double[windowSize];
for (int k = 0; k < windowSize/4; k++) {
analysisWindow[k] = 0;
}
for (int k = windowSize/4; k < windowSize*7/8; k++) {
double x = 2 * M_PI * ((k+0.5)/windowSize - 1.75);
analysisWindow[k] = 2.57392230162633461887-1.58661480271141974718*cos(x)+3.80257516644523141380*sin(x)
-1.93437090055110760822*cos(2*x)-3.27163999159752183488*sin(2*x)+3.26617449847621266201*cos(3*x)
-0.30335261753524439543*sin(3*x)-0.92126091064427817479*cos(4*x)+2.33100177294084742741*sin(4*x)
-1.19953922321306438725*cos(5*x)-1.25098147932225423062*sin(5*x)+0.99132076607048635886*cos(6*x)
-0.34506787787355830410*sin(6*x)-0.04028033685700077582*cos(7*x)+0.55461815542612269425*sin(7*x)
-0.21882110175036428856*cos(8*x)-0.10756484378756643594*sin(8*x)+0.06025986430527170007*cos(9*x)
-0.05777077835678736534*sin(9*x)+0.00920984524892982936*cos(10*x)+0.01501989089735343216*sin(10*x);
}
for (int k = 0; k < windowSize/8; k++) {
analysisWindow[windowSize-1-k] = (1 - analysisWindow[windowSize*3/4-1-k]*analysisWindow[windowSize*3/4+k])/analysisWindow[windowSize/2+k];
}
printf("Analysis window:\n");
for (int k = 0; k < windowSize; k++) {
printf("%d\t%.10f\n", k, analysisWindow[k]);
}
double accu, accu2;
for (int k = 0; k < windowSize; k++) {
accu += k*analysisWindow[k]*analysisWindow[k];
accu2 += analysisWindow[k]*analysisWindow[k];
}
for (int k = 0; k < windowSize; k++) {
synthesisWindow[k] = analysisWindow[windowSize-1-k];
}
printf("\nSynthesis window:\n");
for (int k = 0; k < windowSize; k++) {
printf("%d\t%.10f\n", k, synthesisWindow[k]);
}
printf("Mean of square of analysis window as probability density function:\n%f", accu/accu2);
printf("\nProduct of analysis and synthesis windows:\n");
for (int k = 0; k < windowSize/2; k++) {
printf("%d\t%.10f\n", k, analysisWindow[windowSize/2+k]*synthesisWindow[k]);
}
printf("\nSum of overlapping products of windows:\n");
for (int k = 0; k < windowSize/4; k++) {
printf("%d\t%.10f\n", k, analysisWindow[windowSize/2+k]*synthesisWindow[k]+analysisWindow[windowSize/2+k+windowSize/4]*synthesisWindow[k+windowSize/4]);
}
delete[] analysisWindow;
delete[] synthesisWindow;
}
และซอร์สโค้ดสำหรับฟังก์ชั่นต้นทุนการเพิ่มประสิทธิภาพที่จะใช้กับKiss FFTและไลบรารีการปรับให้เหมาะสม :
class WinProblem : public Opti::Problem {
private:
int numParams;
double *min;
double *max;
kiss_fft_scalar *timeData;
kiss_fft_cpx *freqData;
int smallSize;
int bigSize;
kiss_fftr_cfg smallFFTR;
kiss_fftr_cfg smallIFFTR;
kiss_fftr_cfg bigFFTR;
kiss_fftr_cfg bigIFFTR;
public:
// numParams must be odd
WinProblem(int numParams, int smallSize, int bigSize, double* candidate = NULL) : numParams(numParams), smallSize(smallSize), bigSize(bigSize) {
min = new double[numParams];
max = new double[numParams];
if (candidate != NULL) {
for (int i = 0; i < numParams; i++) {
min[i] = candidate[i]-fabs(candidate[i])*(1.0/65536);
max[i] = candidate[i]+fabs(candidate[i])*(1.0/65536);
}
} else {
for (int i = 0; i < numParams; i++) {
min[i] = -1;
max[i] = 1;
}
}
timeData = new kiss_fft_scalar[bigSize];
freqData = new kiss_fft_cpx[bigSize/2+1];
smallFFTR = kiss_fftr_alloc(smallSize, 0, NULL, NULL);
smallIFFTR = kiss_fftr_alloc(smallSize, 1, NULL, NULL);
bigFFTR = kiss_fftr_alloc(bigSize, 0, NULL, NULL);
bigIFFTR = kiss_fftr_alloc(bigSize, 1, NULL, NULL);
}
double *getMin() {
return min;
}
double *getMax() {
return max;
}
// ___ __ 1
// | \ | | | | | | | / |
// | \ | | | | | | | / |
// | \_ | | | | | | | / |
// | \|__ | | | | | | /| |
// | | -----|_______|___ | | | | / | |
// | | | | ----| | | |/ | |
// --------------------------------x-----------------------x---|---- 0
// 0 1/8 2/8 3/8 4/8 5/8 6/8 7/8 15/16
// |-------------------------------| |-------|
// zeroStarts winStarts
//
// f(x) = 0 if 4/8 < x < 7/8
// f(-x)f(x) + f(-x+1/8)f(x-1/8) = 1 if 0 < x < 1/8
double costFunction(double *params, double compare, int print) {
double penalty = 0;
double accu = params[0]/2;
for (int i = 1; i < numParams; i += 2) {
accu += params[i];
}
if (print) {
printf("%.20f", params[0]/2/accu);
for (int i = 1; i < numParams; i += 2) {
printf("+%.20fcos(%d pi x)", params[i]/accu, (i+1)/2);
printf("+%.20fsin(%d pi x)", params[i+1]/accu, (i+1)/2);
}
printf("\n");
}
if (accu != 0) {
for (int i = 0; i < numParams; i++) {
params[i] /= accu;
}
}
const int zeroStarts = 4; // Normally 4
const int winStarts = 2; // Normally 1
int i = 0;
int j = 0;
freqData[j].r = params[i++];
freqData[j++].i = 0;
for (; i < numParams;) {
freqData[j].r = params[i++];
freqData[j++].i = params[i++];
}
for (; j <= smallSize/2;) {
freqData[j].r = 0;
freqData[j++].i = 0;
}
kiss_fftri(smallIFFTR, freqData, timeData);
double scale = 1.0/timeData[0];
double tilt = 0;
double tilt2 = 0;
for (int i = 2; i < numParams; i += 2) {
if ((i/2)%2) {
tilt2 += (i/2)*params[i]*scale;
} else {
tilt2 -= (i/2)*params[i]*scale;
}
tilt += (i/2)*params[i]*scale;
}
penalty += fabs(tilt);
penalty += fabs(tilt2);
double accu2 = 0;
for (int i = 0; i < smallSize; i++) {
timeData[i] *= scale;
}
penalty += fabs(timeData[zeroStarts*smallSize/8]);
penalty += fabs(timeData[winStarts*smallSize/16]*timeData[smallSize-winStarts*smallSize/16]-0.5);
for (int i = 1; i < winStarts*smallSize/16; i++) {
// Last 16th
timeData[bigSize-winStarts*smallSize/16+i] = timeData[smallSize-winStarts*smallSize/16+i];
accu2 += timeData[bigSize-winStarts*smallSize/16+i]*timeData[bigSize-winStarts*smallSize/16+i];
}
// f(-1/8+i)*f(1/8-i) + f(i)*f(-i) = 1
// => f(-1/8+i) = (1 - f(i)*f(-i))/f(1/8-i)
// => f(-1/16) = (1 - f(1/16)*f(-1/16))/f(1/16)
// = 1/(2 f(1/16))
for (int i = 1; i < winStarts*smallSize/16; i++) {
// 2nd last 16th
timeData[bigSize-winStarts*smallSize/8+i] = (1 - timeData[i]*timeData[bigSize-i])/timeData[winStarts*smallSize/8-i];
accu2 += timeData[bigSize-winStarts*smallSize/8+i]*timeData[bigSize-winStarts*smallSize/8+i];
}
// Between 2nd last and last 16th
timeData[bigSize-winStarts*smallSize/16] = 1/(2*timeData[winStarts*smallSize/16]);
accu2 += timeData[bigSize-winStarts*smallSize/16]*timeData[bigSize-winStarts*smallSize/16];
for (int i = zeroStarts*smallSize/8; i <= bigSize-winStarts*smallSize/8; i++) {
timeData[i] = 0;
}
for (int i = 0; i < zeroStarts*smallSize/8; i++) {
accu2 += timeData[i]*timeData[i];
}
if (print > 1) {
printf("\n");
for (int x = 0; x < bigSize; x++) {
printf("%d,%f\n", x, timeData[x]);
}
}
scale = 1/sqrt(accu2);
if (print) {
printf("sqrt(accu2) = %f\n", sqrt(accu2));
}
double tSpread = 0;
timeData[0] *= scale;
double tMean = 0;
for (int i = 1; i <= zeroStarts*smallSize/8; i++) {
timeData[i] *= scale;
// tSpread += ((double)i)*((double)i)*(timeData[i]*timeData[i]);
double x_0 = timeData[i-1]*timeData[i-1];
double x_1 = timeData[i]*timeData[i];
tSpread += ((double)i)*((double)i)*(x_0 + x_1)*0.5 - ((double)i)*(2.0/3*x_0 + 1.0/3*x_1) + 0.25*x_0 + 1.0/12*x_1;
double slope = timeData[i]-timeData[i-1];
if (slope > 0) {
penalty += slope+1;
}
tMean += x_1*i;
if (timeData[i] < 0) {
penalty -= timeData[i];
}
}
double x_0 = timeData[0]*timeData[0];
for (int i = 1; i <= winStarts*smallSize/8; i++) {
timeData[bigSize-i] *= scale;
double x_1 = timeData[bigSize-i]*timeData[bigSize-i];
tSpread += ((double)i)*((double)i)*(x_0 + x_1)*0.5 - ((double)i)*(2.0/3*x_0 + 1.0/3*x_1) + 0.25*x_0 + 1.0/12*x_1;
x_0 = x_1;
tMean += x_1*(-i);
}
tMean /= smallSize;
penalty += fabs(tMean);
if (tMean > 0) {
penalty += 1;
}
tSpread /= ((double)smallSize)*((double)smallSize);
if (print) {
printf("tSpread = %f\n", tSpread);
}
kiss_fftr(bigFFTR, timeData, freqData);
double fSpread = 0;
x_0 = freqData[0].r*freqData[0].r;
for (int i = 1; i <= bigSize/2; i++) {
double x_1 = freqData[i].r*freqData[i].r+freqData[i].i*freqData[i].i;
fSpread += ((double)i)*((double)i)*(x_0 + x_1)*0.5 - ((double)i)*(2.0/3*x_0 + 1.0/3*x_1) + 0.25*x_0 + 1.0/12*x_1;
x_0 = x_1;
}
if (print > 1) {
for (int i = 0; i <= bigSize/2; i++) {
printf("%d,%f,%f\n", i, freqData[i].r, freqData[i].i);
}
}
fSpread /= bigSize; // Includes kiss_fft scaling
if (print) {
printf("fSpread = %f\n", fSpread);
printf("%f,%f,%f\n", tSpread, fSpread, tSpread*fSpread);
}
return tSpread*fSpread + penalty;
}
double costFunction(double *params, double compare) {
return costFunction(params, compare, false);
}
int getNumDimensions() {
return numParams;
}
~WinProblem() {
delete[] min;
delete[] max;
delete[] timeData;
delete[] freqData;
KISS_FFT_FREE(smallFFTR);
KISS_FFT_FREE(smallIFFTR);
KISS_FFT_FREE(bigFFTR);
KISS_FFT_FREE(bigIFFTR);
}
};