Class: Spliner::Spliner
- Inherits:
-
Object
- Object
- Spliner::Spliner
- Defined in:
- lib/spliner/spliner.rb
Overview
Spliner::Spliner provides cubic spline interpolation based on provided key points on a X-Y curve.
Example
require 'spliner'
# Initialize a spline interpolation with x range 0.0..2.0
my_spline = Spliner::Spliner.new [0.0, 1.0, 2.0], [0.0, 1.0, 0.5]
# Interpolate for a single value
y1 = my_spline[0.5]
# Perform interpolation on 11 values ranging from 0..2.0
y_values = my_spline[(0.0..2.0).step(0.1)]
# You may prefer to use the shortcut class method
y2 = Spliner::Spliner[[0.0, 1.0, 2.0], [0.0, 1.0, 0.5], 0.5]
Algorithm based on en.wikipedia.org/wiki/Spline_interpolation
Instance Attribute Summary collapse
-
#range ⇒ Object
readonly
Returns the value of attribute range.
Class Method Summary collapse
-
.interpolate(*args) ⇒ Object
(also: [])
shortcut method to instanciate a Spliner::Spliner object and return a series of interpolated values.
Instance Method Summary collapse
-
#get(*x) ⇒ Object
(also: #[])
returns the interpolated Y value(s) at the specified X.
-
#initialize(*param) ⇒ Spliner
constructor
Creates a new Spliner::Spliner object to interpolate between the supplied key points.
-
#sections ⇒ Object
The number of non-continuous sections used.
Constructor Details
#initialize(key_points, options) ⇒ Spliner #initialize(x, y, options) ⇒ Spliner
Creates a new Spliner::Spliner object to interpolate between the supplied key points.
The key points shoul be in increaing X order. When duplicate X values are encountered, the spline is split into two or more discontinuous sections.
The extrapolation method may be :linear by default, using a linear extrapolation at the curve ends using the curve derivative at the end points. The :hold method will use the Y value at the nearest end point of the curve.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/spliner/spliner.rb', line 57 def initialize(*param) # sort parameters from two alternative initializer signatures x, y = nil case param.first when Array, Vector xx,yy, = param x = xx.to_a y = yy.to_a else points, = param x = points.keys y = points.values end ||= {} if [:fix_invalid_x] begin size_at_start = x.size pp = Hash[x.zip y] to_delete = pp.keys.each_cons(2).select {|a,b| b < a}.map(&:last) to_delete.each {|k| pp.delete k } x = pp.keys y = pp.values end while x.size < size_at_start end @sections = split_at_duplicates(x).map {|slice| SplinerSection.new x[slice], y[slice] } # Handle extrapolation option parameter [:extrapolate].tap do |ex| case ex when /^\d+(\.\d+)?\s?%$/ percentage = ex[/\d+(\.\d+)?/].to_f span = x.last - x.first extra = span * percentage * 0.01 @range = (x.first - extra)..(x.last + extra) when Range @range = ex when Float span = x.last - x.first extra = span * ex @range = (x.first - extra)..(x.last + extra) when nil @range = x.first..x.last else raise 'Unable to use extrapolation parameter' end end @extrapolation_method = [:emethod] || :linear end |
Instance Attribute Details
#range ⇒ Object (readonly)
Returns the value of attribute range.
28 29 30 |
# File 'lib/spliner/spliner.rb', line 28 def range @range end |
Class Method Details
.interpolate(points, x, options) ⇒ Object .interpolate(key_x, key_y, x, options) ⇒ Object Also known as: []
shortcut method to instanciate a Spliner::Spliner object and return a series of interpolated values. Options are like Spliner::Spliner#initialize
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/spliner/spliner.rb', line 123 def self.interpolate(*args) if (args.first.class == Hash) key_points, x, = args s = Spliner.new key_points, ( || {}) s[x] else key_x, key_y, x, = args s = Spliner.new key_x, key_y, ( || {}) s[x] end end |
Instance Method Details
#get(*x) ⇒ Object Also known as: []
returns the interpolated Y value(s) at the specified X
Example
my_spline = Spliner::Spliner.new [0.0, 1.0, 2.0], [0.0, 1.0, 0.5]
# get one value
y1 = my_spline.get 0.5
# get many values
y2 = my_spline.get [0.5, 1.5, 2.5]
y3 = my_spline.get 0.5, 1.5, 2.5
# get a range of values
y4 = my_spline.get 1..3
# generate an enumeration of x values
y5 = my_spline.get (1.5..2.5).step(0.5)
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/spliner/spliner.rb', line 165 def get(*x) xx = if x.size == 1 x.first else x end get_func = lambda do |v| i = @sections.find_index {|section| section.range.cover? v } if i @sections[i].get v elsif range.cover? v extrapolate(v) else nil end end case xx when Vector xx.collect {|x| get_func.call(x) } when Enumerable xx.map {|x| get_func.call(x) } else get_func.call(xx) end end |
#sections ⇒ Object
The number of non-continuous sections used
196 197 198 |
# File 'lib/spliner/spliner.rb', line 196 def sections @sections.size end |