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

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

ただいまの
回答率

90.84%

  • MATLAB

    134questions

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

和音をフーリエ変換した時に、各音階のy軸の値の差を無くしたい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 344

ranranway

score 193

前提・実現したいこと

MATLABで3つの音の和音(AとCsとE)を鳴らした後、フーリエ変換してグラフにプロットしています。

発生している問題・エラーメッセージ

各音階のy軸の値に差が出ています。なぜフーリエ変換をすると、音の大きさに差が出てしまうのか原因がわからないため、各音階のy軸の値を同一にする方法がわかりません。

該当のソースコード

Fs = 8000; %サンプリングレート
A = 440; %Aの周波数
period = 0.02; %1秒間の信号の長さ
t = (0:1/Fs:period-1/Fs);
f = (1/period:1/period:Fs);
sep = power(2, 1/12);
Cs  = A*power(sep, 4) %C#の周波数
E = Cs*power(sep, 3) %Eの周波数

  % 〔信号の〕ひずみをなくすために0.2を各音に掛ける
y = 0.2*sin(2*pi*(A)*t) + 0.2*sin(2*pi*Cs*t) + 0.2*sin(2*pi*E*t);
sound(y, Fs);
fy = fft(y); %フーリエ変換

plot(f, abs(fy)/length(t));
xlabel('frequency (Hz)')
ylabel('gain')
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

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

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

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

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


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


追記:

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

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

イメージ説明

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/19 09:52

    丁寧なご回答をいただきましてありがとうございます。

    計算結果として出てくるスペクトルの各周波数は自然音階に対応する周波数とバッチリ一致しないという点は理解できましたが、
    本来の周波数と完全に一致しなかった周波数は、本来の周波数からそずれるほど本来の周波数に対するスペクトル値よりも小さな値になる
    という点の理解が難しいです。
    これは、MATLABで動かして見て目で見て納得するしかないんでしょうか。

    お手数おかけしますが、よろしくお願い致します。

    キャンセル

  • 2017/10/19 10:26

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

    キャンセル

  • 2017/10/19 11:29 編集

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

    キャンセル

  • 2017/10/19 14:15

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

    キャンセル

  • 2017/10/19 15:14

    BAを付けていただいたのですが、自分の回答は「スペクトルが本来の大きさとずれる意味」のみで「本来の大きさに近づける具体的な方法」は回答できていません。

    実験的に波形を生成して任意のサンプル区間を設定できるという前提では、rkhsさんの方法(FFT区間を長くして周波数分解能を高める)が試せますね?この方法をトライしてみると本来のスペクトル値に近い結果が得られるのがおわかりかと思います。

    キャンセル

  • 2017/10/19 21:34

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

    キャンセル

+1

信号の時間範囲 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  = A*power(sep, 4);
E = Cs*power(sep, 3);

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/19 21:32

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

    キャンセル

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

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    matlabでの計算について

    matlabで計算をしたいのですが、使い方がいまいちわかっておりません 計算というのは例えば 13 1 15 7 ≈ 58 576 のように1行614400列の行

  • 解決済

    matlabでの作業効率化2

    5つのデータがあるとして、それぞれ違う名前をつけたい(a b c d eのように)ときにどのような手順を踏めばいいのでしょうか。 for N=1:5%ファイルの数だけ繰り返す

  • 解決済

    matlabでのfor文を使った行列の結合

    題名にもある通りfor文を使って行列の結合をしたいと考えています。 k1=(1,2,3);k2=(4,5,6);k3=(7,8,9);k4=(10,11,12);このようにkが9

  • 解決済

    MATLABで読み込んだwavファイルの一部を切り取り、もう一度wavファイルで書き出す方法

    matlabに複数のwavファイルを読み込み 読み込んだwavファイルの初めの1秒間のみを切り出して 「長さが1秒間のwav」を作成、再度wavファイルの形で書き出すプログラム

  • 解決済

    MATLAB ファイル読み込み

    観測したzipファイルを手で解凍し、MATLABで読み込む方法についてです。 観測で得られたzipファイルを手動で解凍し、開くと ーーーーーーーーーー e16A0319.

  • 解決済

    Matlabでのtxtファイル出力について

    前提・実現したいこと iが1から21までループさせ、その結果を1つのテキストファイル(ファイル.txt)に縦に出力させたいです。 ↓fa↓ SizeX0 = 0; Si

  • 解決済

    Matlabで時間スケール変換を用いて音声の尺を長くするコード

    前提・実現したいこと Matlabで時間スケール変換を用いて、音質は損なわずに音声データの尺を2倍長くしようとしています。実現できているのは、尺はそのままで音の高さを変えることです

  • 解決済

    matlabでの連続処理

    前提・実現したいこと カレントディレクトリのcsvを読み込んで解析結果を同じディレクトリに吐き出すプログラムを使用しています。 恥ずかしながら手動でディレクトリを移動させて毎度毎度

同じタグがついた質問を見る

  • MATLAB

    134questions

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