[기타] 일본의 저력.....
일본 책들이나 중국 책들이 설명이 아주 친절하다.
한국에서 대학나온 사람들에게 삼각함수에 대해서 물어보면 대체로 머리를 긁는다.
난 문과라서 몰라....
내 전공이 아니라서 몰라...
wave 데이터를 1722Hz와 861Hz를 가산 한 정현파를 발생해 보아라...물어보면...
통신 공학을 전공한 사람이라면 시간은 걸리겠지만 대답 할 수 있다고 치더라고
거의 대부분의 사람들은 대답을 못할 것이다.
암기 위주의 교육으로는 응용이 되지 못하기 때문이다.
맨땅에 해딩하는 시대는 끝났다.
중복 투자를 하지 않는 것이 생산성 향상에 가장 필수다.
https://tomosoft.jp/design/?p=9127
C#によるWaveデータのFFT処理
Visual Studio Express 2013を使用し、C#言語によりWaveファイル形式でWaveデータに対して、FFT処理を行います。「C#によるWaveデータの作成」によりFFT処理を行うWaveファイルを作成し、FFT処理を行いその処理結果を表示します。次の表示は、1722Hzと861Hzを加算したデータ長100msの正弦波に対して、FFT処理を行った結果を示します。 FFT処理ライブラリの追加 FFTの計算には、Math.NET Numericsを使用します。Math.NET Numeric
tomosoft.jp
wave 데이터는 1722Hz와 861Hz를 가산 한 정현파를 발생하기 위해 28 번째 줄에서 31 번째 줄을 다음과 같이 변경합니다. 또한 발생한 1722Hz와 861Hz를 가산 한 정현파는 FFT 처리를하면 1722Hz 샘플 포인트의 80 번째 861Hz는 샘플 포인트의 40 번째 피크입니다.
1 2 3 4 5 6 7 8 |
// 1722Hzと861Hzを加算した正弦波を作る。 double Wave = 0;
Wave += Math.Sin(Radian * 1722); Wave += Math.Sin(Radian * 861); Wave /= 2;
short Data = (short)(Wave * 30000); |
샘플링주기가 22.675736961451μsec (= 1 / 44,100)에 2048 포인트 FFT하면 주파수 분해능은 1 / (2048 * 22.67573696145μ) = 21.533203125Hz입니다.
샘플 포인트의 40 번째 : 21.533203125Hz * 40 = 861Hz샘플 포인트의 80 번째 : 21.533203125Hz * 80 = 1722Hz
C #에 따르면 Wave 데이터 FFT 처리 프로그램의 작성
설치 한 Math.NET Numerics를 사용하여 FFT 계산합니다. FFT 샘플 수는 2048 포인트로했습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System.Numerics; using MathNet.Numerics; using MathNet.Numerics.IntegralTransforms;
public void computeFFT(int[] soundvalues) { //convert int to complex for (int i = 0; i < windowSize; i++) { complexData[i] = new Complex((double)soundvalues[i], 0); // }
//run FFT Fourier.Forward(complexData, FourierOptions.Matlab); // arbitrary length } |
- 변수 "windowSize"는 "2048"로합니다.
- 10 번째 줄에서 Complex 인스턴스는 입력 한 Wave 데이터를 복소수 데이터로 변환합니다.
C #에 따르면 Wave 데이터 FFT 처리 결과 표시 프로그램 만들기
FFT 처리 결과를 막대 그램으로 표시합니다. 처리 방법에 대해서는 " C #을 사용하여 Wave 파일의 데이터를 이용한 파형 표시 "를 참조하십시오. 또한 다음 부분을 변경합니다.
- 제목 및 축 레이블 변경
- test.ChartType : SeriesChartType.Column
2048 포인트 샘플 값의 표시는 다음과 같이 복소수 "value"의 절대 값으로 표시합니다.
1 2 3 4 5 |
//グラフのデータを追加 for (int i = 0; i < value.Length; i++) { test.Points.AddXY(i, value[i].Magnitude); }
|
보너스
http://semitennis.blog100.fc2.com/blog-entry-82.html
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace SinWave
{
public partial class Form1 : Form
{
// 波形サイズ
int size = 1024;
// サンプリング周波数
int fs = 1800;
// DFT用データ
double[] re;
double[] im;
// FFT用データ
double[] reFFT;
double[] imFFT;
double[] reFFT_2;
double[] imFFT_2;
// 窓関数
public enum WindowFunc
{
Hamming,
Hanning,
Blackman,
Rectangular
}
// コンストラクタ
public Form1()
{
InitializeComponent();
plot();
}
// 正弦波生成
public double Sin(int freq, int i)
{
double sin = 0.2 * Math.Sin(2 * (freq*fs/180) * i * Math.PI / fs);
return sin;
}
// DFT
public void DFT(int n, double[] inputRe, out double[] real, out double[] imag)
{
real = new double[n];
imag = new double[n];
for (int i = 0; i < n; i++)
{
real[i] = 0.0;
imag[i] = 0.0;
for (int j = 0; j < n; j++)
{
real[i] += inputRe[j] * Math.Cos(2 * Math.PI * i * j / fs);
imag[i] += inputRe[j] * -(Math.Sin(2 * Math.PI * i * j / fs));
}
}
}
// FFT
public static void FFT(double[] inputRe, double[] inputIm, out double[] outputRe, out double[] outputIm, int bitSize)
{
int dataSize = 1 << bitSize;
int[] reverseBitArray = BitScrollArray(dataSize);
outputRe = new double[dataSize];
outputIm = new double[dataSize];
// バタフライ演算のための置き換え
for (int i = 0; i < dataSize; i++)
{
outputRe[i] = inputRe[reverseBitArray[i]];
outputIm[i] = inputIm[reverseBitArray[i]];
}
// バタフライ演算
for (int stage = 1; stage <= bitSize; stage++)
{
int butterflyDistance = 1 << stage;
int numType = butterflyDistance >> 1;
int butterflySize = butterflyDistance >> 1;
double wRe = 1.0;
double wIm = 0.0;
double uRe = System.Math.Cos(System.Math.PI / butterflySize);
double uIm = -System.Math.Sin(System.Math.PI / butterflySize);
for (int type = 0; type < numType; type++)
{
for (int j = type; j < dataSize; j += butterflyDistance)
{
int jp = j + butterflySize;
double tempRe = outputRe[jp] * wRe - outputIm[jp] * wIm;
double tempIm = outputRe[jp] * wIm + outputIm[jp] * wRe;
outputRe[jp] = outputRe[j] - tempRe;
outputIm[jp] = outputIm[j] - tempIm;
outputRe[j] += tempRe;
outputIm[j] += tempIm;
}
double tempWRe = wRe * uRe - wIm * uIm;
double tempWIm = wRe * uIm + wIm * uRe;
wRe = tempWRe;
wIm = tempWIm;
}
}
}
// ビットを左右反転した配列を返す
private static int[] BitScrollArray(int arraySize)
{
int[] reBitArray = new int[arraySize];
int arraySizeHarf = arraySize >> 1;
reBitArray[0] = 0;
for (int i = 1; i < arraySize; i <<= 1)
{
for (int j = 0; j < i; j++)
reBitArray[j + i] = reBitArray[j] + arraySizeHarf;
arraySizeHarf >>= 1;
}
return reBitArray;
}
// 窓関数
public static double[] Windowing(double[] data, WindowFunc windowFunc)
{
int size = data.Length;
double[] windata = new double[size];
for (int i = 0; i < size; i++)
{
double winValue = 0;
// 各々の窓関数
if (WindowFunc.Hamming == windowFunc)
{
winValue = 0.54 - 0.46 * Math.Cos(2 * Math.PI * i / (size - 1));
}
else if (WindowFunc.Hanning == windowFunc)
{
winValue = 0.5 - 0.5 * Math.Cos(2 * Math.PI * i / (size - 1));
}
else if (WindowFunc.Blackman == windowFunc)
{
winValue = 0.42 - 0.5 * Math.Cos(2 * Math.PI * i / (size - 1))
+ 0.08 * Math.Cos(4 * Math.PI * i / (size - 1));
}
else if (WindowFunc.Rectangular == windowFunc)
{
winValue = 1.0;
}
else
{
winValue = 1.0;
}
// 窓関数を掛け算
windata[i] = data[i] * winValue;
}
return windata;
}
//グラフ表示形式
private void plot()
{
// chart1
Series series1 = new Series("sinWave 1+5+10+50Hz");
Series series1_mado = new Series("mado");
// chart2
Series series2 = new Series("DFT");
Series series3 = new Series("FFT");
Series series4 = new Series("FFT_mado");
// DFT用データ
double[] dftIn = new double[size];
double[] dftInIm = new double[size];
// 窓関数後データ
double[] data = new double[size];
// 波形生成
for (int i = 0; i < size; i++)
{
dftIn[i] = Sin(1, i);
dftIn[i] += Sin(5, i);
dftIn[i] += Sin(10, i);
dftIn[i] += Sin(50, i);
series1.Points.AddXY(i, dftIn[i]);
dftInIm[i] = 0.0;
}
// 窓関数
data = Windowing(dftIn, WindowFunc.Hanning);
for (int i = 0; i < size; i++)
{
series1_mado.Points.AddXY(i, data[i]);
}
// DFT
DFT(size, dftIn, out re, out im);
// FFT
FFT(dftIn, dftInIm, out reFFT, out imFFT, 10);
FFT(data, dftInIm, out reFFT_2, out imFFT_2, 10);
// DFT波形表示
for (int i = 0; i < size; i++)
{
if (i > 0)
{
series2.Points.AddXY((double)i / (fs / 180), Math.Sqrt(re[i] * re[i] + im[i] * im[i]));
double x = (double)i * (180.0 / size);
double y = Math.Sqrt(reFFT[i] * reFFT[i] + imFFT[i] * imFFT[i]);
//series3.Points.AddXY((double)i * (180.0 / size), Math.Sqrt(reFFT[i] * reFFT[i] + imFFT[i] * imFFT[i]));
series3.Points.AddXY(x, y);
double y2 = Math.Sqrt(reFFT_2[i] * reFFT_2[i] + imFFT_2[i] * imFFT_2[i]);
series4.Points.AddXY(x, y2);
}
}
series1.ChartType = SeriesChartType.Line; // グラフ形状
series1_mado.ChartType = SeriesChartType.Line; // グラフ形状
series2.ChartType = SeriesChartType.Line; // グラフ形状
series3.ChartType = SeriesChartType.Line; // グラフ形状
series4.ChartType = SeriesChartType.Line; // グラフ形状
chart1.Series.Clear();
chart1.Series.Add(series1);
chart1.Series.Add(series1_mado);
chart2.Series.Clear();
chart2.Series.Add(series2);
chart2.Series.Add(series3);
chart2.Series.Add(series4);
Axis ax = chart1.ChartAreas[0].AxisX;
ax.MajorGrid.LineColor = Color.LightGray;
Axis ay = chart1.ChartAreas[0].AxisY;
ay.MajorGrid.LineColor = Color.LightGray;
Axis ax2 = chart2.ChartAreas[0].AxisX;
ax2.MajorGrid.LineColor = Color.LightGray;
ax2.IsLogarithmic = true;
Axis ay2 = chart2.ChartAreas[0].AxisY;
ay2.MajorGrid.LineColor = Color.LightGray;
ay2.IsLogarithmic = true;
}
// save file
private void button1_Click(object sender, EventArgs e)
{
//SaveFileDialogクラスのインスタンスを作成
SaveFileDialog sfd = new SaveFileDialog();
//ダイアログを表示する
if (sfd.ShowDialog() == DialogResult.OK)
{
System.IO.Stream stream;
stream = sfd.OpenFile();
if (stream != null)
{
//ファイルに書き込む
System.IO.StreamWriter sw = new System.IO.StreamWriter(stream);
for (int i = 0; i < size; i++)
{
sw.Write((double)i/(fs/180) + "," + Math.Sqrt(re[i] * re[i] + im[i] * im[i]) + ","
+ (double)i * (180.0 / size) + "," + Math.Sqrt(reFFT[i] * reFFT[i] + imFFT[i] * imFFT[i]) + "\n");
}
sw.Close();
stream.Close();
}
}
}
}
}