Hyperbola in terms of its asymptote slopes and semi-major axis

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.

Using slopes and semi-major axis

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)

$$a^2 = -\frac{1}{\lambda_1} = -\frac{2}{A+C - \sqrt{(A+C)^2 - 4D}}$$

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:

In [1]:
"""
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;
In [5]:
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
Out[5]:
- 4 - 2 0 2 4 - 4 - 2 0 2 4 hyperbola s1 s2

Using slopes and abcissa

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:

In [3]:
"""
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;
In [4]:
@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
Out[4]:
- 4 - 2 0 2 4 - 4 - 2 0 2 4 hyperbola s1 s2 \Delta y
In [ ]: