/// <summary> /// FIR filter design using frequency sampling method (like firwin2 in sciPy). /// /// This method doesn't do any interpolation of the magnitude response, /// so you need to take care of it before calling the method. /// Usage example: /// /// var zeros = Enumerable.Repeat(0.0, 80); /// var ones1 = Enumerable.Repeat(1.0, 80); /// var ones2 = Enumerable.Repeat(1.0, 40); /// var magnitudes = ones1.Concat(zeros).Concat(ones2).ToArray(); /// // 80 ones + 80 zeros + 40 ones = 200 magnitude values /// // 56 zero magnitude values will be added for closest power of two (256) /// /// var kernel = DesignFilter.Fir(101, magnitudes); /// /// var filter = new FirFilter(kernel); /// /// </summary> /// <param name="order">Filter order</param> /// <param name="magnitudeResponse">Magnitude response</param> /// <param name="window">Window</param> /// <returns>FIR filter kernel</returns> public static double[] Fir(int order, double[] magnitudeResponse, WindowTypes window = WindowTypes.Blackman) { // 2x because we reserve space for symmetric part var fftSize = 2 * MathUtils.NextPowerOfTwo(magnitudeResponse.Length); var complexResponse = new Complex[fftSize]; for (var i = 0; i < magnitudeResponse.Length; i++) { complexResponse[i] = magnitudeResponse[i] * Complex.Exp(new Complex(0, -(order - 1) / 2.0 * 2 * Math.PI * i / fftSize)); } var real = complexResponse.Select(c => c.Real).ToArray(); var imag = complexResponse.Select(c => c.Imaginary).ToArray(); var kernel = new double[fftSize]; var fft = new RealFft64(fftSize); fft.Inverse(real, imag, real); kernel = real.Take(order).Select(s => s / fftSize).ToArray(); kernel.ApplyWindow(window); return(kernel); }
private static Tuple <double[], double[]> zpk2tf(Complex[] z, Complex[] p, double k) { double[] numCoeffResult; double[] denCoeffResult; Complex[] numCoeffs = new Complex[1] { new Complex(1.0, 0.0) }; Complex[] denCoeffs = new Complex[1] { new Complex(1.0, 0.0) }; foreach (Complex zero in z) { numCoeffs = MultiplyPolynomial(numCoeffs, new Complex[2] { Complex.One, -zero }); } numCoeffs = numCoeffs.Select(s => s * k).ToArray(); foreach (Complex pole in p) { denCoeffs = MultiplyPolynomial(denCoeffs, new Complex[2] { Complex.One, -pole }); } numCoeffResult = numCoeffs.Select(s => s.Real).ToArray(); denCoeffResult = denCoeffs.Select(s => s.Real).ToArray(); return(new Tuple <double[], double[]>(numCoeffResult, denCoeffResult)); }
public double[][] Process(double[][] input) { var inputLeft = input[0].Select(x => (Complex)x).Concat(new Complex[SignalLen - input[0].Length]).ToArray(); var inputRight = input[1].Select(x => (Complex)x).Concat(new Complex[SignalLen - input[1].Length]).ToArray(); fftSignalLeft = new Complex[inputLeft.Length]; fftSignalRight = new Complex[inputRight.Length]; fftTransform.FFT(inputLeft, fftSignalLeft); fftTransform.FFT(inputRight, fftSignalRight); var bands = GetBands(); ProcessEqBands(bands); ProcessPhaseBands(bands); var outputFinal = new Complex[SignalLen]; fftTransform.IFFT(fftSignalLeft, outputFinal); var leftOutput = outputFinal.Select(x => x.Real).ToArray(); fftTransform.IFFT(fftSignalRight, outputFinal); var rightOutput = outputFinal.Select(x => x.Real).ToArray(); ProcessBlend(leftOutput, rightOutput); return(new[] { leftOutput, rightOutput }); }
/// <summary> /// Calculate function self-convolution values /// </summary> /// <param name="f">Function values</param> /// <returns></returns> public double[] Build(double[] f) { int length = (_functionType == FunctionType.Periodic) ? f.Length : (f.Length + f.Length - 1); var input = new fftw_complexarray(length); var output = new fftw_complexarray(length); fftw_plan forward = fftw_plan.dft_1d(length, input, output, fftw_direction.Forward, fftw_flags.Estimate); fftw_plan backward = fftw_plan.dft_1d(length, input, output, fftw_direction.Backward, fftw_flags.Estimate); var complex = new Complex[length]; for (int i = 0; i < f.Length; i++) { complex[i] = f[i]; } input.SetData(complex); forward.Execute(); complex = output.GetData_Complex(); input.SetData(complex.Select(x => x * x / length).ToArray()); backward.Execute(); complex = output.GetData_Complex(); return(complex.Select(x => x.Magnitude).ToArray()); }
/// <summary> /// Computes the FFT on the provided arrary. A Hamming window is applied on the samples before processing /// </summary> /// <param name="IsamplesArray"></param> /// <param name="QsamplesArray"></param> /// <param name="normaliseMagnitude"></param> /// <param name="shiftFFT"></param> /// <returns></returns> public static List <double> ComputeFft(Int16[] IsamplesArray, Int16[] QsamplesArray, bool normaliseMagnitude, bool shiftFFT) { if (IsamplesArray.Count() == 0 || QsamplesArray.Count() == 0) { return(new List <double>()); } var noOfSamplesPerArray = IsamplesArray.Length; var smoothSamplesI = new double[noOfSamplesPerArray]; var smoothSamplesQ = new double[noOfSamplesPerArray]; var smoothingWindow = MathNet.Numerics.Window.Hamming(noOfSamplesPerArray); //Apply Hamming smoothing window for (var i = 0; i < noOfSamplesPerArray; i++) { smoothSamplesI[i] = smoothingWindow[i] * IsamplesArray[i]; smoothSamplesQ[i] = smoothingWindow[i] * QsamplesArray[i]; } var arrComplex = new Complex[noOfSamplesPerArray]; for (var i = 0; i < noOfSamplesPerArray; i++) { arrComplex[i] = new Complex(smoothSamplesI[i], smoothSamplesQ[i]); } Fourier.Forward(arrComplex, normaliseMagnitude ? FourierOptions.Matlab : FourierOptions.Default); if (shiftFFT) { var fftShifted = ShiftFFT(arrComplex); return(fftShifted.Select(c => c.Magnitude).ToList()); } return(arrComplex.Select(c => c.Magnitude).ToList()); }
private static Tuple <Complex[], Complex[], double> zpk_lowpass2bandpass(Complex[] z, Complex[] p, double k, double w0, double bw) { if (z.Length > p.Length) { throw new ArgumentException("Must have at least as many poles as zeros"); } int degree = p.Length - z.Length; Complex[] z_lp = new Complex[z.Length]; Complex[] p_lp = new Complex[p.Length]; for (int i = 0; i < z_lp.Length; i++) { z_lp[i] = z[i] * (bw / 2); } for (int i = 0; i < p_lp.Length; i++) { p_lp[i] = p[i] * (bw / 2); } Complex[] z_bp = z_lp.Select(s => s + Complex.Sqrt(s * s - w0 * w0)).ToArray().Concat(z_lp.Select(s => s - Complex.Sqrt(s * s - w0 * w0))).ToArray(); Complex[] p_bp = p_lp.Select(s => s + Complex.Sqrt(s * s - w0 * w0)).ToArray().Concat(p_lp.Select(s => s - Complex.Sqrt(s * s - w0 * w0))).ToArray(); z_bp = z_bp.Concat(Enumerable.Repeat(Complex.Zero, degree)).ToArray(); double k_bp = k * Math.Pow(bw, degree); return(new Tuple <Complex[], Complex[], double>(z_bp, p_bp, k_bp)); }
public static Complex[] FFTn(Complex[] x, int M, bool inverse) { int N = x.Length; //М - шаг разбиения Complex[] fft = new Complex[N]; Complex[] X = new Complex[N]; int L = N / M; int p = (int)Log(L, 2); //подготовили бпф по наборам for (int z = 0; z < M; z++) { Complex[] range = x.Where((c, i) => (i - z) % M == 0).ToArray(); var fourier = IFFT(range, inverse); for (int l = 0; l < L; l++) { fft[z + M * l] = fourier[l]; } } for (int s = 0; s < M; s++) { for (int r = 0; r < L; r++) { X[r + s * L] = 0; for (int m = 0; m < M; m++) { X[r + s * L] += fft[m + r * M] * Complex.FromPolarCoordinates(1, -2 * PI * m * (r + s * L) / N); } } } return(X.Select(c => c / (inverse?1:N)).ToArray()); }
//Быстрое дискретное синус-преобразование private static double[] Ettas(IReadOnlyList <double> a) { var n = a.Count; var b = new double[2 * n]; b[0] = 0; for (var i = 1; i < n; i++) { b[i] = a[i] / i; } b[n] = 0; for (var i = 1; i < n; i++) { b[2 * n - i] = -a[i] / i; } var h = new Complex[n]; for (int i = 0; i < n; i++) { h[i] = new Complex(b[2 * i], b[2 * i + 1]); } var a1 = InvFftForRealInput(h); var c = new Complex[n]; for (var i = 0; i < c.Length; i++) { c[i] = Sqrt(2.0) / PI * a1[i] / ImagNum; } return(c.Select(x => x.Real).ToArray()); }
public static void GetDoubles(double[] array, double x = 1.0) { var complex = new Complex[array.Length]; if (array.Length > 0) { complex[0] = Complex.One; } if (array.Length > 1) { complex[1] = x; } if (array.Length > 0) { Fourier(complex, FourierDirection.Forward); complex = complex.Select( value => Complex.Pow(value, array.Length - 1) / array.Length).ToArray(); Fourier(complex, FourierDirection.Backward); } var index = 0; foreach (var value in complex) { array[index++] = value.Real; } }
// this method builds an R(rho, ft) array and then uses FFT to generate R(rho, t) private double[] DetermineROfTimeFromROfFtForFixedRho(double rho, IOpticalPropertyRegion[] regions, out double[] FFTTimeSequence) { // get ops of top tissue region var op0 = regions[0].RegionOP; var fr1 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder1(op0.N); var fr2 = CalculatorToolbox.GetCubicFresnelReflectionMomentOfOrder2(op0.N); var diffusionParameters = GetDiffusionParameters(regions); var layerThicknesses = GetLayerThicknesses(regions); int numFreq = 512; // Kienle used 512 and deltaFreq = 0.1 // Kienle says deltaFrequency depends on source-detector separation var deltaFrequency = 0.1; // 100 MHz if (rho <= 3) { deltaFrequency = 0.5; // so far I've found this value works for smaller rho } var F = numFreq * deltaFrequency; // 51 GHz var deltaTime = 1.0 / (numFreq * deltaFrequency); // 0.02 ns => T = 10 ns // var homoSDA = new PointSourceSDAForwardSolver(); // debug with h**o SDA // var rOfTime = new Complex[numFreq]; // debug array // considerations: 2n datapoint and pad with 0s beyond (deltaTime * numFreq) var rOfFt = new Complex[numFreq]; double[] ft = Enumerable.Range(0, numFreq).Select(x => x * deltaFrequency).ToArray(); FFTTimeSequence = Enumerable.Range(0, numFreq).Select(x => x * deltaTime).ToArray(); for (int i = 0; i < numFreq; i++) { // normalize by F=(numFreq*deltaFrequency) rOfFt[i] = TemporalFrequencyReflectance(rho, ft[i], diffusionParameters, layerThicknesses, fr1, fr2) * F; // rOfTime[i] = homoSDA.ROfRhoAndTime(regions[1].RegionOP, rho, t[i]); // debug array } // to debug, use R(t) and FFT to see if result R(ft) is close to rOfFt //var dft2 = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform(); //dft2.Radix2Forward(rOfTime, FourierOptions.NoScaling); // convert to R(ft) to compare with rOfFt //var relDiffReal = Enumerable.Zip(rOfTime, rOfFt, (x, y) => Math.Abs((y.Real - x.Real) / x.Real)); //var relDiffImag = Enumerable.Zip(rOfTime, rOfFt, (x, y) => Math.Abs((y.Imaginary - x.Imaginary) / x.Imaginary)); //var maxReal = relDiffReal.Max(); //var maxImag = relDiffImag.Max(); //var dum1 = maxReal; //var dum2 = maxImag; //dft2.Inverse(rOfTime, FourierOptions.NoScaling); // debug convert to R(t) // end debug code // FFT R(ft) to R(t) //var dft = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform(); //dft.Inverse(rOfFt, FourierOptions.NoScaling); // convert to R(t) Fourier.Inverse(rOfFt, FourierOptions.NoScaling); var rOfTime = new double[FFTTimeSequence.Length]; rOfTime = rOfFt.Select(r => r.Real / (numFreq / 2)).ToArray(); return(rOfTime); }
public void TestJenkinsTraub5() { var coeff = new Complex[] { 5, -20, 5, 50, -20, -40 }; var expectedRoots = new Number[] { -1, -1, 2, 2, 2.0 }; var roots = KtPolynomial.Create(coeff.Select(elem => (Number)elem).Reverse().ToArray()).Roots(); Assert.AreEqual(expectedRoots.Length, roots.Length); Assert.IsTrue(SequenceEqual(roots.ToArray(), expectedRoots)); Assert.IsTrue(ContentEqual(roots.ToArray(), expectedRoots)); }
public void TestDft() { var dft = new Complex[] { 2, 3, 5, 7, -3, -2, -5, -11 } .Dft(); Assert.AreEqual( "-4.00+0.00i | -4.19-26.26i | -1.00-5.00i | 14.19-6.26i | 2.00+0.00i | 14.19+6.26i | -1.00+5.00i | -4.19+26.26i", string.Join(" | ", dft.Select(TestExtensions.FormatComplex("f2"))), "Approximate Values"); }
/// <summary> /// Method for converting zeros(poles) to TF numerator(denominator) /// </summary> /// <param name="zp"></param> /// <returns></returns> public static double[] ZpToTf(ComplexDiscreteSignal zp) { var poly = new Complex[] { 1, new Complex(-zp.Real[0], -zp.Imag[0]) }; for (var k = 1; k < zp.Length; k++) { var poly1 = new Complex[] { 1, new Complex(-zp.Real[k], -zp.Imag[k]) }; poly = MathUtils.MultiplyPolynomials(poly, poly1); } return(poly.Select(p => p.Real).ToArray()); }
/// <summary> /// Method for converting zeros(poles) to TF numerator(denominator) /// </summary> /// <param name="zp"></param> /// <returns></returns> public static double[] ZpToTf(Complex[] zp) { var poly = new Complex[] { 1, -zp[0] }; for (var k = 1; k < zp.Length; k++) { var poly1 = new Complex[] { 1, -zp[k] }; poly = MathUtils.MultiplyPolynomials(poly, poly1); } return(poly.Select(p => p.Real).ToArray()); }
private void CopyFFTToFrameColumn(Complex[] fftResults) { var maxReal = fftResults.Select(c => 20 * Math.Log10(Math.Abs(c.Magnitude))).Max(); var minReal = fftResults.Select(c => 20 * Math.Log10(Math.Abs(c.Magnitude))).Min(); for (int i = 0; i < _fftSize; i++) { var value = fftResults[i].Magnitude; var logValue = 20 * Math.Log10(Math.Abs(value)); uint ushortedValue = (uint)(maxValue * (logValue - minReal) / (maxReal - minReal)); uint colorB = ushortedValue * _maxColor[2] + (1-ushortedValue)* _minColor[2]; uint colorG = ushortedValue * _maxColor[1] + (1-ushortedValue)* _minColor[1]; uint colorR = ushortedValue * _maxColor[0] + (1-ushortedValue)* _minColor[0]; uint uintValue = 0x000000FF; uintValue = uintValue | (colorR << 8); uintValue = uintValue | (colorG << 16); uintValue = uintValue | (colorB << 24); _spectrogramData[(_fftSize - i - 1) * _numberOfFramesPerImage + _currentFrame] = (uintValue); } }
public void GetPower() { int count = WINDOW_SIZE / FLOAT_SIZE; complex = new Complex[count]; real = new double[count]; imag = new double[count]; for (int i = 0; i < WINDOW_SIZE; i += 4) { //audioStream.Read(buffer, 0, FLOAT_SIZE); complex[i] = (Complex)BitConverter.ToSingle(window, i); } Fourier.FFT(complex, count, FourierDirection.Forward); real = complex.Select(c => Math.Pow(c.Re, 2)).ToArray(); imag = complex.Select(c => Math.Pow(c.Im, 2)).ToArray(); audioStream.Position -= (WINDOW_SIZE - WINDOW_SHIFT_SIZE); audioStream.Read(window, 0, WINDOW_SIZE); }
public void TestJenkinsTraub2() { var coeff = new Complex[] { 1, -3, -2, 6 }; Number[] expectedRoots = { Round(Sqrt(2), 9), -Round(Sqrt(2), 9), 3 }; var roots = KtPolynomial.Create(coeff.Select(elem => (Number)elem).Reverse().ToArray()).Roots(); Assert.AreEqual(expectedRoots.Length, roots.Length); Assert.IsTrue(roots.Contains(expectedRoots[0])); Assert.IsTrue(roots.All(expectedRoots.Contains)); Assert.IsTrue(expectedRoots.All(roots.Contains)); Assert.IsTrue(ContentEqual(roots.ToArray(), expectedRoots)); }
public static double[] FFT(double[] data) { double[] fft; // = new double[data.Length]; // this is where we will store the output (fft) if (data.Length >= 16384) { var size = Math.Ceiling(data.Length / 16384m) * 16384; fft = ArrayLeftPad(data, 0, (int)size); } else { fft = ArrayLeftPad(data, 0, 16384); } Complex[] fftComplex = new Complex[fft.Length]; // the FFT function requires complex format for (int i = 0; i < fft.Length; i++) { fftComplex[i] = new Complex(fft[i], 0.0); // make it complex format (imaginary = 0) } if (data.Length > 16384) { int pageNumber = 1; var queryResultPage = fftComplex .Skip(16384 * pageNumber) .Take(16384); while (queryResultPage != null && queryResultPage.Any()) { Accord.Math.FourierTransform.FFT(queryResultPage.ToArray(), Accord.Math.FourierTransform.Direction.Forward); pageNumber++; queryResultPage = fftComplex .Skip(16384 * pageNumber) .Take(16384); } } else { Accord.Math.FourierTransform.FFT(fftComplex, Accord.Math.FourierTransform.Direction.Forward); } //for (int i = 0; i < data.Length; i++) //{ // fft[i] = fftComplex[i].Magnitude; // back to double // //fft[i] = Math.Log10(fft[i]); // convert to dB //} //return fft; return(fftComplex.Select(x => x.Magnitude).ToArray()); }
public void OperatorSubtractionComplexArrayToComplexTest() { var N = __RndGenerator.Next(10) + 5; var X = new Complex[N].Initialize(i => Rnd); var Y = Rnd; var expected = X.Select(x => x - Y).ToArray(); (X - Y).Foreach((z, i) => { var(re, im) = z; Assert.AreEqual(expected[i].Re, re, 1e-15); Assert.AreEqual(expected[i].Im, im, 1e-15); }); }
public void GetRoots_ComplexTestCaseData_ZeroFunctionValue(Complex absoluteCoefficient, Complex firstOrderCoefficient, Complex secondOrderCoefficient, Complex thirdOrderCoefficient) { Complex[] roots = new Complex[3]; int rootCount = Polynomial.RootFinder.Analytical.GetRoots(absoluteCoefficient, firstOrderCoefficient, secondOrderCoefficient, thirdOrderCoefficient, out roots[0], out roots[1], out roots[2]); Assert.That(rootCount, Is.GreaterThan(0), "No root found for the specified polynomial!"); var polynomial = Polynomial.Complex.Create(absoluteCoefficient, firstOrderCoefficient, secondOrderCoefficient, thirdOrderCoefficient); var functionValues = roots.Select(z => polynomial.GetValue(z)).ToArray(); for (int j = 0; j < rootCount; j++) { Assert.That(Complex.Abs(functionValues[j]), Is.EqualTo(0.0).Within(1E-8)); } }
/// <summary> /// Maximum of the absolute value of all Eigenvalues of <paramref name="H"/>. /// </summary> static public double EigenScheisse(double[,] H) { var linalg = new ManagedLinearAlgebraProvider(); double Eigen; int N = H.GetLength(0); double[] Matrix = H.Resize(false); double[] EigenVect = new double[Matrix.Length]; double[] diagM = new double[Matrix.Length]; Complex[] EigenValues = new Complex[N]; linalg.EigenDecomp(false, N, Matrix, EigenVect, EigenValues, diagM); Eigen = EigenValues.Select(ev => Complex.Abs(ev)).Max(); return(Eigen); }
public void TestInverseDft() { Complex i = Complex.ImaginaryOne; var invDft = new Complex[] { -4, -4.19 - 26.26 * i, -1 - 5 * i, 14.19 - 6.26 * i, 2, 14.19 + 6.26 * i, -1 + 5 * i, -4.19 + 26.26 * i } .InverseDft(); var expect = new Complex[] { 2, 3, 5, 7, -3, -2, -5, -11 }; var err = invDft.GetError(expect); Assert.Less(err, 1e-2, string.Concat( $"{err} error : ", string.Join(" | ", invDft.Select(TestExtensions.FormatComplex("f2"))), " != ", string.Join(" | ", expect.Select(TestExtensions.FormatComplex("f2"))))); }
public FrequencyChart AnalyzeSound(Complex[] sound, int offset) { var sample = new Complex[window.Length]; Array.Copy(sound, offset, sample, 0, window.Length); Fourier.Radix2Forward(sample, FourierOptions.Default); var chart = new FrequencyChart( sample.Select(k => k.Magnitude * 2 / (sample.Length)) .Zip(frqs, (a, f) => new FrequencyPair(f, a)) .Where(k => k.Frequency > 0) .ToArray()); return(chart); }
public static void GetDoubles(double[] array, double x = 1.0) { var complex = new Complex[array.Length]; if (array.Length > 0) complex[0] = Complex.One; if (array.Length > 1) complex[1] = x; if (array.Length > 0) { Fourier(complex, FourierDirection.Forward); complex = complex.Select( value => Complex.Pow(value, array.Length - 1)/array.Length).ToArray(); Fourier(complex, FourierDirection.Backward); } var index = 0; foreach (var value in complex) array[index++] = value.Real; }
/// <summary> /// Calculate function self-convolution values /// </summary> /// <param name="f">Function values</param> /// <returns></returns> public double[] Build(double[] f) { int length = (_functionType == FunctionType.Periodic) ? f.Length : (f.Length + f.Length - 1); var input = new fftw_complexarray(length); var output = new fftw_complexarray(length); fftw_plan forward = fftw_plan.dft_1d(length, input, output, fftw_direction.Forward, fftw_flags.Estimate); fftw_plan backward = fftw_plan.dft_1d(length, input, output, fftw_direction.Backward, fftw_flags.Estimate); var complex = new Complex[length]; for (int i = 0; i < f.Length; i++) complex[i] = f[i]; input.SetData(complex); forward.Execute(); complex = output.GetData_Complex(); input.SetData(complex.Select(x => x*x/length).ToArray()); backward.Execute(); complex = output.GetData_Complex(); return complex.Select(x => x.Magnitude).ToArray(); }
/// <summary> /// 快速傅里叶变换 /// </summary> /// <param name="w">频域横坐标</param> /// <param name="F">系统时域函数</param> /// <param name="startTime">采样开始时间</param> /// <param name="endTime">采样结束时间</param> /// <param name="N">采样点数</param> /// <returns>频域对应值</returns> public static Complex FFT(double w, System.Func <double, double> F, double startTime, double endTime, int N) { if (endTime > startTime) //数据合法性校验 { double T = (endTime - startTime) / N; //采样周期 //求最接近的2的幂 int SequenceNumber = (int)Math.Pow(2, Math.Ceiling(Math.Log(N) / Math.Log(2))); Complex[] Data = new Complex[SequenceNumber]; Data.Initialize(); //如果这一次的和上次的数据不一样,那就重新FFT if (startTime != boostFFTStartTime || endTime != boostFFTEndTime || N != boostFFTN || F != boostFFTFt) { //生成采样数据 for (int i = 0; i < N; i++) { Data[i] = new Complex(F(i * T + startTime), 0); } //FFT采样数据 Data = SubFFT(Data, false); Data = Data.Select((x) => x * 2 / SequenceNumber).ToArray(); Data = FFTShift(Data); //保存这一次的,为了加速计算 boostFFTStartTime = startTime; boostFFTEndTime = endTime; boostFFTN = N; boostFFTFt = F; boostFFTData = Data; } else { Data = boostFFTData; } //f=采样频率/2*(-1+2/SequenceNumber*n) int n = (int)(SequenceNumber * (2 * w * T + 1)) / 2 - 1; if (n < Data.Length && n >= 0) { return(Data[n]); } else { return(0); } } else { throw new Exception("数据上界小于下界"); } }
private static TableInfo ConvertTable(float[][] wavetable, Dictionary <int, int> noteToPartials) { var partials = noteToPartials.Select(x => x.Value).Distinct().OrderByDescending(x => x).ToList(); var transform = new Transform(wavetable.First().Length); var output = new TableInfo(); output.MidiToTable = new int[128]; output.RenderedTable = new float[partials.Count][][]; Action <int, Complex[]> LimitPartials = (max, data) => { for (int i = 0; i < data.Length; i++) { if (i > max && (data.Length - i) > max) { data[i].Real = 0; data[i].Imag = 0; } } }; for (int partialIndex = 0; partialIndex < partials.Count; partialIndex++) { var partial = partials[partialIndex]; noteToPartials.Where(x => x.Value == partial).Select(x => x.Key).Foreach(x => output.MidiToTable[x] = partialIndex); output.RenderedTable[partialIndex] = new float[wavetable.Length][]; for (int tableIndex = 0; tableIndex < wavetable.Length; tableIndex++) { var table = wavetable[tableIndex]; var input = table.Select(x => new Complex(x, 0)).ToArray(); var fft = new Complex[input.Length]; var ifft = new Complex[input.Length]; transform.FFT(input, fft); LimitPartials(partial, fft); transform.IFFT(fft, ifft); var signal = ifft.Select(x => (float)x.Real).ToArray(); output.RenderedTable[partialIndex][tableIndex] = signal; } } return(output); }
public static float[] FilterPerFrameFreq(float[] frame, Complex[] filterAfterFFT) { Complex[] dataFFT = frame.Select(v => new Complex(v, 0)).ToArray(); dataFFT = Audio.Classes.AudioHelper.FFT(dataFFT, true); Complex[] result = new Complex[frame.Length]; for (int i = 0; i < result.Length; i++) { result[i] = dataFFT[i] * filterAfterFFT[i]; } result = Audio.Classes.AudioHelper.FFT(result, false); float[] resultF = result.Select(r => (float)r.Real).ToArray(); return(resultF); }
/// <summary> /// frekvencia-amplitudó értékeket számol a mintából, /// a mintavételezést istart-nál kezdi /// a kimenő vektor i-edik eleme i * freqStep frekvenciához tartozó amplitudóértéket tartalmazza, /// a 0. elem a DC egyenáramhoz tartozik, ez pl 128 lehet akkor ha a minta 128 körül oszcillál /// </summary> public static double[] RgampFromSample <T>(IList <T> rgsample, int istart, int freqStep, Func <T, Complex> dgToComplex, int freqSample = 44100) { var size = DftBlockSize(freqSample, freqStep); var rgcplxSample = new Complex[size]; for (int i = 0; i < size; i++) { rgcplxSample[i] = dgToComplex(rgsample[istart + i]); } new DiscreteFourierTransform().BluesteinForward(rgcplxSample, FourierOptions.Matlab); //le kell normálni a magnitudót sizeblockkal, hogy az amplitudókat megkapjuk. (ez a FourierOptions.Matlab paraméter miatt van így) var rgamp = rgcplxSample.Select(d => d.Magnitude / size).ToArray(); //csak az alsó felét adjuk vissza return(rgamp.Take(rgamp.Length / 2 - 1).ToArray()); }
/// <summary> /// Make fourier forward and backward - result must be same /// </summary> /// <param name="inSoundData"></param> /// <returns></returns> public List <float[]> DoFourierForthAndBack(List <float[]> inSoundData) { var res = new List <float[]>(); for (int j = 0; j < inSoundData.Count; j++) { var data = inSoundData[j]; var complex = new Complex[data.Length]; for (int i = 0; i < data.Length; i++) { complex[i] = new Complex(data[i], 0); } Fourier.Forward(complex); Fourier.Inverse(complex); res.Add(complex.Select(t => (float)t.Real).ToArray()); } return(res); }
/// <summary> /// Get constant q transformation coefficients /// </summary> /// <param name = "x">Initial signal</param> /// <param name = "sparKernel">Spar kernel</param> /// <returns>Constant q transform</returns> /// <remarks> /// Method rewritten from Matlab implementation /// http://wwwmath.uni-muenster.de/logik/Personen/blankertz/constQ/constQ.html /// </remarks> /* * function cq= constQ(x, sparKernel) % x must be a row vector * cq= fft(x,size(sparKernel,1)) * sparKernel; */ public double[] GetTransform(Complex[] x, Complex[][] sparKernel) { int signalLength = x.Length; int sparLength = sparKernel[0].Length; if (signalLength != sparLength) throw new ArgumentException("x and sparKernel dimensions are not equal"); Fourier.FFT(x, x.Length, FourierDirection.Forward); int logBins = sparKernel.GetLength(0); Complex[] cq = new Complex[logBins]; for (int i = 0; i < logBins; i++) { for (int j = 0; j < signalLength /*2048*/; j++) { cq[i].Re += x[j].Re*sparKernel[i][j].Re - x[j].Im*sparKernel[i][j].Im; cq[i].Im += x[j].Re*sparKernel[i][j].Im + x[j].Im*sparKernel[i][j].Re; } } return cq.Select((item) => 20*Math.Log10(item.GetModulus()/FingerprintManager.HUMAN_AUDITORY_THRESHOLD)).ToArray(); }
/// <summary> /// Generate the room impulse response. /// </summary> /// <param name="room">The room to be simulated.</param> /// <param name="soundSource">The sound source to be simulated.</param> /// <param name="microphone">The microphone to be simulated.</param> /// <param name="sampleRate">The sampling frequency of the impulse response.</param> /// <param name="dftLength">The length of the DFT.</param> /// <returns> /// The simulated impulse response. /// Since the acausal components are discarded, /// the length of the returned array is dftLength / 2. /// </returns> public static double[] GenerateImpulseResponse(Room room, SoundSource soundSource, Microphone microphone, int sampleRate, int dftLength) { if (room == null) { throw new ArgumentNullException(nameof(room)); } if (soundSource == null) { throw new ArgumentNullException(nameof(soundSource)); } if (microphone == null) { throw new ArgumentNullException(nameof(microphone)); } if (sampleRate <= 0) { throw new ArgumentException(nameof(sampleRate), "The sampling frequency must be greater than zero."); } if (dftLength <= 0 || dftLength % 2 != 0) { throw new ArgumentException(nameof(dftLength), "The length of the DFT must be positive and even."); } var response = GenerateFrequencyDomainImpulseResponse(room, soundSource, microphone, sampleRate, dftLength); var timeDomainSignal = new Complex[dftLength]; timeDomainSignal[0] = response[0]; for (var w = 1; w < dftLength / 2; w++) { timeDomainSignal[w] = response[w]; timeDomainSignal[dftLength - w] = response[w].Conjugate(); } timeDomainSignal[dftLength / 2] = response[dftLength / 2]; Fourier.Inverse(timeDomainSignal, FourierOptions.AsymmetricScaling); return(timeDomainSignal.Select(value => value.Real).Take(dftLength / 2).ToArray()); }
public static double[][][] TransformWavetable(double[][] wavetable) { var waveCount = wavetable.Length; var newWavetable = new double[waveCount][][]; if (wavetable.Any(x => x.Length != WaveSize)) { throw new Exception("Wave length must be " + WaveSize); } var trans = new TransformNative(WaveSize); for (var w = 0; w < waveCount; w++) { newWavetable[w] = new double[PartialsTableCount][]; var baseWave = wavetable[w]; var complexIn = baseWave.Select(x => new Complex(x, 0)).ToArray(); var fft = new Complex[complexIn.Length]; var ifft = new Complex[fft.Length]; trans.FFT(complexIn, fft); for (var i = 0; i < PartialsTableCount; i++) { var partials = PartialsPerWave[i]; for (var n = partials + 1; n < fft.Length - partials; n++) { fft[n].Real = 0; fft[n].Imag = 0; } trans.IFFT(fft, ifft); newWavetable[w][i] = ifft.Select(x => x.Real).ToArray(); } } return(newWavetable); }
public ActionResult fft1(string[] json) { Complex[] data = new Complex[json.Length]; Complex[] fft = new Complex[json.Length]; for (int i = 0; i < json.Length; i++) { var com = this.ParceCom(json[i]); data[i] = com; } Array.Copy(data, fft, data.Length); FourierTransform.DFT(data, FourierTransform.Direction.Backward); var result = new { time = data.Select(d => new { real = d.Re, imag = d.Im }).ToArray(), fft = fft.Select(d => new { real = d.Re, imag = d.Im }).ToArray() }; return(Json(result)); }
/// <summary> /// Resize bitmap with the Fastest Fourier Transform /// </summary> /// <returns>Resized bitmap</returns> public double[,,] Stretch(double[,,] imageData) { int length = imageData.Length; int n0 = imageData.GetLength(0); int n1 = imageData.GetLength(1); int n2 = imageData.GetLength(2); var doubles = new double[length]; Buffer.BlockCopy(imageData, 0, doubles, 0, length*sizeof (double)); double average; double delta; AverageAndDelta(out average, out delta, doubles, _keepOption); Size newSize = _filterSize; switch (_filterMode) { case FilterMode.FilterSize: break; case FilterMode.FilterStep: int filterStep = _filterStep; newSize = new Size(MulDiv(n1, filterStep + filterStep + 1, filterStep + filterStep), MulDiv(n0, filterStep + filterStep + 1, filterStep + filterStep)); break; default: throw new NotImplementedException(); } var imageData2 = new double[newSize.Height, newSize.Width, n2]; int length2 = imageData2.Length; int m0 = imageData2.GetLength(0); int m1 = imageData2.GetLength(1); int m2 = imageData2.GetLength(2); Complex[] complex = doubles.Select(x => new Complex(x, 0)).ToArray(); var complex2 = new Complex[length2]; Fourier(n0, n1, n2, complex, FourierDirection.Forward); Copy(n0, n1, m0, m1, complex, complex2, n2); Fourier(m0, m1, m2, complex2, FourierDirection.Backward); doubles = complex2.Select(x => x.Magnitude).ToArray(); double average2; double delta2; AverageAndDelta(out average2, out delta2, doubles, _keepOption); // a*average2 + b == average // a*delta2 == delta double a = (_keepOption == KeepOption.AverageAndDelta) ? (delta/delta2) : (average/average2); double b = (_keepOption == KeepOption.AverageAndDelta) ? (average - a*average2) : 0; Debug.Assert(Math.Abs(a*average2 + b - average) < 0.1); doubles = doubles.Select(x => Math.Round(a*x + b)).ToArray(); Buffer.BlockCopy(doubles, 0, imageData2, 0, length2*sizeof (double)); return imageData2; }
/// <summary> /// Set the channel properties /// </summary> /// <param name="channel"></param> public static void SetChannel(Dict channel) { // validate channel's properties var data = new Complex[BlocksPerSymbol]; foreach(var curr in channel.Keys()) { int index; double value; if (!int.TryParse(curr, out index)) throw new Exception(String.Format("Channel quality indexes must be integers. '{0}' is not a valid integer!", curr)); if (index >= data.Length) throw new Exception("Key exceeds array length"); if (!double.TryParse(channel.Get(curr), out value)) throw new Exception(String.Format("Channel quality values must be floats. '{0}' is not a valid float!", curr)); data[index] = new Complex(value, 0); } // reverse-transform to get SNRs var fft = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform(); fft.BluesteinInverse(data, MathNet.Numerics.IntegralTransforms.FourierOptions.Default); ChannelQuality = data.Select(p => p.Magnitude).ToArray(); }
public static string ComplexArrToString(Complex[] complexarr) { string value = String.Join(",", complexarr.Select(i => i.ToString()).ToArray()); return value; }
public override void CalculateTransmissionLoss(Platform platform, Mode mode, Radial radial, BottomProfile bottomProfile, SedimentType sedimentType, double windSpeed, IList<Tuple<double, SoundSpeedProfile>> soundSpeedProfilesAlongRadial) { var sourceDepth = platform.Depth; var frequency = (float)Math.Sqrt(mode.HighFrequency * mode.LowFrequency); if (mode.Depth.HasValue) sourceDepth += mode.Depth.Value; var directoryPath = Path.GetDirectoryName(radial.BasePath); if (directoryPath == null) throw new NullReferenceException("radial.BasePath does not point to a valid directory"); if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); // Derived Parameters // ================== // Note: All the specific calculations given in the comments below assume a frequency of 1kHz // lambda is wavelength, in meters var lambda = ReferenceSoundSpeed / frequency; // if dz < 1m round dz down to either [1/10, 1/5, 1/4 or 1/2] m ... or multiples of 10^-n of these numbers // = [1 2 2.5 or 5 ] x 0.1m " " ... // if dz > 1m round dz down to either [1 2 2.5 5 ] m ... or multiples of 10^+n of these numbers // var fixpoints = new List<double> { 1, 2, 2.5, 5 }; // dz = 0.1 * lambda var dz = RelativeDepthResolution * lambda; // make dz a 'pretty' number //dz = Fix2X10pN(dz, fixpoints); // ndz is the depth decimation factor // MinimumOutputDepthResolution is 10m // dz is 0.1 * lambda (dz = 0.15 for a 1 kHz signal, 'pretty' dz = 0.2 @ 1kHz) // so ndz = (10 / 0.2) = 50 @ 1kHz // this means that we will only output every 50 computational depth cells, giving us a depth // resolution of 50 * 0.2m = 10m @ 1kHz which is what we want it to be. Outstanding. var ndz = (int)Math.Max(1.0, Math.Floor(MinimumOutputDepthResolution / dz)); // similar for dr and assoc. grid decimation // RelativeRangeResolution is 2, so with our 'pretty' dz = 0.2, dr = 0.4 var dr = RelativeRangeResolution * dz; // make dr a 'pretty' number, in this case 0.25 //dr = Fix2X10pN(dr, fixpoints); // ndr is the range decimation factor // MinimumOutputRangeResolution is 10m // dr is 0.25 * lambda, so (10 / 0.25) gives us an ndr of 40 // this means that we will only output every 40 computational range cells, giving us a range // resolution of 40 * 0.25m = 10m @ 1kHz which is what we want it to be. Outstanding. var ndr = (int)Math.Max(1, Math.Floor(MinimumOutputRangeResolution / dr)); // attenuation layer (round up to nearest dz) var sedimentLambda = sedimentType.CompressionWaveSpeed / frequency; var sedimentLayerDz = Math.Ceiling(LastLayerThickness * sedimentLambda / dz) * dz; var attenuationLayerDz = Math.Ceiling(AttenuationLayerThickness * sedimentLambda / dz) * dz; var maxSubstrateDepth = bottomProfile.MaxDepth + sedimentLayerDz; var zstep = dz * ndz; var zmplt = Math.Ceiling((bottomProfile.MaxDepth + 2 * zstep) / zstep) * zstep; // Maximum Depth for PE calc -> zmax // zmax is the z-limit for the PE calc from top of the water column to the bottom of the last substrate layer // (including the attentuation layer if, as recommended, this is included) var zmax = maxSubstrateDepth + attenuationLayerDz; var envFileName = radial.BasePath + ".env"; //Debug.WriteLine("Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}, zmplt: {4}", // radial.TransmissionLoss.AnalysisPoint.Scenario.Name, // radial.TransmissionLoss.AnalysisPoint.Geo, // radial.TransmissionLoss.Modes[0].ModeName, // radial.Bearing, zmplt); using (var envFile = new StreamWriter(envFileName, false)) { envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}", radial.TransmissionLoss.AnalysisPoint.Scenario.Name, radial.TransmissionLoss.AnalysisPoint.Geo, radial.TransmissionLoss.Modes[0].ModeName, radial.Bearing)); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2:0.000000}\t\tf [Frequency (Hz)], zs [Source Depth (m)], zrec0 [First receiever depth (m)]", frequency, sourceDepth, 0.1)); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2}\t\t\trmax[Max range (m)], dr [Range resolution (m)], ndr [Range grid decimation factor]", mode.MaxPropagationRadius + (dr * ndr), dr, ndr)); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2}\t{3:0.000000}\tzmax [Max computational depth (m)], dz [Depth resolution (m)], ndz [Depth grid decimation factor], zmplot [Maximum depth to plot (m)]", zmax, dz, ndz, zmplt)); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1}\t{2}\t{3:0.000000}\t\tc0 [Reference sound speed (m/s)], np [Number of terms in Padé expansion], ns [Number of stability constraints], rs [Maximum range of stability constraints (m)]", ReferenceSoundSpeed, PadeExpansionTerms, StabilityConstraints, StabilityConstraintMaxRange)); // todo: different stuff goes here for RAMSGeo // bathymetry data var first = true; foreach (var profilePoint in bottomProfile.Profile) { envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}{2}", profilePoint.Range * 1000, profilePoint.Depth, first ? "\t\t\t\t\tbathymetry data [range (m), depth (m)]" : "")); first = false; } envFile.WriteLine("-1\t-1"); // range-dependent environment profiles var firstRangeProfile = true; foreach (var rangeProfileTuple in soundSpeedProfilesAlongRadial) { // Range of profile only written for second and subsequent profiles if (!firstRangeProfile) envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.#}\t\t\t\t\t\t\tProfile range (m)", rangeProfileTuple.Item1 * 1000)); var firstSoundSpeedProfile = true; foreach (var profilePoint in rangeProfileTuple.Item2.Data) { if (double.IsNaN(profilePoint.SoundSpeed)) break; envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}{2}", profilePoint.Depth, profilePoint.SoundSpeed, firstSoundSpeedProfile ? "\t\t\t\t\tsound speed profile in water [depth (m), sound speed (m/s)]" : "")); firstSoundSpeedProfile = false; } envFile.WriteLine("-1\t-1"); // todo: RAMGeo and RAMSGeo also support sediment layers, as well as range-dependent sediment, neither of which is not yet supported by ESME // If sediment layers are ever supported, put a loop like for the sound speed profile above // A sediment layer is analogous to a sound speed profile point // For range-dependent sediment, the sediment samples have to be at the same ranges as the sound speed profiles // so we might want to change the API to include sediment properties in what is the current range and sound speed profile tuple envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tcompressive sound speed profile in substrate [depth (m), sound speed (m/s)]", 0.0, sedimentType.CompressionWaveSpeed)); envFile.WriteLine("-1\t-1"); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tdensity profile in substrate [depth (m), rhob (g/cm³)]", 0.0, sedimentType.Density)); envFile.WriteLine("-1\t-1"); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tcompressive attenuation profile in substrate [depth (m), attnp (db/lambda)]", 0.0, 0.0)); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}", attenuationLayerDz, 40)); envFile.WriteLine("-1\t-1"); firstRangeProfile = false; } } var tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(envFileName)); //Debug.WriteLine(string.Format("Env File: {0} temp path: {1}", envFileName, tempDirectory)); if (Directory.Exists(tempDirectory)) { var files = Directory.GetFiles(tempDirectory, "*.*"); foreach (var file in files) File.Delete(file); Directory.Delete(tempDirectory, true); } else if (File.Exists(tempDirectory)) File.Delete(tempDirectory); Directory.CreateDirectory(tempDirectory); File.Copy(envFileName, Path.Combine(tempDirectory, "ramgeo.in")); using (var steerableArrayFile = new StreamWriter(Path.Combine(tempDirectory, "sra.in"), false)) { // From http://www.activefrance.com/Antennas/Introduction%20to%20Phased%20Array%20Design.pdf // theta3 = 3dB beam width, in degrees // emitterSize = size of emitter array, in meters // theta3 = (0.886 * lambda / arrayLength) * 180 / pi // so, doing the algebra and solving for arrayLength, you get: // emitterSize = (0.886 * lambda) / (theta3 * (pi / 180)) var emitterSize = (0.886 * lambda) / (mode.VerticalBeamWidth * (Math.PI / 180.0)); var emitterCount = (int)(emitterSize / (dz * 2)); var emitterSpacing = 1.0; var weights = new List<double> { 1 }; if (emitterCount > 1) { emitterSpacing = emitterSize / (emitterCount - 1); // chebyshev window calculations for relative emitter strength across the array var discreteFourierTransform = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform(); var r0 = Math.Pow(10, mode.SideLobeAttenuation / 20.0); var n = emitterCount - 1; var a = Complex.Cosh((1.0 / n) * Acosh(r0)); var am = new Complex[n]; for (var m = 0; m < n; m++) am[m] = a * Complex.Cos(Math.PI * m / n); var wm = new Complex[n]; var sign = 1; for (var i = 0; i < n; i++) { if (am[i].Magnitude > 1) wm[i] = sign * Complex.Cosh(n * Acosh(am[i])); else wm[i] = sign * Complex.Cos(n * Complex.Acos(am[i])); sign *= -1; } discreteFourierTransform.BluesteinInverse(wm, FourierOptions.Default); weights = wm.Select(e => e.Real).ToList(); weights[0] /= 2; weights.Add(weights[0]); var maxWeight = weights.Max(); for (var i = 0; i < weights.Count; i++) weights[i] /= maxWeight; } steerableArrayFile.WriteLine("{0}\t{1}\t{2}", emitterCount, emitterSpacing, mode.DepressionElevationAngle); for (var i = 0; i < emitterCount; i++) steerableArrayFile.WriteLine("{0}", weights[i]); } //File.Copy(Path.Combine(AssemblyLocation, "sra.in"), Path.Combine(tempDirectory, "sra.in")); //Debug.WriteLine(string.Format("Env File: {0} copied to: {1}", envFileName, tempDirectory)); // Now that we've got the files ready to go, we can launch bellhop to do the actual calculations var ramProcess = new Process { StartInfo = new ProcessStartInfo(Path.Combine(AssemblyLocation, "RAMGeo.exe")) { CreateNoWindow = true, UseShellExecute = false, RedirectStandardInput = false, RedirectStandardOutput = true, RedirectStandardError = true, WorkingDirectory = tempDirectory } }; if (radial.IsDeleted) throw new RadialDeletedByUserException(); ramProcess.Start(); try { ramProcess.PriorityClass = ProcessPriorityClass.Idle; } catch (InvalidOperationException) { } //ramProcess.BeginOutputReadLine(); while (!ramProcess.HasExited) { if (radial.IsDeleted) { ramProcess.Kill(); throw new RadialDeletedByUserException(); } Thread.Sleep(20); } var ramOutput = ramProcess.StandardOutput.ReadToEnd(); var ramError = ramProcess.StandardError.ReadToEnd(); if (ramProcess.ExitCode != 0) { Debug.WriteLine("RAMGeo process for radial {0} exited with error code {1:X}", radial.BasePath, ramProcess.ExitCode); Debug.WriteLine(ramError); Directory.Delete(tempDirectory, true); return; } //File.Delete(Path.Combine(tempDirectory, "ramgeo.in")); //File.Delete(radial.BasePath + ".grid"); //File.Move(Path.Combine(tempDirectory, "tl.grid"), radial.BasePath + ".grid"); //File.Delete(radial.BasePath + ".line"); //File.Move(Path.Combine(tempDirectory, "tl.line"), radial.BasePath + ".line"); //File.Delete(radial.BasePath + ".pgrid"); //File.Move(Path.Combine(tempDirectory, "p.grid"), radial.BasePath + ".pgrid"); //File.Delete(radial.BasePath + ".sra"); //File.Move(Path.Combine(tempDirectory, "sra.in"), radial.BasePath + ".sra"); using (var writer = new StreamWriter(radial.BasePath + ".bty")) writer.Write(bottomProfile.ToBellhopString()); if (File.Exists(Path.Combine(tempDirectory, "p.grid"))) { var pressures = ReadPGrid(Path.Combine(tempDirectory, "p.grid")); File.Copy(Path.Combine(tempDirectory, "p.grid"), radial.BasePath + ".pgrid", true); //File.Delete(radial.BasePath + ".pgrid"); if (pressures.Count == 0) { Debug.WriteLine("Temp directory: " + tempDirectory); Debug.WriteLine("RAMGeo stdout: " + ramOutput); Debug.WriteLine("RAMGeo stderr: " + ramError); Directory.Delete(tempDirectory, true); return; } var rangeCount = pressures.Count; var depthCount = pressures[0].Length; var rr = new double[rangeCount]; var rd = new double[depthCount]; for (var rangeIndex = 0; rangeIndex < rr.Length; rangeIndex++) rr[rangeIndex] = (rangeIndex + 1) * dr * ndr; for (var depthIndex = 0; depthIndex < rd.Length; depthIndex++) rd[depthIndex] = depthIndex * zstep; //Debug.WriteLine("Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}, zmplt: {4}, zstep: {5}, maxDepth: {6}, fileName: {7}, reqDepthCells: {8}, actualDepthCells: {9}", // radial.TransmissionLoss.AnalysisPoint.Scenario.Name, // radial.TransmissionLoss.AnalysisPoint.Geo, // radial.TransmissionLoss.Modes[0].ModeName, // radial.Bearing, // zmplt, // zstep, // rd.Last(), // Path.GetFileNameWithoutExtension(radial.BasePath), // zmplt / zstep, // depthCount); var shadeFile = new ShadeFile(sourceDepth, frequency, rd, rr, pressures); shadeFile.Write(radial.BasePath + ".shd"); //BellhopOutput.WriteShadeFile(radial.BasePath + ".shd", sourceDepth, frequency, rd, rr, pressures); } else { //Debug.WriteLine("Scenario: {0} Analysis point: {1} Mode {2} Bearing {3}", // radial.TransmissionLoss.AnalysisPoint.Scenario.Name, // radial.TransmissionLoss.AnalysisPoint.Geo, // radial.TransmissionLoss.Modes[0].ModeName, // radial.Bearing); //Debug.WriteLine("p.grid file not found in RAMGeo output directory"); } Directory.Delete(tempDirectory, true); //Debug.WriteLine(string.Format("Env File: {0} temp directory deleted: {1}", envFileName, tempDirectory)); }
public static void SaveArrayToFile(string fileName, Complex[] dataToSave) { System.IO.File.WriteAllLines($"{fileName}_X.txt", dataToSave.Select(x => x.Real.ToString()).ToArray()); System.IO.File.WriteAllLines($"{fileName}_Y.txt", dataToSave.Select(x => x.Imaginary.ToString()).ToArray()); }
/// <summary> /// Resize bitmap with the Fastest Fourier Transform /// </summary> /// <returns>Resized bitmap</returns> public Array Stretch(Array imageData) { var length = imageData.Length; var n0 = imageData.GetLength(0); var n1 = imageData.GetLength(1); var n2 = imageData.GetLength(2); var doubles = new double[length]; var handle = GCHandle.Alloc(imageData, GCHandleType.Pinned); Marshal.Copy(handle.AddrOfPinnedObject(), doubles, 0, doubles.Length); handle.Free(); double average; double delta; AverageAndDelta(out average, out delta, doubles, _keepOption); var newSize = _filterSize; switch (_filterMode) { case FilterMode.FilterSize: break; case FilterMode.FilterStep: var filterStep = _filterStep; newSize = new Size(MulDiv(n1, filterStep + filterStep + 1, filterStep + filterStep), MulDiv(n0, filterStep + filterStep + 1, filterStep + filterStep)); break; default: throw new NotImplementedException(); } var imageData2 = new double[newSize.Height, newSize.Width, n2]; var length2 = imageData2.Length; var m0 = imageData2.GetLength(0); var m1 = imageData2.GetLength(1); var m2 = imageData2.GetLength(2); var complex = doubles.Select(x => new Complex(x, 0)).ToArray(); var complex2 = new Complex[length2]; Fourier(n0, n1, n2, complex, FourierDirection.Forward); Copy(n0, n1, m0, m1, complex, complex2, n2); Fourier(m0, m1, m2, complex2, FourierDirection.Backward); doubles = complex2.Select(x => x.Magnitude).ToArray(); double average2; double delta2; AverageAndDelta(out average2, out delta2, doubles, _keepOption); // a*average2 + b == average // a*delta2 == delta var a = (_keepOption == KeepOption.AverageAndDelta) ? (delta/delta2) : (average/average2); var b = (_keepOption == KeepOption.AverageAndDelta) ? (average - a*average2) : 0; Debug.Assert(Math.Abs(a*average2 + b - average) < 0.1); doubles = doubles.Select(x => Math.Round(a*x + b)).ToArray(); handle = GCHandle.Alloc(imageData2, GCHandleType.Pinned); Marshal.Copy(doubles, 0, handle.AddrOfPinnedObject(), doubles.Length); handle.Free(); return imageData2; }