private double CalcCost(Lpf a, Lpf b)
        {
            double cost = 0;

            int N = a.delay.DelaySamples;

            for (int i = 0; i < N; ++i)
            {
                double aD = a.delay.GetNthDelayedSampleValue(i);
                double bD = b.delay.GetNthDelayedSampleValue(i);
                cost += (aD - bD) * (aD - bD);
            }

            return(cost);
        }
        public override PcmFormat Setup(PcmFormat inputFormat)
        {
            double fc         = 20 * 1000;
            double fs         = 150 * 1000;
            int    sampleFreq = 44100 * 64;

            var iir = new WWIIRFilterDesign.IIRFilterDesign();

            if (!iir.Design(fc, fs, sampleFreq, WWIIRFilterDesign.IIRFilterDesign.Method.Bilinear))
            {
                Console.WriteLine("Error: iir.Design failed");
                return(null);
            }

#if false
            // インパルス応答波形を出力。
            {
                var fg = iir.CreateIIRFilterGraph();
                lock (fg) {
                    using (var sw = new System.IO.StreamWriter("C:/audio/impulseResponseBW.csv")) {
                        for (int i = 0; i < 8000; ++i)
                        {
                            double r = fg.Filter(i == 0 ? 1 : 0);
                            sw.WriteLine("{0} {1}", i, r);
                        }
                    }
                }
            }
#endif

            var filterGraph = iir.CreateIIRFilterGraph();
            mOriginalSignal = new Lpf(filterGraph);

            mCandidates = new Lpf[InspectCandidates()];
            for (int i = 0; i < InspectCandidates(); ++i)
            {
                mCandidates[i] = new Lpf(mOriginalSignal);
            }

            // INSPECT_BITSビットのあらゆるビットパターンをそれぞれのフィルターに投入。

            /* INSPECT_BITS == 3のとき 8通り。
             * idx==0 000 : -1, -1, -1
             * idx==1 001 : +1, -1, -1
             * idx==2 010 : -1, +1, -1
             * idx==3 011 : +1, +1, -1
             * idx==4 100 : -1, -1, +1
             * idx==5 101 : +1, -1, +1
             * idx==6 110 : -1, +1, +1
             * idx==7 111 : +1, +1, +1
             */
            Parallel.For(0, InspectCandidates(), idx => {
                var lpf = mCandidates[idx];
                for (int i = 0; i < INSPECT_BITS; ++i)
                {
                    int bit  = 1 & (idx >> i);
                    double v = (bit == 1) ? +1.0 : -1.0;
                    lpf.Filter(v);
                }
            });

            mProcessed = 0;

            return(new PcmFormat(inputFormat));
        }
 public Lpf(Lpf rhs)
 {
     fg    = rhs.fg.CreateCopy();
     delay = rhs.delay.CreateCopy();
 }
        private bool Process(double x, out double y)
        {
            bool result = false;

            y = 0;

            if (mProcessed < INSPECT_BITS - 1)
            {
                mOriginalSignal.Filter(x);
            }
            else
            {
                result = true;

                // オリジナル信号を更新。
                mOriginalSignal.Filter(x);

                double smallestCost = double.MaxValue;
                int    chosenIdx    = -1;

                // 候補ビット列から、最もオリジナル信号と似ているものを選ぶ ==> y。
                for (int i = 0; i < InspectCandidates(); ++i)
                {
                    var    lpf  = mCandidates[i];
                    double cost = CalcCost(mOriginalSignal, lpf);
                    if (cost < smallestCost)
                    {
                        y            = ((i & 1) == 1) ? +1.0 : -1.0;
                        smallestCost = cost;
                        chosenIdx    = i;
                    }
                }

                // yが決定した。
                // 候補ビット列を1ビット進めます。
                if (y == -1.0)
                {
                    /* INSPECT_BITS == 3のとき
                     *            -1で始まるシーケンスが選択された。
                     *            vv
                     * i==0 000 : -1, -1, -1 ==> そのまま使用。-1を投入。
                     * i==1 001 : +1, -1, -1 ==> i==0をコピー。+1を投入。
                     * i==2 010 : -1, +1, -1 ==> そのまま使用。-1を投入。
                     * i==3 011 : +1, +1, -1 ==> i==2をコピー。+1を投入。
                     * i==4 100 : -1, -1, +1 ==> そのまま使用。-1を投入。
                     * i==5 101 : +1, -1, +1 ==> i==4をコピー。+1を投入。
                     * i==6 110 : -1, +1, +1 ==> そのまま使用。-1を投入。
                     * i==7 111 : +1, +1, +1 ==> i==6をコピー。+1を投入。
                     */
                    var newLpfCand = new Lpf[InspectCandidates()];
                    //for (int i = 0; i < InspectCandidates()/2; ++i) {
                    Parallel.For(0, InspectCandidates() / 2, i => {
                        newLpfCand[i * 2 + 0] = mCandidates[i * 2];
                        newLpfCand[i * 2 + 1] = new Lpf(mCandidates[i * 2]);
                        newLpfCand[i * 2 + 0].Filter(-1.0);
                        newLpfCand[i * 2 + 1].Filter(+1.0);
                    });
                    mCandidates = newLpfCand;
                }
                else
                {
                    // y == +1.0

                    /* INSPECT_BITS == 3のとき
                     *            +1で始まるシーケンスが選択された。
                     *            vv
                     * i==0 000 : -1, -1, -1 ==> i==1をコピー。-1を投入。
                     * i==1 001 : +1, -1, -1 ==> そのまま使用。+1を投入。
                     * i==2 010 : -1, +1, -1 ==> i==3をコピー。-1を投入。
                     * i==3 011 : +1, +1, -1 ==> そのまま使用。+1を投入。
                     * i==4 100 : -1, -1, +1 ==> i==5をコピー。-1を投入。
                     * i==5 101 : +1, -1, +1 ==> そのまま使用。+1を投入。
                     * i==6 110 : -1, +1, +1 ==> i==7をコピー。-1を投入。
                     * i==7 111 : +1, +1, +1 ==> そのまま使用。+1を投入。
                     */
                    var newLpfCand = new Lpf[InspectCandidates()];
                    //for (int i=0; i<InspectCandidates()/2; ++i) {
                    Parallel.For(0, InspectCandidates() / 2, i => {
                        newLpfCand[i * 2 + 0] = mCandidates[i * 2 + 1];
                        newLpfCand[i * 2 + 1] = new Lpf(mCandidates[i * 2 + 1]);
                        newLpfCand[i * 2 + 0].Filter(-1.0);
                        newLpfCand[i * 2 + 1].Filter(+1.0);
                    });
                    mCandidates = newLpfCand;
                }
            }

            ++mProcessed;
            return(result);
        }