예제 #1
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="signal"></param>
 /// <returns></returns>
 public static IEnumerable <Complex> ToComplexNumbers(this ComplexDiscreteSignal signal)
 {
     for (var i = 0; i < signal.Length; i++)
     {
         yield return(new Complex(signal.Real[i], signal.Imag[i]));
     }
 }
        /// <summary>
        /// Superimposes signals <paramref name="signal1"/> and <paramref name="signal2"/>.
        /// If sizes are different then the smaller signal is broadcast to fit the size of the larger signal.
        /// </summary>
        /// <param name="signal1">First signal</param>
        /// <param name="signal2">Second signal</param>
        public static ComplexDiscreteSignal Superimpose(this ComplexDiscreteSignal signal1, ComplexDiscreteSignal signal2)
        {
            Guard.AgainstInequality(signal1.SamplingRate, signal2.SamplingRate,
                                    "Sampling rate of signal1", "sampling rate of signal2");

            ComplexDiscreteSignal superimposed;

            if (signal1.Length > signal2.Length)
            {
                superimposed = signal1.Copy();

                for (var i = 0; i < signal2.Length; i++)
                {
                    superimposed.Real[i] += signal2.Real[i];
                    superimposed.Imag[i] += signal2.Imag[i];
                }
            }
            else
            {
                superimposed = signal2.Copy();

                for (var i = 0; i < signal1.Length; i++)
                {
                    superimposed.Real[i] += signal1.Real[i];
                    superimposed.Imag[i] += signal1.Imag[i];
                }
            }

            return(superimposed);
        }
        /// <summary>
        /// Performs the complex division of <paramref name="signal1"/> and <paramref name="signal2"/> (with normalization by length).
        /// </summary>
        /// <param name="signal1">First signal</param>
        /// <param name="signal2">Second signal</param>
        public static ComplexDiscreteSignal Divide(
            this ComplexDiscreteSignal signal1, ComplexDiscreteSignal signal2)
        {
            Guard.AgainstInequality(signal1.SamplingRate, signal2.SamplingRate,
                                    "Sampling rate of signal1", "sampling rate of signal2");

            var length = signal1.Length;

            var real = new double[length];
            var imag = new double[length];

            var real1 = signal1.Real;
            var imag1 = signal1.Imag;
            var real2 = signal2.Real;
            var imag2 = signal2.Imag;

            for (var i = 0; i < length; i++)
            {
                var den = imag1[i] * imag1[i] + imag2[i] * imag2[i];
                real[i] = (real1[i] * real2[i] + imag1[i] * imag2[i]) / den;
                imag[i] = (real2[i] * imag1[i] - imag2[i] * real1[i]) / den;
            }

            return(new ComplexDiscreteSignal(signal1.SamplingRate, real, imag));
        }
        /// <summary>
        /// Method superimposes two signals.
        /// If sizes are different then the smaller signal is broadcasted
        /// to fit the size of the larger signal.
        /// </summary>
        /// <param name="signal1">Object signal</param>
        /// <param name="signal2">Argument signal</param>
        /// <returns></returns>
        public static ComplexDiscreteSignal Superimpose(this ComplexDiscreteSignal signal1, ComplexDiscreteSignal signal2)
        {
            if (signal1.SamplingRate != signal2.SamplingRate)
            {
                throw new ArgumentException("Sampling rates must be the same!");
            }

            ComplexDiscreteSignal superimposed;

            if (signal1.Length > signal2.Length)
            {
                superimposed = signal1.Copy();

                for (var i = 0; i < signal2.Length; i++)
                {
                    superimposed.Real[i] += signal2.Real[i];
                    superimposed.Imag[i] += signal2.Imag[i];
                }
            }
            else
            {
                superimposed = signal2.Copy();

                for (var i = 0; i < signal1.Length; i++)
                {
                    superimposed.Real[i] += signal1.Real[i];
                    superimposed.Imag[i] += signal1.Imag[i];
                }
            }

            return(superimposed);
        }
 /// <summary>
 /// In-place signal amplification by coeff
 /// </summary>
 /// <param name="signal"></param>
 /// <param name="coeff"></param>
 public static void Amplify(this ComplexDiscreteSignal signal, double coeff)
 {
     for (var i = 0; i < signal.Length; i++)
     {
         signal.Real[i] *= coeff;
         signal.Imag[i] *= coeff;
     }
 }
        /// <summary>
        /// In-place signal attenuation by coeff
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="coeff"></param>
        public static void Attenuate(this ComplexDiscreteSignal signal, double coeff)
        {
            if (Math.Abs(coeff) < 1e-10)
            {
                throw new ArgumentException("Attenuation coefficient can't be zero");
            }

            signal.Amplify(1 / coeff);
        }
        /// <summary>
        /// Creates the copy of <paramref name="signal"/> repeated <paramref name="n"/> times.
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="n">Number of times to repeat <paramref name="signal"/></param>
        public static ComplexDiscreteSignal Repeat(this ComplexDiscreteSignal signal, int n)
        {
            Guard.AgainstNonPositive(n, "Number of repeat times");

            return(new ComplexDiscreteSignal(
                       signal.SamplingRate,
                       signal.Real.RepeatArray(n),
                       signal.Imag.RepeatArray(n)));
        }
        /// <summary>
        /// Creates new signal from last <paramref name="n"/> samples of <paramref name="signal"/>.
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="n">Number of samples to copy</param>
        public static ComplexDiscreteSignal Last(this ComplexDiscreteSignal signal, int n)
        {
            Guard.AgainstNonPositive(n, "Number of samples");
            Guard.AgainstExceedance(n, signal.Length, "Number of samples", "signal length");

            return(new ComplexDiscreteSignal(
                       signal.SamplingRate,
                       signal.Real.FastCopyFragment(n, signal.Length - n),
                       signal.Imag.FastCopyFragment(n, signal.Imag.Length - n)));
        }
        /// <summary>
        /// Concatenates <paramref name="signal1"/> and <paramref name="signal2"/>.
        /// </summary>
        /// <param name="signal1">First signal</param>
        /// <param name="signal2">Second signal</param>
        public static ComplexDiscreteSignal Concatenate(this ComplexDiscreteSignal signal1, ComplexDiscreteSignal signal2)
        {
            Guard.AgainstInequality(signal1.SamplingRate, signal2.SamplingRate,
                                    "Sampling rate of signal1", "sampling rate of signal2");

            return(new ComplexDiscreteSignal(
                       signal1.SamplingRate,
                       signal1.Real.MergeWithArray(signal2.Real),
                       signal1.Imag.MergeWithArray(signal2.Imag)));
        }
        /// <summary>
        /// More or less efficient LINQ-less version.
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="sampleCount"></param>
        /// <returns></returns>
        public static ComplexDiscreteSignal Last(this ComplexDiscreteSignal signal, int sampleCount)
        {
            if (sampleCount <= 0 || sampleCount > signal.Length)
            {
                throw new ArgumentException("Number of samples must be positive and must not exceed the signal length!");
            }

            return(new ComplexDiscreteSignal(
                       signal.SamplingRate,
                       signal.Real.FastCopyFragment(sampleCount, signal.Length - sampleCount),
                       signal.Imag.FastCopyFragment(sampleCount, signal.Imag.Length - sampleCount)));
        }
        /// <summary>
        /// Method creates new zero-padded complex discrete signal from the current signal.
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="newLength">The length of a zero-padded signal.
        /// By default array is zero-padded to have length of next power of 2.</param>
        /// <returns>Zero padded complex discrete signal</returns>
        public static ComplexDiscreteSignal ZeroPadded(this ComplexDiscreteSignal signal, int newLength)
        {
            if (newLength <= 0)
            {
                newLength = MathUtils.NextPowerOfTwo(signal.Length);
            }

            return(new ComplexDiscreteSignal(
                       signal.SamplingRate,
                       signal.Real.PadZeros(newLength),
                       signal.Imag.PadZeros(newLength)));
        }
        /// <summary>
        /// Method returns repeated n times copy of the signal
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="times"></param>
        /// <returns></returns>
        public static ComplexDiscreteSignal Repeat(this ComplexDiscreteSignal signal, int times)
        {
            if (times <= 0)
            {
                throw new ArgumentException("Number of repeat times must be at least once");
            }

            return(new ComplexDiscreteSignal(
                       signal.SamplingRate,
                       signal.Real.RepeatArray(times),
                       signal.Imag.RepeatArray(times)));
        }
        /// <summary>
        /// Method concatenates two signals.
        /// </summary>
        /// <param name="signal1"></param>
        /// <param name="signal2"></param>
        /// <returns></returns>
        public static ComplexDiscreteSignal Concatenate(this ComplexDiscreteSignal signal1, ComplexDiscreteSignal signal2)
        {
            if (signal1.SamplingRate != signal2.SamplingRate)
            {
                throw new ArgumentException("Sampling rates must be the same!");
            }

            return(new ComplexDiscreteSignal(
                       signal1.SamplingRate,
                       signal1.Real.MergeWithArray(signal2.Real),
                       signal1.Imag.MergeWithArray(signal2.Imag)));
        }
        /// <summary>
        /// Creates the delayed copy of <paramref name="signal"/>
        /// by shifting it either to the right (positive <paramref name="delay"/>, e.g. Delay(1000))
        /// or to the left (negative <paramref name="delay"/>, e.g. Delay(-1000)).
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="delay">Delay (positive or negative number of delay samples)</param>
        public static ComplexDiscreteSignal Delay(this ComplexDiscreteSignal signal, int delay)
        {
            var length = signal.Length;

            if (delay <= 0)
            {
                delay = -delay;

                Guard.AgainstInvalidRange(delay, length, "Delay", "signal length");

                return(new ComplexDiscreteSignal(
                           signal.SamplingRate,
                           signal.Real.FastCopyFragment(length - delay, delay),
                           signal.Imag.FastCopyFragment(length - delay, delay)));
            }

            return(new ComplexDiscreteSignal(
                       signal.SamplingRate,
                       signal.Real.FastCopyFragment(length, destinationOffset: delay),
                       signal.Imag.FastCopyFragment(length, destinationOffset: delay)));
        }
        /// <summary>
        /// Method performs the complex multiplication of two signals
        /// (with normalization by length)
        /// </summary>
        /// <param name="signal1"></param>
        /// <param name="signal2"></param>
        /// <returns></returns>
        public static ComplexDiscreteSignal Multiply(
            this ComplexDiscreteSignal signal1, ComplexDiscreteSignal signal2)
        {
            var length = signal1.Length;

            var real = new double[length];
            var imag = new double[length];

            var real1 = signal1.Real;
            var imag1 = signal1.Imag;
            var real2 = signal2.Real;
            var imag2 = signal2.Imag;

            for (var i = 0; i < length; i++)
            {
                real[i] = (real1[i] * real2[i] - imag1[i] * imag2[i]);
                imag[i] = (real1[i] * imag2[i] + imag1[i] * real2[i]);
            }

            return(new ComplexDiscreteSignal(signal1.SamplingRate, real, imag));
        }
        /// Method delays the signal
        ///     either by shifting it to the right (positive, e.g. Delay(1000))
        ///         or by shifting it to the left (negative, e.g. Delay(-1000))
        /// <param name="signal"></param>
        /// <param name="delay"></param>
        /// <returns></returns>
        public static ComplexDiscreteSignal Delay(this ComplexDiscreteSignal signal, int delay)
        {
            var length = signal.Length;

            if (delay <= 0)
            {
                delay = -delay;

                if (delay >= length)
                {
                    throw new ArgumentException("Delay can not exceed the length of the signal!");
                }

                return(new ComplexDiscreteSignal(
                           signal.SamplingRate,
                           signal.Real.FastCopyFragment(length - delay, delay),
                           signal.Imag.FastCopyFragment(length - delay, delay)));
            }

            return(new ComplexDiscreteSignal(
                       signal.SamplingRate,
                       signal.Real.FastCopyFragment(length, destinationOffset: delay),
                       signal.Imag.FastCopyFragment(length, destinationOffset: delay)));
        }
        /// <summary>
        /// Attenuates <paramref name="signal"/> by <paramref name="coeff"/> in-place.
        /// </summary>
        /// <param name="signal">Signal</param>
        /// <param name="coeff">Attenuation coefficient</param>
        public static void Attenuate(this ComplexDiscreteSignal signal, double coeff)
        {
            Guard.AgainstNonPositive(coeff, "Attenuation coefficient");

            signal.Amplify(1 / coeff);
        }