Last active
October 23, 2016 21:40
-
-
Save randombrein/c53d9ec4ac07c54896688ff668125562 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Monotonic increasing sinusoidal curve with same entrance/exit angle | |
""" | |
import numpy as np | |
import pylab | |
def discrt_tan(x0, y0, x1, y1): | |
""" discrete tangent function for tuple of points """ | |
return np.divide(np.subtract(y1,y0), np.subtract(x1,x0)) | |
def curve(xs, size, mid_angle=0.0): | |
""" monotonic raising curve function with sinusoidal accent. | |
Function for a monotonic raising curve with same entrance/exit angle. | |
Sinusoidal setup for *monotonic increasing* constraints angles in following fashion; | |
- mid_angle must be between [0..pi/4) - approaching pi/4 yields straight line. | |
- generated entrance/exit angles are between [45..~63.43] degrees | |
The curve is expresses as; | |
y = x + [sin(2PI * x / size)] / accent | |
Args: | |
xs (array like): input value(s) | |
size: size range of the input/output values | |
mid_angle: middle angle of the sinusoidal in radians | |
Returns: | |
array-like curve value. | |
Raises: | |
`ValueError` for params. that out of range; | |
mid_angle - must be between [0..pi/4) | |
xs - must be in range between [0..size] | |
Todo: | |
- `accent` does not well-define middle angle parameter. | |
- if curve will not be limited in size range, derivation will be step-wise continuous. | |
More calculation can be made for continuous derivation. (tangents at 0 and size) | |
""" | |
if mid_angle<0 or mid_angle>=np.pi/4: | |
raise ValueError("mid-angle must be between [0..pi/4)") | |
if np.any(xs < 0) or np.any(xs > size): | |
raise ValueError("xs must be between [0..size]") | |
accent = 2*np.pi/size * np.tan(np.pi/4+mid_angle) # TODO: not well-defined mid-angle param. | |
return xs + np.sin(2*np.pi*xs/size) / accent | |
if __name__ == "__main__": | |
""" | |
Test and plot `curve` function for various values and mid_angle degrees | |
""" | |
eps = 1e-11 | |
#eps = np.finfo(float).eps | |
size = 1 | |
print "### testing values..." | |
print "x= {:.15f}, y={:.15f}".format(size, curve(size, size)) | |
print "x= {:.15f}, y={:.15f}".format(np.subtract(size,eps), curve(np.subtract(size,eps), size)) | |
print "x= {:.15f}, y={:.15f}".format(size/2.0, curve(size/2.0, size)) | |
# angles at 0, mid, size | |
mids = [0, np.pi/128, np.pi/64, np.pi/32, np.pi/16, np.pi/8, np.pi/6, np.pi/4-eps] | |
max_err = 0.0 | |
params = {'legend.fontsize': 'small', | |
'axes.labelsize': 'small', | |
'axes.titlesize':'small', | |
'xtick.labelsize':'small', | |
'ytick.labelsize':'small'} | |
pylab.rcParams.update(params) | |
colc = 2 | |
rowc = (len(mids)+1)/colc | |
f, axarr = pylab.subplots(rowc, colc) | |
print "\n### testing angles..." | |
for i,mid in enumerate(mids): | |
print "mid (input) = {:.15f}".format(np.rad2deg(mid)) | |
t = discrt_tan(size/2.0, curve(size/2.0, size, mid), | |
np.add(size/2.0,eps), curve(np.add(size/2.0,eps), size, mid)) | |
print "angle at mid = {:.15f}".format(np.rad2deg(np.arctan(t))) | |
t = discrt_tan(0, curve(0, size, mid), | |
eps, curve(eps, size, mid)) | |
print "angle at 0 = {:.15f}".format(np.rad2deg(np.arctan(t))) | |
t1 = discrt_tan(size, curve(size, size, mid), | |
np.subtract(size,eps), curve(np.subtract(size,eps), size, mid)) | |
print "angle at size = {:.15f}".format(np.rad2deg(np.arctan(t1))) | |
# error | |
err = np.abs(np.subtract(np.rad2deg(np.arctan(t1)), np.rad2deg(np.arctan(t)))) | |
max_err = np.maximum(max_err, err) | |
print "error = {:.15f}\n".format(err) | |
# plot | |
xs = np.linspace(0, size, 100) | |
ys = curve(xs, size, mid) | |
row = i/colc | |
col = i - row*colc | |
axarr[row, col].plot(xs, ys) | |
axarr[row, col].set_title('mid_angle={:.4f} rad.'.format(mid)) | |
axarr[row, col].text(0.95, 0.15, 'alpha={:.6f} deg.'.format(np.rad2deg(np.arctan(t))), | |
verticalalignment='bottom', horizontalalignment='right', | |
transform=axarr[row, col].transAxes, | |
color='green', fontsize=10) | |
axarr[row, col].text(0.95, 0.03, 'err={:.6f} deg.'.format(err), | |
verticalalignment='bottom', horizontalalignment='right', | |
transform=axarr[row, col].transAxes, | |
color='red', fontsize=10) | |
print"Max. Error = {:.15f}".format(max_err) | |
pylab.show() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment