/// <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); }