public void ForwardFft(WWComplex[] aFrom, WWComplex[] aTo) { if (aFrom == null || aFrom.Length != mNumPoints || aTo == null || aTo.Length != mNumPoints) { throw new ArgumentException(); } WWComplex [] aTmp0 = new WWComplex[mNumPoints]; for (int i=0; i < aTmp0.Length; ++i) { aTmp0[i] = new WWComplex(aFrom[mBitReversalTable[i]]); } WWComplex [] aTmp1 = new WWComplex[mNumPoints]; for (int i=0; i<aTmp1.Length; ++i) { aTmp1[i] = new WWComplex(); } WWComplex [][] aTmps = new WWComplex[2][]; aTmps[0] = aTmp0; aTmps[1] = aTmp1; for (int i=0; i<mNumStage-1; ++i) { FftStageN(i, aTmps[((i&1) == 1) ? 1 : 0], aTmps[((i&1) == 0) ? 1 : 0]); } FftStageN(mNumStage - 1, aTmps[(((mNumStage - 1) & 1) == 1) ? 1 : 0], aTo); }
public WWRadix2Fft(int numPoints) { if (!IsPowerOfTwo(numPoints) || numPoints < 2) { throw new ArgumentException(); } mNumPoints = numPoints; mWn = new WWComplex[mNumPoints]; for (int i=0; i < mNumPoints; ++i) { double angle = -2.0 * Math.PI * i / mNumPoints; mWn[i] = new WWComplex(Math.Cos(angle), Math.Sin(angle)); } // mNumStage == log_2(mNumPoints) int t = mNumPoints; for (int i=0; 0 < t; ++i) { t >>= 1; mNumStage = i; } mBitReversalTable = new uint[mNumPoints]; for (uint i=0; i < mNumPoints; ++i) { mBitReversalTable[i] = BitReversal(mNumStage, i); } }
public WWComplex Mul(WWComplex rhs) { #if false // straightforward but slow double tR = real * rhs.real - imaginary * rhs.imaginary; double tI = real * rhs.imaginary + imaginary * rhs.real; real = tR; imaginary = tI; #else // more efficient way double k1 = real * (rhs.real + rhs.imaginary); double k2 = rhs.imaginary * (real + imaginary); double k3 = rhs.real * (imaginary - real); real = k1 - k2; imaginary = k1 + k3; #endif return this; }
public void InverseFft(WWComplex[] aFrom, WWComplex[] aTo, double? compensation = null) { for (int i=0; i < aFrom.LongLength; ++i) { aFrom[i].imaginary *= -1.0; } ForwardFft(aFrom, aTo); double c = 1.0 / mNumPoints; if (compensation != null) { c = (double)compensation; } for (int i=0; i < aTo.LongLength; ++i) { aTo[i].real *= c; aTo[i].imaginary *= -1.0 * c; } }
private void UpdateMagnitudePhase() { var timeDomain = new WWComplex[SampleCount()]; for (int i=0; i < timeDomain.Length; ++i) { timeDomain[i] = new WWComplex(mSLArray[i].Value, 0); } var freqDomain = new WWComplex[SampleCount()]; for (int i=0; i < freqDomain.Length; ++i) { freqDomain[i] = new WWComplex(); } var fft = new WWRadix2Fft(SampleCount()); fft.ForwardFft(timeDomain, freqDomain); UpdateMagnitude(freqDomain); UpdatePhase(freqDomain); }
private void UpdateMagnitude(WWComplex [] freqDomain) { double pointIntervalX = (canvasWaveFormFR.ActualWidth - GRAPH_YAXIS_POS_X) / (SampleCount() / 2 + 1); LineSetX1Y1X2Y2(lineFRX, GRAPH_YAXIS_POS_X, canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X, canvasWaveFormFR.ActualWidth, canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X); LineSetX1Y1X2Y2(lineFRY, GRAPH_YAXIS_POS_X, 0, GRAPH_YAXIS_POS_X, canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X); LineSetX1Y1X2Y2(lineFRTickPHalf, GRAPH_YAXIS_POS_X - 4, (canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X) / 2, GRAPH_YAXIS_POS_X, (canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X) / 2); LineSetX1Y1X2Y2(lineFRTickPMax, GRAPH_YAXIS_POS_X - 4, 0, GRAPH_YAXIS_POS_X, 0); LineSetX1Y1X2Y2(lineFRTickXPi, canvasWaveFormFR.ActualWidth - pointIntervalX, canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X - 4, canvasWaveFormFR.ActualWidth - pointIntervalX, canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X); CanvasSetLeftTop(labelFRPMax, 0, -labelFRPMax.ActualHeight / 2); CanvasSetLeftTop(labelFRPHalf, 0, (canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X) / 2 - labelFRPHalf.ActualHeight/2); CanvasSetLeftTop(labelFR0, 0, canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X-labelFR0.ActualHeight/2); CanvasSetLeftTop(labelFRXPi, canvasWaveFormFR.ActualWidth - pointIntervalX - labelFRXPi.ActualWidth / 2, canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X); labelFRPMax.Content = string.Format("{0}", SampleCount()); labelFRPHalf.Content = string.Format("{0}", SampleCount()/2); foreach (var t in mMagnitudeGraph.points) { canvasWaveFormFR.Children.Remove(t.Item1); canvasWaveFormFR.Children.Remove(t.Item2); } mMagnitudeGraph.points.Clear(); for (int i=0; i < SampleCount()/2+1; ++i) { double x = GRAPH_YAXIS_POS_X + pointIntervalX * i; double y = canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X - (canvasWaveFormFR.ActualHeight - GRAPH_YAXIS_POS_X) * freqDomain[i].Magnitude() / SampleCount(); var el = new Ellipse(); el.Width = 6; el.Height = 6; el.Fill = Brushes.Black; canvasWaveFormFR.Children.Add(el); CanvasSetLeftTop(el, x - 3, y - 3); var la = new Label(); la.Content = string.Format("{0:0.00}", freqDomain[i].Magnitude()); canvasWaveFormFR.Children.Add(la); CanvasSetLeftTop(la, x, y-labelFRPMax.ActualHeight/2); mMagnitudeGraph.points.Add(new Tuple<Ellipse, Label>(el, la)); } }
public void CopyFrom(WWComplex rhs) { real = rhs.real; imaginary = rhs.imaginary; }
public WWComplex Add(WWComplex rhs) { real += rhs.real; imaginary += rhs.imaginary; return this; }
public WWComplex(WWComplex rhs) { this.real = rhs.real; this.imaginary = rhs.imaginary; }
private void FftStageN(int stageNr, WWComplex[] x, WWComplex[] y) { /* * stage0: 2つの入力データにバタフライ演算 (n=8の時) 4回 (nRepeat=4, nSubRepeat=2) * y[0] = x[0] + w_n^(0*4) * x[1] * y[1] = x[0] + w_n^(1*4) * x[1] * * y[2] = x[2] + w_n^(0*4) * x[3] * y[3] = x[2] + w_n^(1*4) * x[3] * * y[4] = x[4] + w_n^(0*4) * x[5] * y[5] = x[4] + w_n^(1*4) * x[5] * * y[6] = x[6] + w_n^(0*4) * x[7] * y[7] = x[6] + w_n^(1*4) * x[7] */ /* * stage1: 4つの入力データにバタフライ演算 (n=8の時) 2回 (nRepeat=2, nSubRepeat=4) * y[0] = x[0] + w_n^(0*2) * x[2] * y[1] = x[1] + w_n^(1*2) * x[3] * y[2] = x[0] + w_n^(2*2) * x[2] * y[3] = x[1] + w_n^(3*2) * x[3] * * y[4] = x[4] + w_n^(0*2) * x[6] * y[5] = x[5] + w_n^(1*2) * x[7] * y[6] = x[4] + w_n^(2*2) * x[6] * y[7] = x[5] + w_n^(3*2) * x[7] */ /* * stage2: 8つの入力データにバタフライ演算 (n=8の時) 1回 (nRepeat=1, nSubRepeat=8) * y[0] = x[0] + w_n^(0*1) * x[4] * y[1] = x[1] + w_n^(1*1) * x[5] * y[2] = x[2] + w_n^(2*1) * x[6] * y[3] = x[3] + w_n^(3*1) * x[7] * y[4] = x[0] + w_n^(4*1) * x[4] * y[5] = x[1] + w_n^(5*1) * x[5] * y[6] = x[2] + w_n^(6*1) * x[6] * y[7] = x[3] + w_n^(7*1) * x[7] */ /* * stageN: */ int nRepeat = Pow2(mNumStage - stageNr - 1); int nSubRepeat = mNumPoints / nRepeat; var t = new WWComplex(); for (int i=0; i<nRepeat; ++i) { int offsBase = i * nSubRepeat; bool allZero = true; for (int j=0; j < nSubRepeat/2; ++j) { int offs = offsBase + (j % (nSubRepeat/2)); if (Double.Epsilon < x[offs].Magnitude()) { allZero = false; break; } if (Double.Epsilon < x[offs + nSubRepeat / 2].Magnitude()) { allZero = false; break; } } if (allZero) { for (int j=0; j < nSubRepeat / 2; ++j) { y[j + offsBase].Set(0, 0); } } else { for (int j=0; j < nSubRepeat; ++j) { int offs = offsBase + (j % (nSubRepeat / 2)); y[j + offsBase].CopyFrom(x[offs]); t.CopyFrom(mWn[j * nRepeat]); t.Mul(x[offs + nSubRepeat / 2]); y[j + offsBase].Add(t); } } } }
public WWComplex Add(WWComplex rhs) { real += rhs.real; imaginary += rhs.imaginary; return(this); }
private void FftStageN(int stageNr, WWComplex[] x, WWComplex[] y) { /* * stage0: 2つの入力データにバタフライ演算 (n=8の時) 4回 (nRepeat=4, nSubRepeat=2) * y[0] = x[0] + w_n^(0*4) * x[1] * y[1] = x[0] + w_n^(1*4) * x[1] * * y[2] = x[2] + w_n^(0*4) * x[3] * y[3] = x[2] + w_n^(1*4) * x[3] * * y[4] = x[4] + w_n^(0*4) * x[5] * y[5] = x[4] + w_n^(1*4) * x[5] * * y[6] = x[6] + w_n^(0*4) * x[7] * y[7] = x[6] + w_n^(1*4) * x[7] */ /* * stage1: 4つの入力データにバタフライ演算 (n=8の時) 2回 (nRepeat=2, nSubRepeat=4) * y[0] = x[0] + w_n^(0*2) * x[2] * y[1] = x[1] + w_n^(1*2) * x[3] * y[2] = x[0] + w_n^(2*2) * x[2] * y[3] = x[1] + w_n^(3*2) * x[3] * * y[4] = x[4] + w_n^(0*2) * x[6] * y[5] = x[5] + w_n^(1*2) * x[7] * y[6] = x[4] + w_n^(2*2) * x[6] * y[7] = x[5] + w_n^(3*2) * x[7] */ /* * stage2: 8つの入力データにバタフライ演算 (n=8の時) 1回 (nRepeat=1, nSubRepeat=8) * y[0] = x[0] + w_n^(0*1) * x[4] * y[1] = x[1] + w_n^(1*1) * x[5] * y[2] = x[2] + w_n^(2*1) * x[6] * y[3] = x[3] + w_n^(3*1) * x[7] * y[4] = x[0] + w_n^(4*1) * x[4] * y[5] = x[1] + w_n^(5*1) * x[5] * y[6] = x[2] + w_n^(6*1) * x[6] * y[7] = x[3] + w_n^(7*1) * x[7] */ /* * stageN: */ int nRepeat = Pow2(mNumStage - stageNr - 1); int nSubRepeat = mNumPoints / nRepeat; var t = new WWComplex(); for (int i = 0; i < nRepeat; ++i) { int offsBase = i * nSubRepeat; bool allZero = true; for (int j = 0; j < nSubRepeat / 2; ++j) { int offs = offsBase + (j % (nSubRepeat / 2)); if (Double.Epsilon < x[offs].Magnitude()) { allZero = false; break; } if (Double.Epsilon < x[offs + nSubRepeat / 2].Magnitude()) { allZero = false; break; } } if (allZero) { for (int j = 0; j < nSubRepeat / 2; ++j) { y[j + offsBase].Set(0, 0); } } else { for (int j = 0; j < nSubRepeat; ++j) { int offs = offsBase + (j % (nSubRepeat / 2)); y[j + offsBase].CopyFrom(x[offs]); t.CopyFrom(mWn[j * nRepeat]); t.Mul(x[offs + nSubRepeat / 2]); y[j + offsBase].Add(t); } } } }
private void UpdatePhase(WWComplex[] freqDomain) { double pointIntervalX = (canvasWaveFormPhase.ActualWidth - GRAPH_YAXIS_POS_X) / (SampleCount() / 2 + 1); LineSetX1Y1X2Y2(linePX, GRAPH_YAXIS_POS_X, canvasWaveFormPhase.ActualHeight / 2, canvasWaveFormPhase.ActualWidth, canvasWaveFormPhase.ActualHeight / 2); LineSetX1Y1X2Y2(linePY, GRAPH_YAXIS_POS_X, 0, GRAPH_YAXIS_POS_X, canvasWaveFormPhase.ActualHeight); LineSetX1Y1X2Y2(linePTickPPi, GRAPH_YAXIS_POS_X - 4, 0, GRAPH_YAXIS_POS_X, 0); LineSetX1Y1X2Y2(linePTickMPi, GRAPH_YAXIS_POS_X - 4, canvasWaveFormPhase.ActualHeight-1, GRAPH_YAXIS_POS_X, canvasWaveFormPhase.ActualHeight-1); LineSetX1Y1X2Y2(linePTickXPi, canvasWaveFormPhase.ActualWidth - pointIntervalX, canvasWaveFormPhase.ActualHeight / 2 - 4, canvasWaveFormPhase.ActualWidth - pointIntervalX, canvasWaveFormPhase.ActualHeight / 2); CanvasSetLeftTop(labelPPPi, 0, 0 - labelPPPi.ActualHeight / 2); CanvasSetLeftTop(labelPMPi, 0, canvasWaveFormPhase.ActualHeight - labelPMPi.ActualHeight/2); CanvasSetLeftTop(labelP0, 0, canvasWaveFormPhase.ActualHeight / 2 - labelPMPi.ActualHeight / 2); CanvasSetLeftTop(labelPXPi, canvasWaveFormPhase.ActualWidth - pointIntervalX - labelPXPi.ActualWidth/2, canvasWaveFormPhase.ActualHeight / 2); foreach (var t in mPhaseGraph.points) { canvasWaveFormPhase.Children.Remove(t.Item1); canvasWaveFormPhase.Children.Remove(t.Item2); } mPhaseGraph.points.Clear(); for (int i=0; i < SampleCount() / 2 + 1; ++i) { double x = GRAPH_YAXIS_POS_X + pointIntervalX * i; double y = canvasWaveFormPhase.ActualHeight/2 - (canvasWaveFormPhase.ActualHeight)/2/Math.PI * freqDomain[i].Phase(); var el = new Ellipse(); el.Width = 6; el.Height = 6; el.Fill = Brushes.Black; canvasWaveFormPhase.Children.Add(el); CanvasSetLeftTop(el, x - 3, y - 3); var la = new Label(); la.Content = string.Format("{0:0.00}", freqDomain[i].Phase()); canvasWaveFormPhase.Children.Add(la); CanvasSetLeftTop(la, x, y - labelP0.ActualHeight/2); mPhaseGraph.points.Add(new Tuple<Ellipse, Label>(el, la)); } }
private void UpdateUpsampleGraph() { LineSetX1Y1X2Y2(lineUSX, 0, canvasUpsampleGraph.ActualHeight / 2, canvasUpsampleGraph.ActualWidth, canvasUpsampleGraph.ActualHeight / 2); LineSetX1Y1X2Y2(lineUSY, GRAPH_YAXIS_POS_X, 0, GRAPH_YAXIS_POS_X, canvasUpsampleGraph.ActualHeight); LineSetX1Y1X2Y2(lineUSTickP1, GRAPH_YAXIS_POS_X - 4, canvasUpsampleGraph.ActualHeight / 4, GRAPH_YAXIS_POS_X, canvasUpsampleGraph.ActualHeight / 4); LineSetX1Y1X2Y2(lineUSTickM1, GRAPH_YAXIS_POS_X - 4, canvasUpsampleGraph.ActualHeight * 3 / 4, GRAPH_YAXIS_POS_X, canvasUpsampleGraph.ActualHeight * 3 / 4); CanvasSetLeftTop(labelUSP1, 0, canvasUpsampleGraph.ActualHeight / 4 - labelUSP1.ActualHeight / 2); CanvasSetLeftTop(labelUS0, 0, canvasUpsampleGraph.ActualHeight / 2 - labelUS0.ActualHeight / 2); CanvasSetLeftTop(labelUSM1, 0, canvasUpsampleGraph.ActualHeight * 3 / 4 - labelUSM1.ActualHeight / 2); foreach (var t in mUpsampleGraph.points) { canvasUpsampleGraph.Children.Remove(t.Item1); canvasUpsampleGraph.Children.Remove(t.Item2); canvasUpsampleGraph.Children.Remove(t.Item3); } mUpsampleGraph.points.Clear(); // オリジナルPCMデータtimeDomainOrigをFFTして周波数ドメインデータfreqDomainOrigを得る var timeDomainOrig = new WWComplex[SampleCount()]; for (int i = 0; i < timeDomainOrig.Length; ++i) { timeDomainOrig[i] = new WWComplex(mSLArray[i].Value, 0); } var freqDomainOrig = new WWComplex[SampleCount()]; { var fft = new WWRadix2Fft(SampleCount()); fft.ForwardFft(timeDomainOrig, freqDomainOrig); } timeDomainOrig = null; // 周波数ドメインデータfreqDomainOrigを0で水増ししたデータfreqDomainUpsampledを作って逆FFTする int upsampledSampleCount = SampleCount() * UpsampleMultiple(); var freqDomainUpsampled = new WWComplex[upsampledSampleCount]; for (int i = 0; i < freqDomainUpsampled.Length; ++i) { if (i <= freqDomainOrig.Length / 2) { freqDomainUpsampled[i].CopyFrom(freqDomainOrig[i]); if (i == freqDomainOrig.Length / 2) { freqDomainUpsampled[i].Mul(0.5); } } else if (freqDomainUpsampled.Length - freqDomainOrig.Length / 2 <= i) { int pos = i + freqDomainOrig.Length - freqDomainUpsampled.Length; freqDomainUpsampled[i].CopyFrom(freqDomainOrig[pos]); if (freqDomainUpsampled.Length - freqDomainOrig.Length / 2 == i) { freqDomainUpsampled[i].Mul(0.5); } } else { // do nothing } } freqDomainOrig = null; var timeDomainUpsampled = new WWComplex[upsampledSampleCount]; { var fft = new WWRadix2Fft(upsampledSampleCount); fft.InverseFft(freqDomainUpsampled, timeDomainUpsampled, 1.0 / SampleCount()); } freqDomainUpsampled = null; // アップサンプルされたPCMデータtimeDomainUpsampledをグラフにプロットする double pointIntervalX = (canvasUpsampleGraph.ActualWidth - GRAPH_YAXIS_POS_X) / (upsampledSampleCount + 2 * UpsampleMultiple()); for (int i = 0; i < upsampledSampleCount; ++i) { double x = GRAPH_YAXIS_POS_X + pointIntervalX * (i + UpsampleMultiple()); double y = canvasUpsampleGraph.ActualHeight / 2 - (canvasUpsampleGraph.ActualHeight / 4) * timeDomainUpsampled[i].real; var el = new Ellipse(); el.Width = 6; el.Height = 6; el.Fill = Brushes.Black; canvasUpsampleGraph.Children.Add(el); CanvasSetLeftTop(el, x - 3, y - 3); var la = new Label(); la.Content = string.Format("{0:0.00}", timeDomainUpsampled[i].real); canvasUpsampleGraph.Children.Add(la); if (timeDomainUpsampled[i].real >= 0) { CanvasSetLeftTop(la, x - 16, y - labelUS0.ActualHeight); } else { CanvasSetLeftTop(la, x - 16, y); } var li = new Line(); li.Stroke = Brushes.Black; canvasUpsampleGraph.Children.Add(li); LineSetX1Y1X2Y2(li, x, y, x, canvasUpsampleGraph.ActualHeight / 2); mUpsampleGraph.points.Add(new Tuple <Ellipse, Label, Line>(el, la, li)); } }
private void UpdateUpsampleGraph() { LineSetX1Y1X2Y2(lineUSX, 0, canvasUpsampleGraph.ActualHeight / 2, canvasUpsampleGraph.ActualWidth, canvasUpsampleGraph.ActualHeight / 2); LineSetX1Y1X2Y2(lineUSY, GRAPH_YAXIS_POS_X, 0, GRAPH_YAXIS_POS_X, canvasUpsampleGraph.ActualHeight); LineSetX1Y1X2Y2(lineUSTickP1, GRAPH_YAXIS_POS_X - 4, canvasUpsampleGraph.ActualHeight / 4, GRAPH_YAXIS_POS_X, canvasUpsampleGraph.ActualHeight / 4); LineSetX1Y1X2Y2(lineUSTickM1, GRAPH_YAXIS_POS_X - 4, canvasUpsampleGraph.ActualHeight * 3 / 4, GRAPH_YAXIS_POS_X, canvasUpsampleGraph.ActualHeight * 3 / 4); CanvasSetLeftTop(labelUSP1, 0, canvasUpsampleGraph.ActualHeight / 4 - labelUSP1.ActualHeight / 2); CanvasSetLeftTop(labelUS0, 0, canvasUpsampleGraph.ActualHeight / 2 - labelUS0.ActualHeight / 2); CanvasSetLeftTop(labelUSM1, 0, canvasUpsampleGraph.ActualHeight * 3 / 4 - labelUSM1.ActualHeight / 2); foreach (var t in mUpsampleGraph.points) { canvasUpsampleGraph.Children.Remove(t.Item1); canvasUpsampleGraph.Children.Remove(t.Item2); canvasUpsampleGraph.Children.Remove(t.Item3); } mUpsampleGraph.points.Clear(); // オリジナルPCMデータtimeDomainOrigをFFTして周波数ドメインデータfreqDomainOrigを得る var timeDomainOrig = new WWComplex[SampleCount()]; for (int i=0; i < timeDomainOrig.Length; ++i) { timeDomainOrig[i] = new WWComplex(mSLArray[i].Value, 0); } var freqDomainOrig = new WWComplex[SampleCount()]; { var fft = new WWRadix2Fft(SampleCount()); fft.ForwardFft(timeDomainOrig, freqDomainOrig); } timeDomainOrig = null; // 周波数ドメインデータfreqDomainOrigを0で水増ししたデータfreqDomainUpsampledを作って逆FFTする int upsampledSampleCount = SampleCount() * UpsampleMultiple(); var freqDomainUpsampled = new WWComplex[upsampledSampleCount]; for (int i=0; i < freqDomainUpsampled.Length; ++i) { if (i <= freqDomainOrig.Length / 2) { freqDomainUpsampled[i].CopyFrom(freqDomainOrig[i]); if (i == freqDomainOrig.Length / 2) { freqDomainUpsampled[i].Mul(0.5); } } else if (freqDomainUpsampled.Length - freqDomainOrig.Length / 2 <= i) { int pos = i + freqDomainOrig.Length - freqDomainUpsampled.Length; freqDomainUpsampled[i].CopyFrom(freqDomainOrig[pos]); if (freqDomainUpsampled.Length - freqDomainOrig.Length / 2 == i) { freqDomainUpsampled[i].Mul(0.5); } } else { // do nothing } } freqDomainOrig = null; var timeDomainUpsampled = new WWComplex[upsampledSampleCount]; { var fft = new WWRadix2Fft(upsampledSampleCount); fft.InverseFft(freqDomainUpsampled, timeDomainUpsampled, 1.0 / SampleCount()); } freqDomainUpsampled = null; // アップサンプルされたPCMデータtimeDomainUpsampledをグラフにプロットする double pointIntervalX = (canvasUpsampleGraph.ActualWidth - GRAPH_YAXIS_POS_X) / (upsampledSampleCount + 2 * UpsampleMultiple()); for (int i=0; i < upsampledSampleCount; ++i) { double x = GRAPH_YAXIS_POS_X + pointIntervalX * (i + UpsampleMultiple()); double y = canvasUpsampleGraph.ActualHeight / 2 - (canvasUpsampleGraph.ActualHeight / 4) * timeDomainUpsampled[i].real; var el = new Ellipse(); el.Width = 6; el.Height = 6; el.Fill = Brushes.Black; canvasUpsampleGraph.Children.Add(el); CanvasSetLeftTop(el, x - 3, y - 3); var la = new Label(); la.Content = string.Format("{0:0.00}", timeDomainUpsampled[i].real); canvasUpsampleGraph.Children.Add(la); if (timeDomainUpsampled[i].real >= 0) { CanvasSetLeftTop(la, x - 16, y - labelUS0.ActualHeight); } else { CanvasSetLeftTop(la, x - 16, y); } var li = new Line(); li.Stroke = Brushes.Black; canvasUpsampleGraph.Children.Add(li); LineSetX1Y1X2Y2(li, x, y, x, canvasUpsampleGraph.ActualHeight / 2); mUpsampleGraph.points.Add(new Tuple<Ellipse, Label, Line>(el, la, li)); } }
private void Butterfly(WWComplex vFrom0, WWComplex vFrom1, WWComplex wn, WWComplex[] vTo, int toPos) { vTo[toPos].CopyFrom(vFrom0); WWComplex t = new WWComplex(vFrom1); t.Mul(wn); vTo[toPos].Mul(t); vTo[toPos + 1].CopyFrom(vFrom0); t.Mul(-1); vTo[toPos + 1].Mul(t); }