Example #1
0
        /// <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);
        }
Example #2
0
        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 });
        }
Example #4
0
        /// <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());
        }
Example #5
0
        /// <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());
        }
Example #6
0
        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));
        }
Example #7
0
        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());
        }
Example #9
0
        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;
            }
        }
Example #10
0
        // 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);
        }
Example #11
0
        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");
        }
Example #13
0
        /// <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());
        }
Example #14
0
        /// <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());
        }
Example #15
0
        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);

              }
        }
Example #16
0
        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);
        }
Example #17
0
        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));
        }
Example #18
0
        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());
        }
Example #19
0
        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);
            });
        }
Example #20
0
        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));
            }
        }
Example #21
0
        /// <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")))));
        }
Example #23
0
        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);
        }
Example #24
0
 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;
 }
Example #25
0
        /// <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();
        }
Example #26
0
 /// <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("数据上界小于下界");
     }
 }
Example #27
0
        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);
        }
Example #28
0
        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);
        }
Example #29
0
        /// <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());
        }
Example #30
0
        /// <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);
        }
Example #31
0
        /// <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();
        }
Example #32
0
        /// <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);
        }
Example #34
0
        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));
        }
Example #35
0
        /// <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;
        }
Example #36
0
        /// <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();
        }
Example #37
0
 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));
        }
Example #39
0
 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());
 }
Example #40
0
        /// <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;
        }