-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Savitzky-Golay filtering #4
Comments
@alexreg @cdrnet: I have both a naive C# and a naive F# implementation of the Savitzky-Golay filter using using System;
using MathNet.Numerics.LinearAlgebra;
namespace Filtering
{
/// <summary>
/// <para>Implements a Savitzky-Golay smoothing filter, as found in [1].</para>
/// <para>[1] Sophocles J.Orfanidis. 1995. Introduction to Signal Processing. Prentice-Hall, Inc., Upper Saddle River, NJ, USA.</para>
/// </summary>
public sealed class SavitzkyGolayFilter
{
private readonly int sidePoints;
private Matrix<double> coefficients;
public SavitzkyGolayFilter(int sidePoints, int polynomialOrder)
{
this.sidePoints = sidePoints;
Design(polynomialOrder);
}
/// <summary>
/// Smoothes the input samples.
/// </summary>
/// <param name="samples"></param>
/// <returns></returns>
public double[] Process(double[] samples)
{
int length = samples.Length;
double[] output = new double[length];
int frameSize = (sidePoints << 1) + 1;
double[] frame = new double[frameSize];
Array.Copy(samples, frame, frameSize);
for (int i = 0; i < sidePoints; ++i)
{
output[i] = coefficients.Column(i).DotProduct(Vector<double>.Build.DenseOfArray(frame));
}
for (int n = sidePoints; n < length - sidePoints; ++n)
{
Array.ConstrainedCopy(samples, n - sidePoints, frame, 0, frameSize);
output[n] = coefficients.Column(sidePoints).DotProduct(Vector<double>.Build.DenseOfArray(frame));
}
Array.ConstrainedCopy(samples, length - frameSize, frame, 0, frameSize);
for (int i = 0; i < sidePoints; ++i)
{
output[length - sidePoints + i] = coefficients.Column(sidePoints + 1 + i).DotProduct(Vector<double>.Build.Dense(frame));
}
return output;
}
private void Design(int polynomialOrder)
{
double[,] a = new double[(sidePoints << 1) + 1, polynomialOrder + 1];
for (int m = -sidePoints; m <= sidePoints; ++m)
{
for (int i = 0; i <= polynomialOrder; ++i)
{
a[m + sidePoints, i] = Math.Pow(m, i);
}
}
Matrix<double> s = Matrix<double>.Build.DenseOfArray(a);
coefficients = s.Multiply(s.TransposeThisAndMultiply(s).Inverse()).Multiply(s.Transpose());
}
}
} open MathNet.Numerics.LinearAlgebra
open System
module SavitzkyGolay =
let design polynomialOrder sidePoints =
let width = (sidePoints * 2) + 1
let s =
Array.init width
(fun m ->
Array.init (polynomialOrder + 1) (fun i -> float (pown m i)))
|> matrix
(width,
s.Multiply(s.TransposeThisAndMultiply(s).Inverse())
.Multiply(s.Transpose()))
let apply polynomialOrder sidePoints =
let (width, coefficients) = design polynomialOrder sidePoints
fun (signal : float []) ->
let start =
Array.init (sidePoints + 1)
(fun i ->
coefficients.Column(i)
.DotProduct(vector signal.[..width - 1]))
let end' =
Array.init (sidePoints + 1)
(fun i ->
coefficients.Column(sidePoints + i)
.DotProduct(vector
signal.[Array.length signal
- width..]))
let steady =
Array.init (Array.length signal - (2 * sidePoints + 3))
(fun i ->
coefficients.Column(sidePoints + 1)
.DotProduct(vector
signal.[i..i + 2 * sidePoints]))
Array.concat [| start; steady; end' |] I ported my work from the MATLAB files |
Hello, I am trying to implement the Savitzky-Golay filter but I am having errors on the Process function, can you submit an example on how to use it please?. Thank you!. |
@juancaldone You use the Savitzky-Golay filter with a signal of at least 2n + 1 samples long for a number of side points of the window n and a polynomial order less than n. For example: using System;
using System.Linq;
public class Program
{
public static void Main()
{
var signal = Enumerable.Range(0, 100).Select(x => Math.Sin(x * 0.1));
var random = new Random();
var noise = Enumerable.Range(0, 100).Select(_ => random.NextDouble() * 0.01);
var noisySignal = signal.Zip(noise, (x, y) => x + y).ToArray();
var filteredSignal = new SavitzkyGolayFilter(5, 1).Process(noisySignal);
}
} |
Thank you very much for your prompt response. |
@mettekou are you sure about your C# code ? PS: Except at the second |
@xas Indeed, this is a mistake I made when porting the filter from MATLAB to C#, as MATLAB uses one-based indexing for vectors and matrices. I discovered it myself a couple of months ago and forgot to update this version on GitHub. I have now done so; please find the updated version above. |
Can you add comments to the C# code to understand what are you doing? great work by the way |
@cc4566 Please consult the section on Savitzky-Golay smoothing filters in this freely available book (page 427 to 453) for an in-depth explanation, as my code was ported from that section's MATLAB code. |
Works. Thanks a lot. Is there any plan for 2d implementation? |
@KonradZaremba No, I only use it for signal processing. |
There is a performance penalty here: |
@emanuelhristea No, I got rid of that over a year ago in my own codebase, but I do not update the snippet in this thread every time. @cdrnet A lot of people use this snippet, maybe it is time to finally add it to the library? |
@mettekou Thanks a lot for translating this library from Matlab codes into the C# MathNet version. Do you have any further plan for implementing the Savitzky Golay Derivatives in this code snippet? Thanks a lot |
Hi! @cdrnet: Is there any goal to merge this or provide this filter any other way? |
Did you compare the results with matlab results? I get different |
I compared the results for my implementation with the implementation in LabVIEW, which yields results identical to the implementation in MATLAB. |
Do you plan to implement it at some point? It's one of the most well-known and widely used filters, of course.
The text was updated successfully, but these errors were encountered: