Mauro Werder 2016-03-31
I was looking for the function of one branch of a generally oriented hyperbola to use as a function which smoothly transitions between two linear functions (continous). Alas, either this is not to be found on the internet or my search-foo failed me. Now it's written down here for the next person to find. I show two approaches, the first entails a bit more algebra and uses the semi-major axis as a parameter, the second uses the abcissa as parameter instead.
Note that there are other ways to make a smooth transition, even between discontinous functions, e.g. using sigmoid functions.
This notebook can be downloaded here, you need to run it yourself to use the interactive features.
The general equation for a conic section centered at the origin is
$$ Ax^2 + 2Bxy + Cy^2 + 1 = 0$$(refer to Wikipedia). It is a hyperbola if $D=AC-B^2<0$. Above equation can be solved for y
$$y(x) = \frac{-Bx \pm \sqrt{-D x^2-C}}{C},$$
which gives the two branches of the hyperbola.
However, instead of the coefficients A
, B
and C
, I want the formula in terms of the slopes of the asymptotes (s1
, s2
) and the semi-major axis a
(i.e. the closest distance to the origin). The slopes are given by
$$s_{1/2} = \frac{-B \pm \sqrt{-D}}{C}$$
and a
is given by (see Wikipedia)
These equations can be solved for A, B, C (and D):
$$ A = \sqrt{-D} \alpha, \quad B = \sqrt{-D} \beta, \quad C = \sqrt{-D} \gamma $$with $\gamma=2/(s_1-_s2), \quad \beta = (s_2+s_1)/(s_2-s_1), \quad \alpha = - (1-b^2)/c$ and
$$D = - \frac{4}{a^4 \big( \alpha + \gamma - \sqrt{(\alpha+\gamma)^2 +4} \big)^2}$$Now I got everything for the desired hyperbola function, implemented below:
"""
One branch of a hyperbola as a function of x given by
- s1: asymptote slope for x<0
- s2: asymptote slope for x>0
- a: semi major axis, i.e. minimum distance from the origin
- optionally shift the origin by xoff, yoff
"""
function hyperbola(x, s1, s2, a, xoff=0.0, yoff=0.0)
x = x-xoff
# Deal with degenerate cases and select the right branch of the hyperbola
if a==0 # return two lines
i1 = x.<0
i2 = x.>=0
return vcat(s1*x[i1], s2*x[i2]) + yoff
elseif s1==s2 # return one line
return collect(s1*x + yoff) # collect to make it type stable
elseif s1>s2
branch = +1
s1,s2 = s2,s1
else
branch = -1
end
γ = 2/(s1-s2)
β = (s2+s1)/(s2-s1)
α = - (1- β^2)/γ
D = - 4 / ( a^2 *( α + γ - sqrt((α+γ)^2 +4)) )^2
@assert D<0
C = sqrt(-D) * γ
B = sqrt(-D) * β
A = sqrt(-D) * α
@assert isapprox(D, A*C-B^2)
return (-B*x + branch * sqrt(x.^2*(B^2-A*C) - C))/C + yoff
end;
using Reactive, Interact, Plots # make an interactive graphic
gr(size=(600,600)) # use GR.jl, much faster than PyPlot
dx = 0.05
x = -5:dx:5
@manipulate for s1=-6:0.1:5, s2=-5:0.1:5.5, a=0.0:0.05:1.5, xoff=-1:0.1:1, yoff=-1:0.1:1
x1 = -5:dx:xoff
x2 = xoff:dx:5
plot(x, hyperbola(x, s1, s2, a, xoff, yoff), label="hyperbola", w=3)
plot!(x1, (x1-xoff)*s1+yoff, label="s1", w=2)
plot!(x2, (x2-xoff)*s2+yoff, label="s2", xlims=(-5,5), ylims=(-5,5), w=2)
end
Much easier is using the abcissa at x=0. Use the ansatz (note A,C, and D are different from above):
$$y(x) = Bx + \sqrt{-Dx^2-C}$$with $D<0, C<0$. This gives the slopes
$$s_{1/2} = B\mp \sqrt{-D}$$and absolute value of abcissa at $x=0$
$$\Delta y = \sqrt{-C}$$solving for B, C, D
$$ B = \frac{s_1+s_2}{2}, \quad D=\frac{(s_2-s_1)^2}{4}, \quad C = -\Delta y^2$$Implemented below, also taking care to select the right hyperbola branche and of degenerate cases:
"""
One branch of a hyperbola as a function of x given by
- s1: asymptote slope for x<0
- s2: asymptote slope for x>0
- Δy: absolute value of abcissa at x=0
- optionally shift the origin by xoff, yoff
"""
function hyperbola2(x, s1, s2, Δy, xoff=0.0, yoff=0.0)
x = x-xoff
# Deal with degenerate cases and select the right branch of the hyperbola
if Δy==0 # return two lines
i1 = x.<0
i2 = x.>=0
return vcat(s1*x[i1], s2*x[i2]) + yoff
elseif s1==s2 # return one line
branch = 0
elseif s1>s2
branch = -1
s1,s2 = s2,s1
else
branch = +1
end
B = (s1+s2)/2
C = -Δy^2
D = - (s2-s1)^2/4
return B*x + branch * sqrt(-D*x.^2-C) + yoff
end;
@manipulate for s1=-6:0.1:5, s2=-5:0.1:5.5, Δy=0:0.05:1.5, xoff=-1:0.1:1, yoff=-1:0.1:1
x1 = -5:dx:xoff
x2 = xoff:dx:5
plot(x, hyperbola2(x, s1, s2, Δy, xoff, yoff), label="hyperbola", w=3)
plot!(x1, (x1-xoff)*s1+yoff, label="s1", w=2)
plot!(x2, (x2-xoff)*s2+yoff, label="s2", xlims=(-5,5), ylims=(-5,5), w=2)
plot!([xoff,xoff], sign(s2-s1)*[yoff, yoff+Δy], label="\\Delta y", w=2)
end