🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1951閲覧

FFTで周波数がうまく取り出せません

Anfaenger

総合スコア14

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/02/25 01:36

下記のプログラムはsinwave.wav(2000Hz×1秒間のファイル)から音声データを配列に格納して
その配列をFFTにかけるというプログラムです。
2000Hzの場所でパワースペクトルが上がることを期待していたのですが
なぜか900Hzあたりでパワースペクトルが上がってしまいます。
サンプル数のあたりが間違っているんでしょうか?
お力添えお願いします。

C++

1#include <stdio.h> 2#include <math.h> 3#include <stdlib.h> 4#pragma warning(disable:4996) 5 6typedef struct 7 8{ 9 10 int fs; //サンプリング周波数 11 12 int bits; //量子化bit数 13 14 int L; //データ長 15 16} WAV_PRM; 17 18FILE* fp; // ファイル入出力 19 20#define PI 4.0*atan(1.0) // 円周率 21 22void S_fft(double* x, double* y, int, int); 23#define N 4096 // N=データ総数(2,4,8,16,32,64,128,256,512,1024 のどれか) 24 25double* audio_read(WAV_PRM* prm, char* filename); 26 27double* audiodatasize; 28 29int main(void) { 30 31 WAV_PRM prm_in; 32 double* data; 33 FILE* audio = fopen("sinwave.wav", "rb"); 34 FILE* txt = fopen("data.txt", "w"); 35 char fn[] = "sinwave.wav"; 36 37 int i, Fr = 4096; 38 double dt = 0.00005; 39 double sc; 40 double* x, * y; 41 x = (double*)malloc(sizeof(double) * N); 42 y = (double*)malloc(sizeof(double) * N); 43 44 45 double fq; 46 int pw = 0; 47 printf("STG 01\n"); 48 sc = 2.0 * PI * dt; 49 for (i = 0; i < N; i++) { 50 if (x != NULL && y != NULL) { 51 y[i] = 0.0; 52 } 53 } 54 x = audio_read(&prm_in, fn); //配列xにsinwave.wavの波形データ(2000Hz)を代入 55 printf("STG 02\n"); 56 // Fourier変換 57 S_fft(x, y, N, -1); 58 59 //for (i = 0; i < Fr; i++) printf(" i=%d %f %f \n", i, x[i], y[i]); 60 61 // 計算結果をファイルに格納 62 fp = fopen("fft.txt", "w"); // ファイル名は fft.dat 63 for (i = 0; i < N; i++) { 64 if (x != NULL && y != NULL) { 65 pw = sqrt(x[i] * x[i] + y[i] * y[i]) * 10; // パワースペクトル 66 } 67 fq = i / (dt * Fr); // 周波数 68 //printf("%f = %d / (%f * %d)\n", fq, i, dt, N); 69 fprintf(fp, "%fHz %d\n", fq, pw); 70 } 71 printf("STG 03\n"); 72 fclose(fp); 73 fclose(audio); 74 return 0; 75} 76 77/********* Fourier変換および逆Fourier変換を行う副関数 ***************/ 78/* 入力: x[n]: 被解析波形(振幅) n; 離散データの数 */ 79/* ff: Fourier変換の場合は -1, 逆Fourier変換の場合は 1 */ 80/* 出力: ak[n]:cos関数の係数、 bk[n]:sin関数の係数 */ 81/**********************************************************************/ 82void S_fft(double ak[], double bk[], int n, int ff) { 83 int i, j, k, k1, num, nhalf, phi, phi0; 84 static int rot[N]; 85 double s, sc, c, a0, b0, tmp; 86 for (i = 0; i < n; i++) rot[i] = 0; 87 88 nhalf = n / 2; num = n / 2; sc = 2.0 * PI / n; 89 while (num >= 1) { 90 for (j = 0; j < n; j += 2 * num) { 91 phi = rot[j] / 2; phi0 = phi + nhalf; 92 c = cos(sc * phi); s = sin(sc * phi * ff); 93 for (k = j; k < j + num; k++) { 94 k1 = k + num; 95 a0 = ak[k1] * c - bk[k1] * s; b0 = ak[k1] * s + bk[k1] * c; 96 ak[k1] = ak[k] - a0; bk[k1] = bk[k] - b0; 97 ak[k] = ak[k] + a0; bk[k] = bk[k] + b0; 98 rot[k] = phi; rot[k1] = phi0; 99 } 100 } 101 num = num / 2; 102 } 103 if (ff < 0) { 104 for (i = 0; i < n; i++) { 105 ak[i] /= n; bk[i] /= n; 106 } 107 } 108 109 for (i = 0; i < n - 1; i++) { 110 if ((j = rot[i]) > i) { 111 tmp = ak[i]; ak[i] = ak[j]; ak[j] = tmp; 112 tmp = bk[i]; bk[i] = bk[j]; bk[j] = tmp; 113 } 114 } 115} 116 117 118 119double* audio_read(WAV_PRM* prm, char* filename) 120 121{ 122 123 //変数宣言 124 125 FILE* fp; 126 127 int n; 128 129 double* data; 130 131 char header_ID[4]; 132 133 long header_size; 134 135 char header_type[4]; 136 137 char fmt_ID[4]; 138 139 long fmt_size; 140 141 short fmt_format; 142 143 short fmt_channel; 144 145 long fmt_samples_per_sec; 146 147 long fmt_bytes_per_sec; 148 149 short fmt_block_size; 150 151 short fmt_bits_per_sample; 152 153 char data_ID[4]; 154 155 long data_size; 156 157 short data_data; 158 159 160 161 //wavファイルオープン 162 163 fp = fopen(filename, "rb"); 164 165 166 167 //wavデータ読み込み 168 169 fread(header_ID, 1, 4, fp); 170 171 fread(&header_size, 4, 1, fp); 172 173 fread(header_type, 1, 4, fp); 174 175 fread(fmt_ID, 1, 4, fp); 176 177 fread(&fmt_size, 4, 1, fp); 178 179 fread(&fmt_format, 2, 1, fp); 180 181 fread(&fmt_channel, 2, 1, fp); 182 183 fread(&fmt_samples_per_sec, 4, 1, fp); 184 185 fread(&fmt_bytes_per_sec, 4, 1, fp); 186 187 fread(&fmt_block_size, 2, 1, fp); 188 189 fread(&fmt_bits_per_sample, 2, 1, fp); 190 191 fread(data_ID, 1, 4, fp); 192 193 fread(&data_size, 4, 1, fp); 194 195 196 197 //パラメータ代入 198 199 prm->fs = fmt_samples_per_sec; 200 201 prm->bits = fmt_bits_per_sample; 202 203 prm->L = data_size / 2; 204 205 206 207 //音声データ代入 208 209 data = (double*)calloc(prm->L, sizeof(double)); 210 audiodatasize = (double*)malloc(sizeof(double) * prm->L); 211 212 for (n = 0; n < prm->L; n++) { 213 214 fread(&data_data, 2, 1, fp); 215 216 if (data != NULL) { 217 data[n] = (double)data_data / 32768.0; 218 } 219 220 } 221 222 223 224 fclose(fp); 225 226 return data; 227 228}

出力されたデータがこちらです。

~~~~~~ . . . 888.671875Hz 0 893.554688Hz 0 898.437500Hz 0 903.320313Hz 1 908.203125Hz 4 913.085938Hz 0 917.968750Hz 0 922.851563Hz 0 . . . ~~~~~~

##開発環境
Visual Studio 2019 C++

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jbpb0

2021/02/25 03:47

> 2000Hz×1秒間のファイル > 2000Hzの場所でパワースペクトルが上がることを期待 2000Hzでサンプリングしたデータからは、1000Hz未満のスペクトルしか分かりません 参考 http://kinokorori.hatenablog.com/entry/20161207/1481117395 だからと言って、それは900Hzが上がる理由にはならないので、他にも何か間違いがあるのだとは思いますけど
guest

回答1

0

自己解決

fqを2.2倍することで解決しました。

投稿2021/02/25 08:00

Anfaenger

総合スコア14

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2021/02/25 13:41

どういう信号を入力したのか、「事実」についての情報が全くないのでなんとも言えませんが、多分その対応は間違っているのではないかと思います。 なぜWAVファイルから取得したサンプリング周波数が計算に反映されていないのですか? 「周波数」の解釈も、どうでしょう...FFTの出力は、0~fs/2が0~N/2にマッピングされ、N/2~N-1まではその折返しになる、とかわかっているのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問