#define _USE_MATH_DEFINES #include #include #include #include #define LENGTH 512 /* 信号長 ただし,2の整数乗 */ typedef struct { double r; /* 実部 */ double i; /* 虚部 */ } Complex; /* 複素数 */ /* ---------------------------------------------------- * 複素数演算関数群 * ---------------------------------------------------- */ Complex getComplex(double r, double i) { return (Complex){r, i}; } Complex addComplex(Complex a, Complex b) { return getComplex(a.r + b.r, a.i + b.i); } Complex subComplex(Complex a, Complex b) { return getComplex(a.r - b.r, a.i - b.i); } Complex timeComplex(Complex a, Complex b) { return getComplex(a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r); } Complex divComplexByReal(Complex z, double div) { return getComplex(z.r / div, z.i / div); } Complex cexptheta(double theta) { return getComplex(cos(theta), sin(theta)); } /* ---------------------------------------------------- * 信号処理関数群 * ---------------------------------------------------- */ /* 窓関数(Complex型配列専用に統合) */ void applyWindow(Complex *x, int N) { for (int i = 0; i < N; i++) { double w = 0.5 - 0.5 * cos(2.0 * M_PI * i / (N - 1)); // ハニング窓 x[i].r *= w; x[i].i *= w; } } /* 平均パワー計算(Complex型配列専用に統合) */ double calcAmpPower(Complex *x, int N) { double power = 0.0; for (int i = 0; i < N; i++) { power += (x[i].r * x[i].r + x[i].i * x[i].i); } return power / N; } /* ビット逆順並び替え */ void bit_reversal(Complex *x, int N) { int i, j, k; Complex temp; j = 0; for (i = 0; i < N; i++) { if (i < j) { temp = x[i]; x[i] = x[j]; x[j] = temp; } k = N >> 1; while (k <= j && k > 0) { j -= k; k >>= 1; } j += k; } } /* 高速フーリエ変換 */ void fft(Complex *x, int N, int inverse) { bit_reversal(x, N); for (int stage = 1; (1 << stage) <= N; stage++) { int block = 1 << stage; int block2 = block >> 1; double theta = (inverse ? 2.0 : -2.0) * M_PI / block; Complex wm = cexptheta(theta); for (int k = 0; k < N; k += block) { Complex w = getComplex(1.0, 0); for (int j = 0; j < block2; j++) { Complex u = x[k + j]; Complex v = timeComplex(w, x[k + j + block2]); x[k + j] = addComplex(u, v); x[k + j + block2] = subComplex(u, v); w = timeComplex(w, wm); } } } if (inverse) { for (int i = 0; i < N; i++) { x[i] = divComplexByReal(x[i], N); } } } /* 離散フーリエ変換 * 冗長な回転子テーブル生成・計算関数を省き、 * 定義通りに計算するようリファクタリング済 */ void dft(Complex *x, Complex *c, int N) { for (int k = 0; k < N; k++) { c[k] = getComplex(0.0, 0.0); for (int n = 0; n < N; n++) { double theta = -2.0 * M_PI * k * n / N; Complex w = cexptheta(theta); c[k] = addComplex(c[k], timeComplex(x[n], w)); } } } /* 結果出力用ユーティリティ関数 */ void saveAmpSpectrum(const char *filename, Complex *x, int N) { FILE *fp = fopen(filename, "w"); if (fp == NULL) { fprintf(stderr, "Failed to open output file: %s\n", filename); return; } for (int i = 0; i < N; i++) { double amp = sqrt(x[i].r * x[i].r + x[i].i * x[i].i); fprintf(fp, "%f\n", amp); } fclose(fp); printf(" -> Saved amplitude spectrum to %s\n", filename); } /* ---------------------------------------------------- * メイン関数 * ---------------------------------------------------- */ int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } int N = LENGTH; char *file1 = argv[1]; char *file2 = argv[2]; short input[LENGTH]; Complex x[LENGTH]; Complex c[LENGTH]; printf("========== FFT UNIFIED PROGRAM ==========\n"); printf("File 1: %s\n", file1); printf("File 2: %s\n", file2); printf("=========================================\n\n"); /* ---------------------------------------------------- * モード 1 & 2 & 3: 実行時間・パワー比較・FFT結果 (file1を使用) * ---------------------------------------------------- */ printf("[Mode: File1 Analysis (%s)]\n", file1); FILE *fp1 = fopen(file1, "rb"); if (fp1 == NULL) { fprintf(stderr, "File open error (%s)\n", file1); exit(1); } if (fread(input, sizeof(short), N, fp1) != (size_t)N) { fprintf(stderr, "File read error (%s)\n", file1); fclose(fp1); exit(1); } fclose(fp1); // --- 実行時間の比較 (Time Mode) --- LARGE_INTEGER start, end, freq; double elapsedTime; QueryPerformanceFrequency(&freq); for (int i = 0; i < N; i++) x[i] = getComplex(input[i], 0); QueryPerformanceCounter(&start); dft(x, c, N); QueryPerformanceCounter(&end); elapsedTime = (double)(end.QuadPart - start.QuadPart) / freq.QuadPart; printf("\n--- Execution Time Comparison ---\n"); printf(" DFT Elapsed time: %f seconds\n", elapsedTime); QueryPerformanceCounter(&start); fft(x, N, 0); QueryPerformanceCounter(&end); elapsedTime = (double)(end.QuadPart - start.QuadPart) / freq.QuadPart; printf(" FFT Elapsed time: %f seconds\n", elapsedTime); // --- 窓関数適用とパワー比較 (Power Mode) --- for (int i = 0; i < N; i++) x[i] = getComplex(input[i], 0); double beforePower = calcAmpPower(x, N); applyWindow(x, N); double afterPower = calcAmpPower(x, N); printf("\n--- Power Analysis (Window Application) ---\n"); printf(" BEFORE : %16f\n", beforePower); printf(" AFTER : %16f\n", afterPower); printf(" DIFF : %16f\n", beforePower - afterPower); printf(" RATIO : %16f\n", afterPower / beforePower); // --- FFT振幅スペクトル出力 (Amp Mode) --- printf("\n--- Amplitude Spectrum Output ---\n"); fft(x, N, 0); // すでに窓関数適用済みの配列に対してFFTを実行 saveAmpSpectrum("result_amp_file1.txt", x, N); /* ---------------------------------------------------- * モード 4: 指定時刻シーク分析 (file2を使用) * ---------------------------------------------------- */ printf("\n[Mode: Seek Analysis (%s)]\n", file2); FILE *fp2 = fopen(file2, "rb"); if (fp2 == NULL) { fprintf(stderr, "File open error (%s)\n", file2); exit(1); } typedef struct { double time_sec; const char *vowel; } SeekTarget; // 指定された5つの時刻を定義 SeekTarget targets[] = { {0.361, "a"}, // あ {0.969, "i"}, // い {1.415, "u"}, // う {1.936, "e"}, // え {2.431, "o"} // お }; long fs = 16000; long bytes_per_sample = 2; for (int t = 0; t < 5; t++) { long start_byte = (long)(targets[t].time_sec * fs * bytes_per_sample); fseek(fp2, start_byte, SEEK_SET); if (fread(input, sizeof(short), N, fp2) != (size_t)N) { fprintf(stderr, "File read error (%s) at %f s\n", file2, targets[t].time_sec); continue; } // Complex型への変換、窓関数の適用、FFTの実行 for (int i = 0; i < N; i++) x[i] = getComplex(input[i], 0); applyWindow(x, N); fft(x, N, 0); char out_filename[256]; sprintf(out_filename, "result_seek_%s.txt", targets[t].vowel); saveAmpSpectrum(out_filename, x, N); } fclose(fp2); printf("\nAll analyses finished successfully.\n"); return 0; }