1

学校で行っているプロジェクトに離散フーリエ変換アルゴリズムを実装しようとしています。しかし、クラスを作成するのは難しいようです(そうすべきではありません)。VisualStudio2012を使用しています。

基本的に、DFTから取得した2つの値を格納するためにComplexというクラスが必要です。実数部と虚数部。

これは私がこれまでに持っているものです:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SoundEditor_V3
{
    public class Complex
    {
        public double real;
        public double im;

        public Complex()
        {
            real = 0;
            im = 0;
        }
    }
}

問題は、コンストラクターがコンストラクターとして認識されないことです。私はC#を学習しているだけですが、オンラインで調べたところ、このようになっているはずです。しかし、それは私のコンストラクターをメソッドとして認識します。

何故ですか?クラスを間違って作成していますか?

私のフーリエクラスでも同じことをしています。ですから、フーリエオブジェクトを作成してそのメソッドを使用しようとするたびに...そのようなことはありません。

たとえば、私はこれを行います:

Fourier fou = new Fourier();
fou.DFT(s, N,  amp, 0);

そしてそれは、fouが「フィールド」であるが、「タイプ」のように使用されていることを教えてくれ ます。なぜそれがそれを言っているのですか?

これが私のフーリエクラスのコードでもあります:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SoundEditor_V3
{
   public class Fourier
   {

        //FOURIER
        //N = number of samples
        //s is the array of samples(data)
        //amp is the array where the complex result will be written to
        //start is the where in the array to start
        public void DFT(byte[] s, int N, ref Complex[] amp, int start)
        {
            Complex tem = new Complex();
            int f;
            int t;

            for (f = 0; f < N; f++)
            {

                tem.real = 0;
                tem.im = 0;

                for (t = 0; t < N; t++)
                {
                    tem.real += s[t + start] * Math.Cos(2 * Math.PI * t * f / N);
                    tem.im -= s[t + start] * Math.Sin(2 * Math.PI * t * f / N);

                }
                amp[f].real = tem.real;
                amp[f].im = tem.im;

            }
        }

        //INVERSE FOURIER
        public void IDFT(Complex[] A, ref int[] s)
        {
            int N = A.Length;
            int t, f;
            double result;
            for (t = 0; t < N; t++)
            {
                result = 0;
                for (f = 0; f < N; f++)
                {
                    result += A[f].real * Math.Cos(2 * Math.PI * t * f / N) - A[f].im * Math.Sin(2 * Math.PI * t * f / N);
                }
                s[t] = (int)Math.Round(result);
            }
        }
    }
}

私は現在非常に立ち往生しています、どんなそしてすべての助けもいただければ幸いです。ありがとうございました。

編集:

これは、すべてのクラスにアクセスしようとしている場所です。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SoundEditor_V3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        string filename;
        NAudio.Wave.WaveStream waveStream;

        private NAudio.Wave.DirectSoundOut sout = null;

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {

            OpenFileDialog open = new OpenFileDialog();
            open.Filter = "Wave File (*.wav)|*.wav";
            if (open.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            waveStream = new NAudio.Wave.WaveFileReader(open.FileName);
            filename = open.FileName;
            sout = new NAudio.Wave.DirectSoundOut();
            sout.Init(new NAudio.Wave.WaveChannel32(waveStream));

        }

        //Play
        private void Play_btn_Click(object sender, EventArgs e)
        {
            sout.Play();
        }

        //Stop
        private void Stop_btn_Click(object sender, EventArgs e)
        {
            sout.Stop();
            waveStream.Position = 0;
        }

        //Pause
        private void Pause_btn_Click(object sender, EventArgs e)
        {
            sout.Pause();
        }



        //display fourier
        //N = number of samples(length of array)
        //s is the array of samples(data)
        //amp is the array where the complex result will be written to
        //start is the where in the array to start
        static int N = 8;
        byte[] s = {1,2,3,4,5,6,7,8};


        Complex[] amp = new Complex[N];

        Fourier xfo = new Fourier();



        //xfo.DFT(s, N,  amp, 0); 

    }
}
4

4 に答える 4

1

この呼び出しはメソッド内にある必要があります。今のところ、クラスの直下に見えます。

//xfo.DFT(s, N,  amp, 0);

また、を追加refampます。(パラメータvoid DFT(...., ref Complex[] amp,....)を取るように。ref amp

xfo.DFT(s, N, ref amp, 0);
于 2012-10-05T04:20:35.873 に答える
1

おやおや、改善の余地がたくさんあります。

まず、クラスComplexを構造体として使用しています。実際、クラスである必要はないので、構造体にします。

public struct Complex
{
    public double Imaginary;
    public double Real;
}

コンストラクターは必要ありません。デフォルトのコンストラクター(コンパイラーが追加)は、フィールドをタイプに応じてデフォルト値に設定しdoubleます。デフォルト値の場合は0.0(とにかく割り当てているものです*)。

また、imの名前をImaginaryに変更しました。インテリセンスを取得したため、さらに入力する必要があるとは言わないでください。行っていない場合は、MonoDevelopまたはVisualStudioExpressをダウンロードしてください。ああ、私はあなたの考えを感じることができます:私たちはツールを中継するべきではありません。そうですね、それが、概念に慣れていない人でも読みやすいコードを書くもう1つの理由です(検索も簡単になります)。

0*:これは整数リテラルであり、 doubleであることに注意したいのです0.0が、コンパイラーはこれを再調整し、変換を最適化するため、実際の目的では同じです。

フーリエクラスに移りましょう。最初にメソッドDFTをコピーします(Complexのフィールドの名前は名前が変更されています)。

    //FOURIER
    //N = number of samples
    //s is the array of samples(data)
    //amp is the array where the complex result will be written to
    //start is the where in the array to start
    public void DFT(byte[] s, int N, ref Complex[] amp, int start)
    {
        Complex tem = new Complex();
        int f;
        int t;

        for (f = 0; f < N; f++)
        {

            tem.real = 0;
            tem.im = 0;

            for (t = 0; t < N; t++)
            {
                tem.real += s[t + start] * Math.Cos(2 * Math.PI * t * f / N);
                tem.im -= s[t + start] * Math.Sin(2 * Math.PI * t * f / N);
            }
            amp[f].real = tem.real;
            amp[f].im = tem.im;

        }
    }

最初に気付くのは、Nはサンプルの数であり、sはサンプル配列であると言うことです。配列がある場合は、配列のサイズを照会できます。これは、配列の一部のみを処理できるようにする場合でも、良い考えです(私はそれが必要だと思います)。しかし、本当にNとs?

ほら、それは魔法のようなものです:

   //FOURIER
   //amp is the array where the complex result will be written to
   //start is the where in the array to start
   public void DFT(byte[] samples, int samplesCount, ref Complex[] amp, int start)
   {
       Complex tem = new Complex();
       int f;
       int t;

       for (f = 0; f < samplesCount; f++)
       {

           tem.Real = 0;
           tem.Imaginary = 0;

           for (t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
           }
           amp[f].Real = tem.Real;
           amp[f].Imaginary = tem.Imaginary;
       }
   }

さて、次にあなたはアンプが出力であると言います。さて、それが出力なら、メソッドがそれを返すようにしてみませんか?

バム!

   //FOURIER
   //start is the where in the array to start
   Complex[] DFT(byte[] samples, int samplesCount, int start)
   {
       var = new Complex[samplesCount];
       Complex tem = new Complex();
       int f;
       int t;
       for (f = 0; f < samplesCount; f++)
       {

           tem.Real = 0;
           tem.Imaginary = 0;

           for (t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
           }
           result[f].Real = tem.Real;
           result[f].Imaginary = tem.Imaginary;
       }
       return result;
   }

本当に配列である必要がありますか?yieldこれは、キーワードを使用してを返す良い機会だと思いますIEnumerable<Complex>。しかし、私はあなたが望むことを、実際には、配列と見なします。

さて、あなたは配列を返したくなかったのかもしれません。既存のアレイの一部を変更したいだけかもしれません。その場合、あなたはあなたの限界をチェックし始めるべきです。そして、それが真実であったとしても、refはまったく必要ありません!配列は参照型だからです。これは値によって渡される参照です。その考えに頭を悩ませることができない場合は、私を信じてください。配列の内容を変更して、参照せずに外部に反映されることを確認できます...参照によって参照を渡すと、別の人による参照、そしてあなたはそれをしていません。

デモを行うには:

void Main()
{
    var x = new int[1];
    Do(x);
    Console.WriteLine(x);
}

void Do (int[] array)
{
    array[0] = 1;
}

前のプログラム(LinqPadでコンパイル)の出力は「1」です。

しかし、コードに戻りましょう。

fとは何なのかわかりませんt。ありがたいことに、私はimが架空のものであることを知っていました(そうだったでしょう?)。だから私はそれらの名前を変更しません。しかし、私はそれらの定義をループに移します:

   Complex[] DFT(byte[] samples, int samplesCount, int start)
   {
       var result = new Complex[samplesCount];
       Complex tem = new Complex();
       for (int f = 0; f < samplesCount; f++)
       {
           tem.Real = 0;
           tem.Imaginary = 0;
           for (int t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);

           }
           result[f].Real = tem.Real;
           result[f].Imaginary = tem.Imaginary;
       }
       return result;
   }

varキーワードの使用に注意してください。これを使用して、コンパイラは変数の型を、初期化に使用している型に割り当てます。したがって、この場合の結果はですがComplex[]、コードに2回記述する必要はありませんでした。

そして最後に、Complexオブジェクトのコンテンツをコピーする部分も変更します。なんで?Complexは構造体になり、構造体は値型であるためです。したがって、そのコンテンツは参照ではなくコピーされます。

   //FOURIER
   //start is the where in the array to start
   Complex[] DFT(byte[] samples, int samplesCount, int start)
   {
       var result = new Complex[samplesCount];
       Complex tem = new Complex();
       for (int f = 0; f < samplesCount; f++)
       {
           tem.Real = 0;
           tem.Imaginary = 0;
           for (int t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);

           }
           result[f] = tem;
       }
       return result;
   }

私はあなたが本当にあなたの配列のほんの一部を処理したいと思っていることを知っています。しかし、我慢してください...あなたはいくつかのことを学び、そのコードはとにかく役立つでしょう。

次に必要なのはIEnumerable<Complex>、Complexタイプのオブジェクトを取得するために繰り返すことができるすべてのものを表すインターフェイスであるanを返すことです。yieldキーワードも使用します。

さらに、sampleCountを削除し、代わりにsamples.Lengthを使用します。

それがどれほど美しくなるか見てください:

    //FOURIER
    public IEnumerable<Complex> DFT(byte[] samples, int startIndex)
    {
        int samplesLength = samples.Length;
        for (int f = 0; f < samplesLength; f++)
        {
            Complex resultItem = new Complex();
            for (int t = 0; t < samplesLength; t++)
            {
                resultItem.Real += samples[t + startIndex] * Math.Cos(2 * Math.PI * t * f / samplesLength);
                resultItem.Imaginary -= samples[t + startIndex] * Math.Sin(2 * Math.PI * t * f / samplesLength);
            }
            yield return resultItem;
        }
    }

実際、startIndexも削除します(とにかく境界をチェックしていません*)。

*:つまり、インデックスが配列サイズ内にあるかどうかはチェックしていません。私は知っている、私は知っている、あなたは後でそれらを追加するつもりだった...おそらく。

とにかく、あなたはここでいくつかのC#を学んでいます。

    //FOURIER
    public IEnumerable<Complex> DFT(byte[] samples)
    {
        int samplesLength = samples.Length;
        for (int f = 0; f < samplesLength; f++)
        {
            Complex resultItem = new Complex();
            for (int t = 0; t < samplesLength; t++)
            {
                resultItem.Real += samples[t] * Math.Cos(2 * Math.PI * t * f / samplesLength);
                resultItem.Imaginary -= samples[t] * Math.Sin(2 * Math.PI * t * f / samplesLength);
            }
            yield return resultItem;
        }
    }

さて、次に気になるのは、クラスフーリエには状態がないという事実です(フィールドがないか、値が永続化される変数がありません...どういうわけか)。したがって、静的メソッドを使用して静的クラスにします。

public static class Fourier
{
    //FOURIER
    public static IEnumerable<Complex> DFT(byte[] samples)
    {
        int samplesLength = samples.Length;
        for (int f = 0; f < samplesLength; f++)
        {
            Complex resultItem = new Complex();
            for (int t = 0; t < samplesLength; t++)
            {
                resultItem.Real += samples[t] * Math.Cos(2 * Math.PI * t * f / samplesLength);
                resultItem.Imaginary -= samples[t] * Math.Sin(2 * Math.PI * t * f / samplesLength);
            }
            yield return resultItem;
        }
    }
}

もちろん、私がIDFTを追加していないことに気づきました。あれは宿題です。

それでは、どのように使用するか見てみましょう。私の場合、ConsoleApplicationを作成しました。これは、高速に稼働させるためです(GUIの設計に時間を浪費することはありません)。

私が欲しいのは、Fourier.DFTと呼ぶことです。これは、静的であるため、Fourier型のオブジェクトがなくても可能です(実際、Fourier型のオブジェクトは静的であるため作成できません)。

このメソッドは、タイプの引数を受け取りますbyte[]。あれはnew byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }。そして、そのメソッドは、Complexタイプのオブジェクトを取得するために反復するために使用できるものを返します。だから私はそれをループに入れたいと思います。

これは私のコードがどのように見えるかです:

class Program
{
    static void Main(string[] args)
    {
        //display fourier
        foreach (var item in Fourier.DFT(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }))
        {
            Console.WriteLine(item);
        }
    }
}

今...出力は...ドラムロール...

まあ、私はそれを見ることができません、私は忘れましConsole.ReadLine();た、しかしそれを追加した後、出力は...

Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex

待って、何?Complex型のオブジェクトを文字列に変換する方法を教えていないことがあります。それで、それを追加しましょう:

public struct Complex
{
    public double Imaginary;
    public double Real;

    public override string ToString()
    {
        return string.Format("Complex [Real: {0}, Imaginary: {1}]", Real, Imaginary);
    }
}

今私の出力は次のとおりです。

Complex [Real: 36, Imaginary: 0]
Complex [Real: -4, Imaginary: 9,65685424949238]
Complex [Real: -4, Imaginary: 4]
Complex [Real: -4, Imaginary: 1,65685424949239]
Complex [Real: -4, Imaginary: -3,91874033223161E-15]
Complex [Real: -4,00000000000001, Imaginary: -1,65685424949239]
Complex [Real: -4,00000000000002, Imaginary: -4,00000000000001]
Complex [Real: -3,99999999999997, Imaginary: -9,65685424949237]

出力は正しいですか?おかしな考えはありません!私はフーリエについてもっと学ぶ必要があります(しかしそれは合法に見えます)。

検証後、出力は正しいです。


最後の注意点:デバッガーを使用してコードをステップ実行すると、驚きが生じる場合があります(ヒント:yield)。

于 2012-10-05T05:41:45.850 に答える
0

メソッドが必要です。これを試してください。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SoundEditor_V3
{
    public class Complex
    {
        public double real;
        public double im;

        public Complex()
        {
            real = 0;
            im = 0;
        }

        public Setval (double newReal, double newIm)
        {
            real = newReal;
            im = newIm;
        }
    }
}

他のクラスに関して、コンストラクターはどこにありますか?;)

于 2012-10-05T03:52:59.753 に答える
0

助けてくれてありがとう。私は実際にすべてを理解することになった。アクセスしようとした領域のメソッドにアクセスできませんでした。これらはすべてフォーム内にコーディングされていたため、メソッドブロック内に配置する必要がありました。それはとにかく私の理解です。

しかし、繰り返しになりますが、すべての提案に感謝します。それらはすべて役に立ちました。

于 2012-10-06T22:28:16.517 に答える