199 lines
8.1 KiB
C#
199 lines
8.1 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace FftSharp
|
|
{
|
|
public enum WindowType
|
|
{
|
|
Bartlett,
|
|
Blackman,
|
|
BlackmanHarris,
|
|
Cosine,
|
|
FlatTop,
|
|
Hamming,
|
|
Hanning,
|
|
Kaiser,
|
|
Rectangular,
|
|
Tukey,
|
|
Welch
|
|
}
|
|
public enum WindowAveragingType
|
|
{
|
|
Averaging,
|
|
PeakHoldMax,
|
|
PeakHoldMin
|
|
}
|
|
public abstract class Window : IWindow
|
|
{
|
|
public abstract string Name { get; }
|
|
|
|
public abstract string Description { get; }
|
|
|
|
public override string ToString() => Name;
|
|
|
|
protected abstract double windowValue(int index, int size);
|
|
public virtual double[] Create(int size, bool normalize = false)
|
|
{
|
|
// save this window so it can be re-used if the next request is the same size
|
|
if (lastWindow.Length == size && lastWindowNormalize == normalize)
|
|
{
|
|
return lastWindow;
|
|
}
|
|
if (size <= 0)
|
|
{
|
|
return new double[0];
|
|
}
|
|
double[] window = new double[size];
|
|
|
|
for (int i = 0; i < size; i++)
|
|
window[i] = windowValue(i, size);
|
|
|
|
if (normalize)
|
|
NormalizeInPlace(window);
|
|
lastWindow = window;
|
|
lastWindowNormalize = normalize;
|
|
return window;
|
|
}
|
|
|
|
protected double[] lastWindow = new double[0];
|
|
protected bool lastWindowNormalize = false;
|
|
|
|
/// <summary>
|
|
/// Multiply the array by this window and return the result as a new array
|
|
/// </summary>
|
|
public double[] Apply(double[] input, bool normalize = false)
|
|
{
|
|
double[] window = Create(input.Length, normalize);
|
|
double[] output = new double[input.Length];
|
|
|
|
Parallel.For(0, input.Length, i => output[i] = input[i] * window[i]);
|
|
return output;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Multiply the array by this window, modifying it in place
|
|
/// </summary>
|
|
public void ApplyInPlace(double[] input, bool normalize = false)
|
|
{
|
|
double[] window = Create(input.Length, normalize);
|
|
|
|
Parallel.For(0, input.Length, i => input[i] = input[i] * window[i]);
|
|
}
|
|
|
|
internal static void NormalizeInPlace(double[] values)
|
|
{
|
|
double sum = 0;
|
|
Parallel.For(0, values.Length, i => sum += values[i]);
|
|
|
|
Parallel.For(0, values.Length, i => values[i] /= sum);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return an array containing all available windows.
|
|
/// Note that all windows returned will use the default constructor, but some
|
|
/// windows have customization options in their constructors if you create them individually.
|
|
/// </summary>
|
|
public static IWindow[] GetWindows()
|
|
{
|
|
return Assembly.GetExecutingAssembly()
|
|
.GetTypes()
|
|
.Where(x => x.IsClass)
|
|
.Where(x => !x.IsAbstract)
|
|
.Where(x => x.GetInterfaces().Contains(typeof(IWindow)))
|
|
.Select(x => (IWindow)Activator.CreateInstance(x))
|
|
.ToArray();
|
|
}
|
|
|
|
public static IWindow GetWindow(WindowType type)
|
|
{
|
|
return GetWindows().First(w => type.ToString() == w.Name);
|
|
}
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Rectangular(int pointCount) => new Windows.Rectangular().Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Hanning(int pointCount) => new Windows.Hanning().Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Hamming(int pointCount) => new Windows.Hanning().Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Blackman(int pointCount) => new Windows.Blackman().Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] BlackmanCustom(int pointCount, double a = .42, double b = .5, double c = .08) => new Windows.Blackman(a, b, c).Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] BlackmanHarris(int pointCount) => new Windows.Blackman(0.42323, 0.49755, 0.07922).Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] FlatTop(int pointCount) => new Windows.FlatTop().Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Bartlett(int pointCount) => new Windows.Bartlett().Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Cosine(int pointCount) => new Windows.Cosine().Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Kaiser(int pointCount, double beta) => new Windows.Kaiser(beta).Create(pointCount);
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static double[] Apply(double[] window, double[] signal)
|
|
{
|
|
if (window.Length != signal.Length)
|
|
throw new ArgumentException("window and signal must be same length");
|
|
|
|
double[] output = new double[window.Length];
|
|
|
|
for (int i = 0; i < signal.Length; i++)
|
|
output[i] = signal[i] * window[i];
|
|
|
|
return output;
|
|
}
|
|
|
|
[Obsolete("This method is obsolete. Create a window in the Windows namespace and interact with its methods.")]
|
|
public static void ApplyInPlace(double[] window, double[] signal)
|
|
{
|
|
if (window.Length != signal.Length)
|
|
throw new ArgumentException("window and signal must be same length");
|
|
|
|
Parallel.For(0, signal.Length, i => signal[i] = signal[i] * window[i]);
|
|
}
|
|
|
|
[Obsolete("Use GetWindows() instead")]
|
|
public static string[] GetWindowNames()
|
|
{
|
|
return typeof(Window)
|
|
.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
|
.Where(x => x.ReturnType.Equals(typeof(double[])))
|
|
.Where(x => x.GetParameters().Length == 1)
|
|
.Where(x => x.GetParameters()[0].ParameterType == typeof(int))
|
|
.Select(x => x.Name)
|
|
.ToArray();
|
|
}
|
|
|
|
[Obsolete("Use GetWindows() and work with the output instead")]
|
|
public static double[] GetWindowByName(string windowName, int pointCount)
|
|
{
|
|
MethodInfo[] windowInfos = typeof(Window)
|
|
.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
|
.Where(x => x.ReturnType.Equals(typeof(double[])))
|
|
.Where(x => x.GetParameters().Length == 1)
|
|
.Where(x => x.GetParameters()[0].ParameterType == typeof(int))
|
|
.Where(x => x.Name == windowName)
|
|
.ToArray();
|
|
|
|
if (windowInfos.Length == 0)
|
|
throw new ArgumentException($"invalid window name: {windowName}");
|
|
|
|
object[] parameters = new object[] { pointCount };
|
|
double[] result = (double[])windowInfos[0].Invoke(null, parameters);
|
|
return result;
|
|
}
|
|
}
|
|
}
|