Takes 1D data sampled at uniform intervals and resamples it at arbitrary, nonuniform locations.
The package is currently not registered, so you'll have to install it from GitHub. Open a Julia REPL and run:
]add https://github.com/Firionus/NonuniformResampling1D.jlThis package is not production ready. It is recommended to only use it for non-critical applications.
using NonuniformResampling1D
xin = 1:9 # input locations
yin = [1, 3, 2, 6, 7, 3, 2, 8, 3] # input values
yout = nuresample(xin, yin, [4.5, 6.2])
# output
2-element Vector{Float64}:
6.613040058882213
2.7151900996408322#
NonuniformResampling1D.nuresample — Function.
nuresample(xin, yin, xout, smoothing_function; kwargs...)Take data yin sampled at uniformly spaced locations xin and resample at nonuniform locations xout.
Positional Arguments
xinis anAbstractRangeof input locationsyinis anAbstractArraywith the input valuesxoutis anAbstractArraywith the the increasing output locationssmoothing_functionis aWindowFunction. The width of the window function is scaled proportional to the distance to the nearest neighbor on the left and right side of the output point. At the start and end ofxouta symmetrical window is used. The default is a rectangular window without overlap.
Keyword Arguments
upsampling_function: aWindowFunctionthat is used to perform upsampling when the density of input points is not high enough compared to the density of output points. The default is Lanczos3.required_points_per_slice: the number of input points that must be in a slice (left or right half of a window) before smoothing. If the number of input points is lower than this value, upsampling is performed to createrequired_points_per_slicemany points before applying the smoothing function. The default isround(4 * smoothing_function.width), which means 4 points are required per unit width to the nearest neighbor. The minimum value is 1, in which case upsampling is only performed if no input point falls in a slice.
Examples
julia> nuresample(1:9, 1:9, [4.2, 6.2])
2-element Vector{Float64}:
4.201106036510037
6.201106036510037julia> nuresample(1:9, 1:9, [4.2, 6.2],
rect_window(.5), # moving average without overlap
required_points_per_slice = 1, # no upsampling
upsampling_function = lanczos_window(2)) # Lanczos2 interpolation if a slice were empty
2-element Vector{Float64}:
4.5
6.5Output Type
Returns an Array{Float64, 1}. Other output types are currently unsupported.
#
NonuniformResampling1D.rect_window — Function.
rect_window(width = 0.5)Rectangular window which is 1 from 0 to width and 0 otherwise.
Can be used to calculate a moving average, for example.
#
NonuniformResampling1D.hann_window — Function.
hann_window(width = 1)Hann window (raised cosine) that is 1 at 0 and reaches 0 at width.
#
NonuniformResampling1D.tri_window — Function.
tri_window(width = 1)Triangular window which is 1 at 0 and reaches 0 at width.
Can be used to perform linear interpolation when used as upsampling_function with width=1.
#
NonuniformResampling1D.kaiser_window — Function.
kaiser_window(width = 1.2; alpha = 3.5)Kaiser window cut off at width with the shape parameter alpha.
#
NonuniformResampling1D.lanczos_window — Function.
lanczos_window(lobes = 3; width = 1)Lanczos window which is 1 at 0 and 0 at 1*width, 2*width, 3*width, ...
The higher the number of lobes, the higher the accuracy of sinc approximation.
To define your own window functions, take a look at the examples in window_functions.jl and use the exported WindowFunction type:
#
NonuniformResampling1D.WindowFunction — Type.
WindowFunction(_f::Function, width)A radial window function.
It is defined by the callback _f between x = 0 (center) and x = width. x=1 is the position of the nearest neighbor and the range x ∈ [0,1] is called a unit.
Fields
_f<:Function
Callback defining the window function.
It will be called as _f(x::Real) and is expected to return a Real number. x can be expected to go from 0 (center of window) to width. x values above width will return 0 without calling _f.
By convention, _f(0) == 1. If orthogonality to the nearest neighbor is desired, it should return _f(1) == 0.
width<:Real
Value up to which the callback function will be evaluated.
width must be bigger than 0. A width of 1 means that the window function is evaluated up to the nearest neighbor.
Examples
julia> rectangular_window = WindowFunction(x -> 1., 0.5)
WindowFunction{var"#1#2", Float64}(var"#1#2"(), 0.5)
julia> rectangular_window(.4)
1.0
julia> rectangular_window(.6)
0.0The basic idea of the provided algorithm is that the output value at any location should be given by a weighted average of input values in a region around the output point, where the weight is given by a window function. The supporting region is called a slice and is proportional in size to the distance to the next neighbor. The ratio between slice width and distance to the nearest neighbor is the window function width and determines how strong the smoothing is.
Further, if there are few points in a slice, the result might not be accurate. Therefore, ad-hoc resampling is used. So if the left or right slice of an output point contains less points than specified, upsampling on a regular grid is performed for both slices.
Consider an example with
nuresample(xin, yin, xout, hann_window(1.35), required_points_per_slice = 4)which can be visualized like this:
The orange output point shows how the window function and supporting regions are scaled asymmetrically around the output point, depending on how far the neighboring output points are away. The input values and the window function are multiplied pointwise, resulting in the windowed slices shown in the second plot from the top. The normalized average of these points is the orange output value.
The blue point shows the dynamic upsampling. since its slices contain less than 4 points, upsampling is applied before applying the window function. The default upsampling function Lanczos3 is used to create the points in bright blue. They are created with uniform step size. The upsampled points are then weighted with the window function and the normalized average forms the blue output value.
Upsampling is performed for both slices, even if only one of them has too few points. This ensures that the weight between the two slices stays approximately even. The upsampling step is the same between the two slices and is chosen such that required_points_per_slice are created in the smaller of the two slices.
I originally wrote this package to perform logarithmic smoothing. A demo notebook is available at https://github.com/Firionus/logarithmic_smoothing_julia_demo.
If you have any problems or feedback, please open an issue.