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

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

新規登録して質問してみよう
ただいま回答率
85.48%
MATLAB

MATLABはMathWorksで開発された数値計算や数値の視覚化のための高水準の対話型プログラミング環境です。

Q&A

解決済

2回答

3507閲覧

音をフーリエ変換した各音階の差

退会済みユーザー

退会済みユーザー

総合スコア0

MATLAB

MATLABはMathWorksで開発された数値計算や数値の視覚化のための高水準の対話型プログラミング環境です。

0グッド

0クリップ

投稿2017/10/18 05:58

編集2018/10/14 08:36

###前提・実現したいこと
MATLABで3つの音の和音を鳴らした後、フーリエ変換してグラフにプロットしています。

###発生している問題・エラーメッセージ
各音階のy軸の値に差が出ています。

###該当のソースコード

MATLAB

1 2 3plot(f, abs(fy)/length(t)); 4xlabel('frequency (Hz)') 5ylabel('gain')

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

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

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

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

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

guest

回答2

0

信号の時間範囲 t を増やせばよい。

%%
Fs = 8000; %サンプリングレート
A = 440; %Aの周波数
period = 1; %<----------------------------- period = 0.02を変更
t = (0:1/Fs:period-1/Fs);
%f = (1/period:1/period:Fs);
f = (0:Fs-1); %<---------------------------- 周波数領域を修正
sep = power(2, 1/12);
Cs = Apower(sep, 4);
E = Cs
power(sep, 3);

% 〔信号の〕ひずみをなくすために0.2を各音に掛ける
y = 0.2sin(2pi*(A)t) + 0.2sin(2piCst) + 0.2sin(2piE*t);
%sound(y, Fs);
fy = fft(y);

plot(f, abs(fy)/length(t));
xlabel('frequency (Hz)')
ylabel('gain')

投稿2017/10/19 00:56

WathMorks

総合スコア1582

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

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

退会済みユーザー

退会済みユーザー

2017/10/19 12:32

ご回答いただきましてありがとうございました。
guest

0

ベストアンサー

とりあえず期待通りにならない点についてのみのコメントです。解決策でなくてスミマセン

FFTは区間とサンプリング周波数で決まる最低周波数をF0とすると、サンプルの波形データから、F0の整数倍のスペクトルへ変換するものということなのですが・・・

通常、計算結果として出てくるスペクトルの各周波数は自然音階に対応する周波数とバッチリ一致してくれません。F0=30 Hzだとすると出てくるスペクトルの周波数は30, 60, ..., 420, 450, ...となるわけで、440 Hzちょうどのスペクトルは出てきません。本来の周波数と完全に一致した周波数のスペクトルは計算上正確に出てきますが、そこからずれるほど本来の周波数に対するスペクトル値よりも小さな値になると思います。

試しに自然音階ではなく、F0の正確な倍数の周波数の混合波形を作ってFFTをやってみてください。元の成分の大きさとばっちり一致した結果が得られると思います。


もしFFTの目的が「あらかじめ波形に含まれ得る周波数がわかっていて、その周波数の音の大きさを解析する」なら、より厳密な周波数分析の手法を用いるのだろうと想像します。一方、単に音声のスペクトルの雰囲気を「低音成分が大きい」「高音成分が大きい」という程度にわかればいいのなら、本件はあまり気にしなくていいと思います。


追記:

本来の周波数に対するスペクトル値よりも小さな値になる

以下は最低周波数F0とF0の8倍近くの波Fの2つの波を合成したFFT結果ですが、
左からF=F08, F=F08.1, F=F0*8.5にした時のものです。

イメージ説明

感覚的な説明になりますが、これを見るとF=F08ちょうどの波(一番左)はスパイクがF08のスペクトルにのみ出ており、そこからF08.1, F08.5とずれるに従い周辺の周波数のスペクトルにスパイク成分が分散してしまっており、本来の周波数に一番近いスペクトルの値(スペクトルのピークの値)は小さくなっていることが見て取れると思います。これは離散フーリエ変換の一般的な特性です。

投稿2017/10/18 06:56

編集2017/10/19 02:12
KSwordOfHaste

総合スコア18394

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

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

退会済みユーザー

退会済みユーザー

2017/10/19 00:52

丁寧なご回答をいただきましてありがとうございます。 計算結果として出てくるスペクトルの各周波数は自然音階に対応する周波数とバッチリ一致しないという点は理解できましたが、 本来の周波数と完全に一致しなかった周波数は、本来の周波数からそずれるほど本来の周波数に対するスペクトル値よりも小さな値になる という点の理解が難しいです。 これは、MATLABで動かして見て目で見て納得するしかないんでしょうか。 お手数おかけしますが、よろしくお願い致します。
退会済みユーザー

退会済みユーザー

2017/10/19 01:26

加えて、F0=30Hzというのは例だと思いますが、上記のコードではF0はどのように導き出すことができるのかも教えていただけますと大変助かります。
KSwordOfHaste

2017/10/19 02:39 編集

一般にF0=サンプリング周波数/FFT区間のサンプル数ですが、このあたりはDFT(離散フーリエ変換)の基礎的な事項なので「離散フーリエ変換」などで検索してみてください。 仮にサンプリング周波数を44.1KHzとし1024サンプルをFFT区間にすると44.1HzあたりがF0になります。440Hzの音はF0*10近くですがその半音上の音466.163...HzはF0*10.5...となり、解答に書いた例の一番右の状態に近い感じになるわけです。一般的なサンプリング周波数で音楽の波形を単にDFTを使って解析しても自然音階のどの音がどのくらいの大きさかを解析するのはなかなかに難しいと思います。区間を長くすれば周波数の分解能は上がりますが、普通の音楽波形はずっと同じピッチの音が出続けているわけではなく常に変化していますので。
退会済みユーザー

退会済みユーザー

2017/10/19 05:15

大変助かりました。ご説明いただきましてありがとうございました。
KSwordOfHaste

2017/10/19 06:14

BAを付けていただいたのですが、自分の回答は「スペクトルが本来の大きさとずれる意味」のみで「本来の大きさに近づける具体的な方法」は回答できていません。 実験的に波形を生成して任意のサンプル区間を設定できるという前提では、rkhsさんの方法(FFT区間を長くして周波数分解能を高める)が試せますね?この方法をトライしてみると本来のスペクトル値に近い結果が得られるのがおわかりかと思います。
退会済みユーザー

退会済みユーザー

2017/10/19 12:34

なぜフーリエ変換をすると、音の大きさに差が出てしまうのかがわかっていなかったのと、KSwordOfHasteさんがとても丁寧に解説してくださったのでBAにさせていただきました。最後まで、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問