質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.35%
C++

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

Q&A

解決済

1回答

1814閲覧

FFTで20000Hzまで計算できるようにしたい

Anfaenger

総合スコア14

C++

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

0グッド

0クリップ

投稿2021/02/21 13:23

編集2021/02/22 09:55

FFTで20000Hzまで計算できるようにしたい

C++でFFTのプログラムを下記のサイトを参考にして作っています。
http://www-in.aut.ac.jp/~minemura/pub/Csimu/C/FFT.html
周波数は25000Hzくらいまで表示できるのですが
パワースペクトルが周波数と対応しません。
どなたかご教示お願い致します。

該当のソースコード

C++

1#include <stdio.h> 2#include <math.h> 3#include <stdlib.h> 4#pragma warning(disable:4996) 5 6FILE* fp; // ファイル入出力 7 8#define PI 4.0*atan(1.0) // 円周率 9 10void S_fft(double* x, double* y, int, int); 11#define N 32768 // N=データ総数(2,4,8,16,32,64,128,256,512,1024 のどれか) 12 13int main(void) { 14 int i, count, Fr = 128; 15 double dt = 0.01; 16 double sc; 17 double* x, * y; 18 x = (double*)malloc(sizeof(double) * N); 19 y = (double*)malloc(sizeof(double) * N); 20 21 22 double fq, pw; 23 24 sc = 2.0 * PI * dt; 25 for (i = 0; i < N; i++) { // 1Hzに60Hzのノイズが重なった波形の例 26 x[i] = sin(sc * i); 27 y[i] = 0.0; 28 } 29 // Fourier変換 30 S_fft(x, y, N, -1); 31 32 //for (i = 0; i < Fr; i++) printf(" i=%d %f %f \n", i, x[i], y[i]); 33 34 // 計算結果をファイルに格納 35 fp = fopen("fft.txt", "w"); // ファイル名は fft.dat 36 for (i = 0; i < N; i++) { 37 if (i % 256 == 0) { 38 pw = sqrt(x[i] * x[i] + y[i] * y[i]) * 100; // パワースペクトル 39 } 40 fq = i / (dt * Fr); // 周波数 41 //printf("%f = %d / (%f * %d)\n", fq, i, dt, N); 42 fprintf(fp, "%fHz %f \n", fq, pw); 43 } 44 fclose(fp); 45 return 0; 46} 47 48/********* Fourier変換および逆Fourier変換を行う副関数 ***************/ 49/* 入力: x[n]: 被解析波形(振幅) n; 離散データの数 */ 50/* ff: Fourier変換の場合は -1, 逆Fourier変換の場合は 1 */ 51/* 出力: ak[n]:cos関数の係数、 bk[n]:sin関数の係数 */ 52/**********************************************************************/ 53void S_fft(double ak[], double bk[], int n, int ff) { 54 int i, j, k, k1, num, nhalf, phi, phi0; 55 static int rot[N]; 56 double s, sc, c, a0, b0, tmp; 57 for (i = 0; i < n; i++) rot[i] = 0; 58 59 nhalf = n / 2; num = n / 2; sc = 2.0 * PI / n; 60 while (num >= 1) { 61 for (j = 0; j < n; j += 2 * num) { 62 phi = rot[j] / 2; phi0 = phi + nhalf; 63 c = cos(sc * phi); s = sin(sc * phi * ff); 64 for (k = j; k < j + num; k++) { 65 k1 = k + num; 66 a0 = ak[k1] * c - bk[k1] * s; b0 = ak[k1] * s + bk[k1] * c; 67 ak[k1] = ak[k] - a0; bk[k1] = bk[k] - b0; 68 ak[k] = ak[k] + a0; bk[k] = bk[k] + b0; 69 rot[k] = phi; rot[k1] = phi0; 70 } 71 } 72 num = num / 2; 73 } 74 if (ff < 0) { 75 for (i = 0; i < n; i++) { 76 ak[i] /= n; bk[i] /= n; 77 } 78 } 79 80 for (i = 0; i < n - 1; i++) { 81 if ((j = rot[i]) > i) { 82 tmp = ak[i]; ak[i] = ak[j]; ak[j] = tmp; 83 tmp = bk[i]; bk[i] = bk[j]; bk[j] = tmp; 84 } 85 } 86}

試したこと

mallocを使ってみましたが、下記の警告が出て異常終了してしまいます。

警告

NULLポインター'x'を逆参照しています。
NULLポインター'y'を逆参照しています。

補足情報(FW/ツールのバージョンなど)

Visual Studio 2019

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

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

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

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

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

1T2R3M4

2021/02/21 13:31

x[1024], y[1024] rot[1024] これらも変更してますか。
Anfaenger

2021/02/21 15:49

変更してみました!
thkana

2021/02/21 22:40 編集

(質問が編集されましたが、以前のエラーは出なくなったのですか? ソースコードはなにも変更していないようですが、なにが変わったのですか?-最新の更新しか見ていなかった勘違いなのでここまで削除) 一致っていうのは、二つ以上のなにかとなにかが同じであることをいいます。 一つはこのプログラムの結果として、それとなにが一致しないと言っているのですか? 直流、正弦波、矩形波、鋸歯状波など、既知の波形を入力したらその結果は妥当なのですか?
cateye

2021/02/21 22:20

>#define N 32768 ・・・・ > double sc, x[N], y[N]; ←これ、スタック壊してませんか?
Anfaenger

2021/02/22 00:03

>>thkanaさん 言葉足らずですみません。 周波数とそれに対応するパワースペクトルが一致しないという意味です。 Nをいじってサンプリング周波数?は変えられたと思うのですが、パワースペクトルの範囲が0〜99.9Hzになっているようで……
Anfaenger

2021/02/22 00:04

>>cateyeさん 壊れてはいないと思いますが…… なぜですか?
thkana

2021/02/22 00:44 編集

私が、あなたがやったのと同じ比較をして「一致していない」ことを確認しようとするなら、 どうすれば比較する二つのデータを入手できますか?
thkana

2021/02/22 00:45

もう一つ、比較対照しているデータが間違っていない、ということは確かなのですか?
Anfaenger

2021/02/22 09:15 編集

>>thkanaさん データは以下のようになります。 0.000000Hz 0.001109 0.781250Hz 0.001109 1.562500Hz 0.001109 2.343750Hz 0.001109 3.125000Hz 0.001109 . . . 0.781250Hzのところで高いパワースペクトルが取り出せることを期待していたのですが 0になってしまいます。多分データがずれてるんだと思います。 追記:もしかするとcateyeさんの仰るようにスタックオーバーフロー?を起こしてるのかもしれません
Anfaenger

2021/02/22 09:06

>>cateyeさん mallocについても調べてみましたが初心者でよく分かりません…… お力添えをお願いします
guest

回答1

0

ベストアンサー

FFTの周波数ってサンプリング周波数で正規化されてますから、単純にHzで表される話じゃないです。Nを増やしても「周波数」は変わりません。分解能が変わるだけです。

で、ソース中のコメントにN=データ総数(2,4,8,16,32,64,128,256,512,1024 のどれか)と書いてあります。何も考えずにNを1025以上にするなら異常動作が起こっても当然、でしょう。

内容は検討していませんが、1024で取っている配列の要素数をN以上に増やせばなんとかなりそうな気はします。


うわぁ、編集していっぱい書いたのが消えた...

書き直す気力もないので、簡略版。

double dt = 0.01; //<略> sc = 2.0 * PI * dt; for (i = 0; i < N; i++) { // 1Hzに60Hzのノイズが重なった波形の例 <- ウソのコメント x[i] = sin(sc * i); y[i] = 0.0; //本題に関係ない }

つまり、sin(2pi0.01*i)だから100サンプル周期の正弦波です。32768/100=327.68ですから、327とか328番目(最初はDC成分なのでさらに+1する)を見てみると、

328番目 19.771515
329番目 41.983550
330番目 10.170375

ちゃんと出ているようにおもいます。

なにか問題がありますか? ナントカHzってのは全く意味不明なので無視していますが。

投稿2021/02/21 14:24

編集2021/02/22 11:24
thkana

総合スコア7703

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問