// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // using System; namespace IStation.Numerics { public static class Window { /// /// Hamming window. Named after Richard Hamming. /// Symmetric version, useful e.g. for filter design purposes. /// public static double[] Hamming(int width) { const double a = 0.53836; const double b = -0.46164; double phaseStep = (2.0*Math.PI)/(width - 1.0); var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a + b*Math.Cos(i*phaseStep); } return w; } /// /// Hamming window. Named after Richard Hamming. /// Periodic version, useful e.g. for FFT purposes. /// public static double[] HammingPeriodic(int width) { const double a = 0.53836; const double b = -0.46164; double phaseStep = (2.0*Math.PI)/width; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a + b*Math.Cos(i*phaseStep); } return w; } /// /// Hann window. Named after Julius von Hann. /// Symmetric version, useful e.g. for filter design purposes. /// public static double[] Hann(int width) { double phaseStep = (2.0*Math.PI)/(width - 1.0); var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = 0.5 - 0.5*Math.Cos(i*phaseStep); } return w; } /// /// Hann window. Named after Julius von Hann. /// Periodic version, useful e.g. for FFT purposes. /// public static double[] HannPeriodic(int width) { double phaseStep = (2.0*Math.PI)/width; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = 0.5 - 0.5*Math.Cos(i*phaseStep); } return w; } /// /// Cosine window. /// Symmetric version, useful e.g. for filter design purposes. /// public static double[] Cosine(int width) { double phaseStep = Math.PI/(width - 1.0); var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = Math.Sin(i*phaseStep); } return w; } /// /// Cosine window. /// Periodic version, useful e.g. for FFT purposes. /// public static double[] CosinePeriodic(int width) { double phaseStep = Math.PI/width; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = Math.Sin(i*phaseStep); } return w; } /// /// Lanczos window. /// Symmetric version, useful e.g. for filter design purposes. /// public static double[] Lanczos(int width) { double phaseStep = 2.0/(width - 1.0); var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = Trig.Sinc(i*phaseStep - 1.0); } return w; } /// /// Lanczos window. /// Periodic version, useful e.g. for FFT purposes. /// public static double[] LanczosPeriodic(int width) { double phaseStep = 2.0/width; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = Trig.Sinc(i*phaseStep - 1.0); } return w; } /// /// Gauss window. /// public static double[] Gauss(int width, double sigma) { double a = (width - 1)/2.0; var w = new double[width]; for (int i = 0; i < w.Length; i++) { double exponent = (i - a)/(sigma*a); w[i] = Math.Exp(-0.5*exponent*exponent); } return w; } /// /// Blackman window. /// public static double[] Blackman(int width) { const double alpha = 0.16; const double a = 0.5 - 0.5*alpha; const double b = 0.5*alpha; int last = width - 1; double c = 2.0*Math.PI/last; double d = 2.0*c; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a - 0.5*Math.Cos(i*c) + b*Math.Cos(i*d); } return w; } /// /// Blackman-Harris window. /// public static double[] BlackmanHarris(int width) { const double a = 0.35875; const double b = -0.48829; const double c = 0.14128; const double d = -0.01168; int last = width - 1; double e = 2.0*Math.PI/last; double f = 2.0*e; double g = 3.0*e; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a + b*Math.Cos(e*i) + c*Math.Cos(f*i) + d*Math.Cos(g*i); } return w; } /// /// Blackman-Nuttall window. /// public static double[] BlackmanNuttall(int width) { const double a = 0.3635819; const double b = -0.4891775; const double c = 0.1365995; const double d = -0.0106411; int last = width - 1; double e = 2.0*Math.PI/last; double f = 2.0*e; double g = 3.0*e; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a + b*Math.Cos(e*i) + c*Math.Cos(f*i) + d*Math.Cos(g*i); } return w; } /// /// Bartlett window. /// public static double[] Bartlett(int width) { int last = width - 1; double a = 2.0/last; double b = last/2.0; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a*(b - Math.Abs(i - b)); } return w; } /// /// Bartlett-Hann window. /// public static double[] BartlettHann(int width) { const double a = 0.62; const double b = -0.48; const double c = -0.38; int last = width - 1; double d = 1.0/last; double e = 2.0*Math.PI/last; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a + b*Math.Abs(i*d - 0.5) + c*Math.Cos(i*e); } return w; } /// /// Nuttall window. /// public static double[] Nuttall(int width) { const double a = 0.355768; const double b = -0.487396; const double c = 0.144232; const double d = -0.012604; int last = width - 1; double e = 2.0*Math.PI/last; double f = 2.0*e; double g = 3.0*e; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a + b*Math.Cos(e*i) + c*Math.Cos(f*i) + d*Math.Cos(g*i); } return w; } /// /// Flat top window. /// public static double[] FlatTop(int width) { const double a = 1.0; const double b = -1.93; const double c = 1.29; const double d = -0.388; const double e = 0.032; int last = width - 1; double f = 2.0*Math.PI/last; double g = 2.0*f; double h = 3.0*f; double k = 4.0*f; double[] w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a + b*Math.Cos(f*i) + c*Math.Cos(g*i) + d*Math.Cos(h*i) + e*Math.Cos(k*i); } return w; } /// /// Uniform rectangular (Dirichlet) window. /// public static double[] Dirichlet(int width) { var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = 1.0; } return w; } /// /// Triangular window. /// public static double[] Triangular(int width) { double a = 2.0/width; double b = width/2.0; double c = (width - 1)/2.0; var w = new double[width]; for (int i = 0; i < w.Length; i++) { w[i] = a*(b - Math.Abs(i - c)); } return w; } /// /// Tukey tapering window. A rectangular window bounded /// by half a cosine window on each side. /// /// Width of the window /// Fraction of the window occupied by the cosine parts public static double[] Tukey(int width, double r = 0.5) { if (r <= 0) { return Generate.Repeat(width, 1.0); } else if (r >= 1) { return Hann(width); } var w = new double[width]; var period = (width - 1) * r; var step = 2* Math.PI / period; var b1 = (int)Math.Floor((width - 1) * r * 0.5 + 1); var b2 = width - b1; for (var i = 0; i < b1; i++) { w[i] = (1 - Math.Cos(i * step)) * 0.5; } for (var i = b1; i < b2; i++) { w[i] = 1; } for (var i = b2; i < width; i++) { w[i] = w[width-i-1]; } return w; } } }