Skip to content

Commit

Permalink
FFT Spline (#6)
Browse files Browse the repository at this point in the history
Smoothing Splines via a hybrid of  linear + sine basis functions
  • Loading branch information
francescoalemanno authored May 31, 2023
1 parent 9ef0b2c commit 80f9574
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "KissSmoothing"
uuid = "23b0397c-cd08-4270-956a-157331f0528f"
authors = ["Francesco Alemanno <[email protected]>"]
version = "1.0.6"
version = "1.0.7"

[deps]
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Expand Down
33 changes: 20 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,33 +154,40 @@ savefig("nspline.png")

fit_sine_series(X::Vector, Y::Vector, basis_elements::Integer, noise=0)

fit Y ~ 1 + X + Σ sin(.) according to:
fit Y ~ 1 + X + Σ sin(.) by minimising Σ (Y - f(x))^2 + lambda * ∫(Δ^order F)^2

`X` : array N, N number of training points
`X` : array N, N number of training points.

`Y` : array N, N number of training points
`Y` : array N, N number of training points.

`basis_elements` : number of sine terms
`basis_elements` : number of sine terms.

`noise` : noise filtering according to Wiener method, default to 0 (off)
Keyword arguments:

`lambda` : intensity of regularization.

`order` : derivative to regularise.

returns a callable function.

### Example

```julia
using PyPlot, KissSmoothing
t = LinRange(0,pi,250)
ty = sin.(t.^2) .+ t
y = ty .+ randn(length(t)) .*0.05
fn = fit_sine_series(t,y,20)
scatter(t, y, color="gray",s=2,label="noisy")
plot(t, fn.(t), color="red",lw=1.,label="sine fit")
plot(t,ty, color="blue",lw=0.7,label="true")
fg(x) = sin(x^2) + x
x = collect(LinRange(0,pi,250))
xc = identity.(x)
filter!(x->(x-1)^2>0.1, x)
filter!(x->(x-2)^2>0.1, x)
y = fg.(x) .+ randn(length(x)) .*0.05
fn = fit_sine_seris(x,y,20, lambda = 0.00001)
scatter(x, y, color="gray",s=2,label="noisy")
plot(xc, fn.(xc), color="red",lw=1.,label="fit")
plot(xc,fg.(xc), color="blue",lw=0.7,label="true")
xlabel("X")
ylabel("Y")
legend()
tight_layout()
savefig("sine_fit.png")
```
![sine_fit.png](sine_fit.png "Plot of NSpline estimation")
![sine_fit.png](sine_fit.png "Plot of FFT Spline estimation")
Binary file modified sine_fit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 19 additions & 13 deletions src/KissSmoothing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -198,42 +198,48 @@ end
"""
fit_sine_series(X::Vector, Y::Vector, basis_elements::Integer, noise=0)
fit Y ~ 1 + X + Σ sin(.) according to:
fit Y ~ 1 + X + Σ sin(.) by minimising Σ (Y - f(x))^2 + lambda * ∫(Δ^order F)^2
`X` : array N, N number of training points
`X` : array N, N number of training points.
`Y` : array N, N number of training points
`Y` : array N, N number of training points.
`basis_elements` : number of sine terms
`basis_elements` : number of sine terms.
`noise` : noise filtering according to Wiener method, default to 0 (off)
Keyword arguments:
`lambda` : intensity of regularization.
`order` : derivative to regularise.
returns a callable function.
"""
function fit_sine_series(X::AbstractVector{<:Real}, Y::AbstractVector{<:Real}, basis_elements::Integer, noise = 0.0)
function fit_sine_series(X::AbstractVector{<:Real},Y::AbstractVector{<:Real}, basis_elements::Integer; lambda = 0.0, order::Int64=3)
lx, hx = extrema(X)
T = @. (X - lx)/(hx-lx)*pi
M = zeros(length(X),2+basis_elements)
for i in eachindex(X)
M[i, 1] = 1
M[i, 2] = T[i]
for k in 1:basis_elements
M[ i, 2+k] = sin(k*T[i])
M[i, 2+k] = sin(k*T[i])#/k^order
end
end
C = M\Y
phi = M'M
for i=3:2+basis_elements
phi[i,i] += lambda*(i-2)^(2order)
end
C = phi \ (M'*Y)
return function fn(x)
t = (x - lx)/(hx-lx)*pi
s = C[1]+C[2]*t
s = C[1] + C[2]*t
for k in 1:basis_elements
cn1 = C[2+k]
SN = abs2(cn1)
hn = max(1 - noise*noise/SN,0)
s += cn1*sin(k*t)*hn
s += C[2+k]*sin(k*t)#/k^order
end
s
end
end


export denoise, fit_rbf, RBF, fit_nspline, fit_sine_series
end # module
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ end
for μ in LinRange(-100,100,5)
t = LinRange(0,2pi,150)
y = sin.(t) .+ μ .* t
fn = fit_sine_series(t,y,50)
fn = fit_sine_series(t,y,50, order = 3, lambda = 0.00001)
pred_y = fn.(t)
error = sqrt(sum(abs2, pred_y .- y)/length(t))
@test error < 0.0002
Expand Down

0 comments on commit 80f9574

Please sign in to comment.