-
Notifications
You must be signed in to change notification settings - Fork 0
/
interpolate.py
52 lines (42 loc) · 1.5 KB
/
interpolate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import numpy as np
from scipy.stats import norm
def lerp(val, low, high):
"""Linear interpolation"""
return low + (high - low) * val
def lerp_gaussian(val, low, high):
"""Linear interpolation with gaussian CDF"""
low_gau = norm.cdf(low)
high_gau = norm.cdf(high)
lerped_gau = lerp(val, low_gau, high_gau)
return norm.ppf(lerped_gau)
def slerp(val, low, high):
"""Spherical interpolation. val has a range of 0 to 1."""
if val <= 0:
return low
elif val >= 1:
return high
elif np.allclose(low, high):
return low
omega = np.arccos(np.dot(low/np.linalg.norm(low), high/np.linalg.norm(high)))
so = np.sin(omega)
return np.sin((1.0-val)*omega) / so * low + np.sin(val*omega)/so * high
def slerp_gaussian(val, low, high):
"""Spherical interpolation with gaussian CDF (generally not useful)"""
offset = norm.cdf(np.zeros_like(low)) # offset is just [0.5, 0.5, ...]
low_gau_shifted = norm.cdf(low) - offset
high_gau_shifted = norm.cdf(high) - offset
circle_lerped_gau = slerp(val, low_gau_shifted, high_gau_shifted)
epsilon = 0.001
clipped_sum = np.clip(circle_lerped_gau + offset, epsilon, 1.0 - epsilon)
result = norm.ppf(clipped_sum)
return result
def get_interpfn(spherical, gaussian):
"""Returns an interpolation function"""
if spherical and gaussian:
return slerp_gaussian
elif spherical:
return slerp
elif gaussian:
return lerp_gaussian
else:
return lerp