ml-savitzky-golay-generalized
Advanced tools
Comparing version 1.1.1 to 2.0.0
@@ -0,1 +1,10 @@ | ||
# [2.0.0](https://github.com/mljs/savitzky-golay-generalized/compare/v1.1.1...v2.0.0) (2020-02-26) | ||
### Bug Fixes | ||
* spelling ([aa11ca3](https://github.com/mljs/savitzky-golay-generalized/commit/aa11ca304fc307619b1e7f3cb978e68ea4caa9a5)) | ||
<a name="1.1.1"></a> | ||
@@ -2,0 +11,0 @@ ## [1.1.1](https://github.com/mljs/savitzky-golay-generalized/compare/v1.0.4...v1.1.1) (2017-07-24) |
{ | ||
"name": "ml-savitzky-golay-generalized", | ||
"version": "1.1.1", | ||
"version": "2.0.0", | ||
"description": "Savitzky–Golay filter in Javascript", | ||
"main": "src/index.js", | ||
"directories": { | ||
"lib": "src", | ||
"test": "test" | ||
}, | ||
"main": "lib/index.js", | ||
"module": "src/index.js", | ||
"files": [ | ||
"lib", | ||
"src" | ||
], | ||
"scripts": { | ||
"test": "mocha --require should --reporter mocha-better-spec-reporter --recursive" | ||
"eslint": "eslint src", | ||
"eslint-fix": "npm run eslint -- --fix", | ||
"prepublishOnly": "rollup -c", | ||
"test": "npm run test-coverage && npm run eslint", | ||
"test-coverage": "jest --coverage", | ||
"test-only": "jest" | ||
}, | ||
@@ -35,10 +41,14 @@ "repository": { | ||
"devDependencies": { | ||
"mocha": "latest", | ||
"mocha-better-spec-reporter": "latest", | ||
"should": "latest" | ||
"@babel/plugin-transform-modules-commonjs": "^7.8.3", | ||
"@types/jest": "^25.1.3", | ||
"eslint": "^6.8.0", | ||
"eslint-config-cheminfo": "^2.0.4", | ||
"eslint-plugin-import": "^2.20.1", | ||
"eslint-plugin-jest": "^23.8.0", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"jest": "^25.1.0", | ||
"prettier": "^1.19.1", | ||
"rollup": "^1.31.1" | ||
}, | ||
"dependencies": { | ||
"extend": "^3.0.0", | ||
"ml-stat": "^1.3.3" | ||
} | ||
"dependencies": {} | ||
} |
# savitzky-golay-generalized | ||
General Least-Squares Smoothing and Differentiation by the Convolution (Savitzky-Golay) Method Peter A. Gorry | ||
@@ -8,37 +9,50 @@ | ||
I'll try an automatic parameter tunning based on the SNR or in the entropy of the signal. | ||
#Usage | ||
# Usage | ||
```js | ||
npm i ml-savitzky-golay-generalized | ||
const SG = var SG = require("ml-savitzky-golay-generalized"); | ||
const SG = require("ml-savitzky-golay-generalized"); | ||
SG(dataY, deltaX|X, options) | ||
``` | ||
##Parameters | ||
## Parameters | ||
### dataY | ||
The data to be filtered. | ||
###deltaX | X | ||
### deltaX | X | ||
deltaX specifies the difference between 2 consecutive points of the independent: deltaX = X[i+1] - X[i]. Specficiying a deltaX suppose that all your points are equally spaced on the independent variable. | ||
If your points are not equally spaced in the ordinate variable, then you have to provide explicitelly your X values. The algorithm will use the average deltaX within each bin of 'windowSize' points to approximate the derivatives. This fast approximation only works if the X is almost locally equally spaced. | ||
If your points are not equally spaced in the ordinate variable, then you have to provide explicitly your X values. The algorithm will use the average deltaX within each bin of 'windowSize' points to approximate the derivatives. This fast approximation only works if the X is almost locally equally spaced. | ||
###options | ||
####windowSize: | ||
The odd number of points to approximate the regresion polynomial. Default 9 | ||
####derivative: | ||
The grade of the derivative. 0 by defualt(Smoothing) | ||
####polynomial: | ||
The order of the regresion polynomial. Default 3 | ||
### options | ||
#### windowSize: | ||
The odd number of points to approximate the regression polynomial. Default 9 | ||
#### derivative: | ||
The grade of the derivative. 0 by default (Smoothing) | ||
#### polynomial: | ||
The order of the regression polynomial. Default 3 | ||
## Examples | ||
```js | ||
var SG = require("ml-savitzky-golay-generalized"); | ||
var SG = require('ml-savitzky-golay-generalized'); | ||
``` | ||
### Smoothing example | ||
```js | ||
var options = { | ||
windowSize: 15, | ||
derivative: 0, | ||
polynomial: 3 | ||
}; | ||
windowSize: 15, | ||
derivative: 0, | ||
polynomial: 3, | ||
}; | ||
@@ -48,4 +62,6 @@ var noiseLevel = 0.1; | ||
for (var i = 0; i < data.length; i++) | ||
data[i] = Math.sin(i*Math.PI*2/data.length)+(Math.random()-0.5)*noiseLevel; | ||
var ans = SG(data, Math.PI*2/data.length, options); | ||
data[i] = | ||
Math.sin((i * Math.PI * 2) / data.length) + | ||
(Math.random() - 0.5) * noiseLevel; | ||
var ans = SG(data, (Math.PI * 2) / data.length, options); | ||
console.log(ans); | ||
@@ -58,6 +74,6 @@ ``` | ||
var options = { | ||
windowSize: 47, | ||
derivative: 1, | ||
polynomial: 3 | ||
}; | ||
windowSize: 45, | ||
derivative: 1, | ||
polynomial: 3, | ||
}; | ||
@@ -67,6 +83,7 @@ var noiseLevel = 0.1; | ||
for (var i = 0; i < data.length; i++) | ||
data[i] = Math.sin(i*Math.PI*2/data.length)+(Math.random()-0.5)*noiseLevel; | ||
var ans = SG(data, Math.PI*2/data.length, options); | ||
data[i] = | ||
Math.sin((i * Math.PI * 2) / data.length) + | ||
(Math.random() - 0.5) * noiseLevel; | ||
var ans = SG(data, (Math.PI * 2) / data.length, options); | ||
console.log(ans); | ||
``` | ||
@@ -78,6 +95,6 @@ | ||
var options = { | ||
windowSize: 47, | ||
derivative: 1, | ||
polynomial: 3 | ||
}; | ||
windowSize: 47, | ||
derivative: 1, | ||
polynomial: 3, | ||
}; | ||
@@ -87,8 +104,10 @@ var noiseLevel = 0.1; | ||
var x = new Array(200); | ||
for (var i = 0; i < data.length; i++){ | ||
data[i] = Math.sin(i*Math.PI*2/data.length)+(Math.random()-0.5)*noiseLevel; | ||
x[i]=i*Math.PI*2/data.length; | ||
for (var i = 0; i < data.length; i++) { | ||
data[i] = | ||
Math.sin((i * Math.PI * 2) / data.length) + | ||
(Math.random() - 0.5) * noiseLevel; | ||
x[i] = (i * Math.PI * 2) / data.length; | ||
} | ||
var ans = SG(data, Math.PI*2/data.length, options); | ||
var ans = SG(data, (Math.PI * 2) / data.length, options); | ||
var ans2 = SG(data, x, options); | ||
@@ -95,0 +114,0 @@ |
232
src/index.js
@@ -1,124 +0,123 @@ | ||
//Code translate from Pascal source in http://pubs.acs.org/doi/pdf/10.1021/ac00205a007 | ||
var extend = require('extend'); | ||
var stat = require('ml-stat'); | ||
export default function SavitzkyGolay(data, h, options = {}) { | ||
let { windowSize = 9, derivative = 0, polynomial = 3 } = options; | ||
var defaultOptions = { | ||
windowSize: 9, | ||
derivative: 0, | ||
polynomial: 3, | ||
}; | ||
if (windowSize % 2 === 0 || windowSize < 5 || !Number.isInteger(windowSize)) { | ||
throw new RangeError( | ||
'Invalid window size (should be odd and at least 5 integer number)', | ||
); | ||
} | ||
if (windowSize > data.length) { | ||
throw new RangeError( | ||
`Window size is higher than the data length ${windowSize}>${data.length}`, | ||
); | ||
} | ||
if (derivative < 0 || !Number.isInteger(derivative)) { | ||
throw new RangeError('Derivative should be a positive integer'); | ||
} | ||
if (polynomial < 1 || !Number.isInteger(polynomial)) { | ||
throw new RangeError('Polynomial should be a positive integer'); | ||
} | ||
if (polynomial >= 6) { | ||
// eslint-disable-next-line no-console | ||
console.warn( | ||
'You should not use polynomial grade higher than 5 if you are' + | ||
' not sure that your data arises from such a model. Possible polynomial oscillation problems', | ||
); | ||
} | ||
let half = Math.floor(windowSize / 2); | ||
let np = data.length; | ||
let ans = new Array(np); | ||
let weights = fullWeights(windowSize, polynomial, derivative); | ||
let hs = 0; | ||
let constantH = true; | ||
if (Array.isArray(h)) { | ||
constantH = false; | ||
} else { | ||
hs = Math.pow(h, derivative); | ||
} | ||
function SavitzkyGolay(data, h, options) { | ||
options = extend({}, defaultOptions, options); | ||
if ((options.windowSize % 2 === 0) || (options.windowSize < 5) || !(Number.isInteger(options.windowSize))) | ||
throw new RangeError('Invalid window size (should be odd and at least 5 integer number)') | ||
if (options.windowSize>data.length) | ||
throw new RangeError('Window size is higher than the data length '+options.windowSize+">"+data.length); | ||
if ((options.derivative < 0) || !(Number.isInteger(options.derivative))) | ||
throw new RangeError('Derivative should be a positive integer'); | ||
if ((options.polynomial < 1) || !(Number.isInteger(options.polynomial))) | ||
throw new RangeError('Polynomial should be a positive integer'); | ||
if (options.polynomial >= 6) | ||
console.warn('You should not use polynomial grade higher than 5 if you are' + | ||
' not sure that your data arises from such a model. Possible polynomial oscillation problems'); | ||
var windowSize = options.windowSize; | ||
var half = Math.floor(windowSize/2); | ||
var np = data.length; | ||
var ans = new Array(np); | ||
var weights = fullWeights(windowSize,options.polynomial,options.derivative); | ||
var hs = 0; | ||
var constantH = true; | ||
if( Object.prototype.toString.call( h ) === '[object Array]' ) { | ||
constantH = false; | ||
//For the borders | ||
for (let i = 0; i < half; i++) { | ||
let wg1 = weights[half - i - 1]; | ||
let wg2 = weights[half + i + 1]; | ||
let d1 = 0; | ||
let d2 = 0; | ||
for (let l = 0; l < windowSize; l++) { | ||
d1 += wg1[l] * data[l]; | ||
d2 += wg2[l] * data[np - windowSize + l - 1]; | ||
} | ||
else{ | ||
hs = Math.pow(h, options.derivative); | ||
if (constantH) { | ||
ans[half - i - 1] = d1 / hs; | ||
ans[np - half + i] = d2 / hs; | ||
} else { | ||
hs = getHs(h, half - i - 1, half, derivative); | ||
ans[half - i - 1] = d1 / hs; | ||
hs = getHs(h, np - half + i, half, derivative); | ||
ans[np - half + i] = d2 / hs; | ||
} | ||
//console.log("Constant h: "+constantH); | ||
//For the borders | ||
for(var i=0;i<half;i++){ | ||
var wg1=weights[half-i-1]; | ||
var wg2=weights[half+i+1]; | ||
var d1 = 0,d2=0; | ||
for (var l = 0; l < windowSize; l++){ | ||
d1 += wg1[l] * data[l]; | ||
d2 += wg2[l] * data[np-windowSize+l-1]; | ||
} | ||
if(constantH){ | ||
ans[half-i-1] = d1/hs; | ||
ans[np-half+i] = d2/hs; | ||
} | ||
else{ | ||
hs = getHs(h,half-i-1,half, options.derivative); | ||
ans[half-i-1] = d1/hs; | ||
hs = getHs(h,np-half+i,half, options.derivative); | ||
ans[np-half+i] = d2/hs; | ||
} | ||
} | ||
//For the internal points | ||
var wg = weights[half]; | ||
for(var i=windowSize;i<np+1;i++){ | ||
var d = 0; | ||
for (var l = 0; l < windowSize; l++) | ||
d += wg[l] * data[l+i-windowSize]; | ||
if(!constantH) | ||
hs = getHs(h,i-half-1,half, options.derivative); | ||
ans[i-half-1] = d/hs; | ||
} | ||
return ans; | ||
} | ||
//For the internal points | ||
let wg = weights[half]; | ||
for (let i = windowSize; i <= np; i++) { | ||
let d = 0; | ||
for (let l = 0; l < windowSize; l++) d += wg[l] * data[l + i - windowSize]; | ||
if (!constantH) hs = getHs(h, i - half - 1, half, derivative); | ||
ans[i - half - 1] = d / hs; | ||
} | ||
return ans; | ||
} | ||
function getHs(h,center,half,derivative){ | ||
var hs = 0; | ||
var count = 0; | ||
for(var i=center-half;i<center+half;i++){ | ||
if(i>=0 && i < h.length-1){ | ||
hs+= (h[i+1]-h[i]); | ||
count++; | ||
} | ||
function getHs(h, center, half, derivative) { | ||
let hs = 0; | ||
let count = 0; | ||
for (let i = center - half; i < center + half; i++) { | ||
if (i >= 0 && i < h.length - 1) { | ||
hs += h[i + 1] - h[i]; | ||
count++; | ||
} | ||
return Math.pow(hs/count,derivative); | ||
} | ||
return Math.pow(hs / count, derivative); | ||
} | ||
function GramPoly(i,m,k,s){ | ||
var Grampoly = 0; | ||
if(k>0){ | ||
Grampoly = (4*k-2)/(k*(2*m-k+1))*(i*GramPoly(i,m,k-1,s) + | ||
s*GramPoly(i,m,k-1,s-1)) - ((k-1)*(2*m+k))/(k*(2*m-k+1))*GramPoly(i,m,k-2,s); | ||
function GramPoly(i, m, k, s) { | ||
let Grampoly = 0; | ||
if (k > 0) { | ||
Grampoly = | ||
((4 * k - 2) / (k * (2 * m - k + 1))) * | ||
(i * GramPoly(i, m, k - 1, s) + s * GramPoly(i, m, k - 1, s - 1)) - | ||
(((k - 1) * (2 * m + k)) / (k * (2 * m - k + 1))) * | ||
GramPoly(i, m, k - 2, s); | ||
} else { | ||
if (k === 0 && s === 0) { | ||
Grampoly = 1; | ||
} else { | ||
Grampoly = 0; | ||
} | ||
else{ | ||
if(k==0&&s==0){ | ||
Grampoly=1; | ||
} | ||
else{ | ||
Grampoly=0; | ||
} | ||
} | ||
//console.log(Grampoly); | ||
return Grampoly; | ||
} | ||
return Grampoly; | ||
} | ||
function GenFact(a,b){ | ||
var gf=1; | ||
if(a>=b){ | ||
for(var j=a-b+1;j<=a;j++){ | ||
gf*=j; | ||
} | ||
function GenFact(a, b) { | ||
let gf = 1; | ||
if (a >= b) { | ||
for (let j = a - b + 1; j <= a; j++) { | ||
gf *= j; | ||
} | ||
return gf; | ||
} | ||
return gf; | ||
} | ||
function Weight(i,t,m,n,s){ | ||
var sum=0; | ||
for(var k=0;k<=n;k++){ | ||
//console.log(k); | ||
sum+=(2*k+1)*(GenFact(2*m,k)/GenFact(2*m+k+1,k+1))*GramPoly(i,m,k,0)*GramPoly(t,m,k,s) | ||
} | ||
return sum; | ||
function Weight(i, t, m, n, s) { | ||
let sum = 0; | ||
for (let k = 0; k <= n; k++) { | ||
//console.log(k); | ||
sum += | ||
(2 * k + 1) * | ||
(GenFact(2 * m, k) / GenFact(2 * m + k + 1, k + 1)) * | ||
GramPoly(i, m, k, 0) * | ||
GramPoly(t, m, k, s); | ||
} | ||
return sum; | ||
} | ||
@@ -132,12 +131,12 @@ | ||
*/ | ||
function fullWeights(m,n,s){ | ||
var weights = new Array(m); | ||
var np = Math.floor(m/2); | ||
for(var t=-np;t<=np;t++){ | ||
weights[t+np] = new Array(m); | ||
for(var j=-np;j<=np;j++){ | ||
weights[t+np][j+np]=Weight(j,t,np,n,s); | ||
} | ||
function fullWeights(m, n, s) { | ||
let weights = new Array(m); | ||
let np = Math.floor(m / 2); | ||
for (let t = -np; t <= np; t++) { | ||
weights[t + np] = new Array(m); | ||
for (let j = -np; j <= np; j++) { | ||
weights[t + np][j + np] = Weight(j, t, np, n, s); | ||
} | ||
return weights; | ||
} | ||
return weights; | ||
} | ||
@@ -170,2 +169,1 @@ | ||
module.exports = SavitzkyGolay; | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16751
0
381
118
10
7
2
- Removedextend@^3.0.0
- Removedml-stat@^1.3.3
- Removedextend@3.0.2(transitive)
- Removedml-stat@1.3.3(transitive)