Exemplo n.º 1
0
def adaptive(t,
             y,
             h,
             prop_1,
             trans,
             prop_2,
             inv_trans,
             err_tol=1e-3,
             err_fun=None):
    if err_fun is None:
        err_fun = lambda yd, ys: (mathx.abs_sqd(yd - ys).sum() / mathx.abs_sqd(
            yd).sum())**0.5
    yd = double(t, y, h, prop_1, trans, prop_2, inv_trans)
    ys = single(t, y, h, prop_1, trans, prop_2, inv_trans)

    # Per channel - maybe TODO make option
    #rel_err=(abs(yd-ys)/np.maximum(np.maximum(abs(yd),abs(ys)),sys.float_info.min)).max()
    err = err_fun(yd, ys)
    eps = err_tol / err
    pow = 1. / 3
    ok = eps >= 1
    if eps >= 1:
        h_next = h * min(0.9 * eps**pow, 10)
    else:
        h_next = h * max(0.9 * eps**pow, 0.1)
    return yd, ok, h_next, None, None, h, False
Exemplo n.º 2
0
def spectrogram(t, sign, Et, Gt, omega, bound_cond='pad'):
    assert bound_cond in ('pad', 'odd-cyclic', 'cyclic')
    if not type(Gt) == np.array:
        nG = Gt
        ga = np.arange(nG) - (nG - 1.0) / 2
        Gt = np.exp(-(5 * ga / nG)**2)
#            plt.figure()
#            plt.plot(ga,Gt)
    else:
        nG = Gt.size
    Dt = t[1] - t[0]
    t_G = np.arange(nG) * Dt
    if bound_cond == 'pad':
        t, Et = usv.pad_sampled(t, Et, nG, nG)
    omega_s = conj_axis(t_G, omega[0], 'start')
    ft = FTD(sign, x=t_G, k=omega_s)
    if bound_cond in ('cyclic', 'odd-cyclic'):
        tsis = np.arange(t.size) - int(nG / 2)
    else:
        tsis = np.arange(t.size - Gt.size)
    t_s = t[0] + (tsis + nG / 2) * Dt
    S = np.zeros((omega_s.size, t_s.size))
    for tsii in range(len(tsis)):
        tsi = tsis[tsii]
        inds = np.arange(tsi, tsi + nG)
        if bound_cond == 'odd-cyclic':
            sign = (-1)**np.floor(inds / t.size)
        else:
            sign = 1
        if bound_cond in ('cyclic', 'odd-cyclic'):
            inds = inds % t.size
        S[:, tsii] = mx.abs_sqd(ft.trans(Et[inds] * Gt * sign))
    return (t_s, omega_s, S)
Exemplo n.º 3
0
Arquivo: fsq.py Projeto: draustin/otk
def refract_field_gradient(normal, k1, Er, gradxyEr1, k2, Ir=None):
    """Apply local Snell's law at an interface given derivatives of the field.

    Args:
        normal (3-tuple): arrays of surface normal components. Should have positive z component.
        k1: wavenumber in initial medium.
        Er: field.
        gradxyEr1 (2-tuple): derivatives of Er w.r.t x and y.
        k2: wavenumber in final medium.

    Returns:
        Igradphi2 (3-tuple): product of intensity |Er|^2 and gradient of phase w.r.t. coordinate axes.
        Ir: |Er|^2 (for reuse).
    """
    assert np.all(normal[2] > 0)
    assert len(gradxyEr1) == 2
    if Ir is None:
        Ir = mathx.abs_sqd(Er)

    # Calculate intensity-scaled phase gradient (3 vector).
    Igradphi = calc_Igradphi(k1, Er, gradxyEr1, Ir)

    Igradphi_tangent = mathx.project_onto_plane(Igradphi, normal)[0]
    Igradphi_normal = np.maximum((Ir * k2)**2 - mathx.dot(Igradphi_tangent),
                                 0)**0.5
    Igradphi2 = [
        tc + nc * Igradphi_normal for tc, nc in zip(Igradphi_tangent, normal)
    ]

    return Igradphi2
Exemplo n.º 4
0
Arquivo: fsq.py Projeto: draustin/otk
def calc_Igradphi(k, Er, gradxyEr, Ir=None) -> list:
    if Ir is None:
        Ir = mathx.abs_sqd(Er)

    # Calculate phase gradient times intensity.
    Igradxyphi = [(component * Er.conj()).imag for component in gradxyEr]

    # The phase gradient is the eikonal (with scalar k included). In the short wavelength approximation (geometrical optics)
    # the length of the eikonal is k. (See  Born & Wolf eq. 15b in sec. 3.1.)
    Igradzphi = np.maximum((Ir * k)**2 - matseq.dot(Igradxyphi), 0)**0.5
    Igradphi = Igradxyphi + [Igradzphi]

    return Igradphi
Exemplo n.º 5
0
    def __init__(self,
                 lamb,
                 n,
                 z,
                 rs_support,
                 Er,
                 gradxyE,
                 rs_center=(0, 0),
                 qs_center=(0, 0),
                 polarizationxy=(1, 0)):
        assert np.isscalar(z)
        Profile.__init__(self, lamb, n, z, rs_support, Er, gradxyE, rs_center,
                         qs_center, polarizationxy)
        self.z = z
        # Flat beam is beam with quadratic phase removed.
        self.Er_flat = self.Er * self.calc_quadratic_phase_factor(
            self.x, self.y).conj()
        self.Eq_flat = math.fft2(self.Er_flat)
        Iq_flat = mathx.abs_sqd(self.Eq_flat)
        sumIq_flat = Iq_flat.sum()
        self.qs_support = 2 * np.pi * np.asarray(Er.shape) / self.rs_support
        kx, ky = sa.calc_kxky(rs_support, Er.shape, qs_center)
        self.kx = kx
        self.ky = ky
        self.q_center_indices = abs(kx - qs_center[0]).argmin(), abs(
            ky - qs_center[1]).argmin()
        mean_kx_flat = mathx.moment(kx, Iq_flat, 1, sumIq_flat)
        mean_ky_flat = mathx.moment(ky, Iq_flat, 1, sumIq_flat)
        self.centroid_qs_flat = mean_kx_flat, mean_ky_flat
        var_kx_flat = mathx.moment(kx - qs_center[0], Iq_flat, 2, sumIq_flat)
        var_ky_flat = mathx.moment(ky - qs_center[1], Iq_flat, 2, sumIq_flat)

        # Calculate angular variance (of plane beam) from flat beam.
        var_kx = bvar.infer_angular_variance_spherical(self.var_rs[0],
                                                       self.phi_cs[0],
                                                       var_kx_flat)
        var_ky = bvar.infer_angular_variance_spherical(self.var_rs[1],
                                                       self.phi_cs[1],
                                                       var_ky_flat)
        self.var_qs = np.asarray((var_kx, var_ky))

        dz_waists, self.var_r_waists, self.Msqds, self.z_R = np.asarray([
            bvar.calc_waist(self.k, var_r, phi_c,
                            var_q) for var_r, phi_c, var_q in zip(
                                self.var_rs, self.phi_cs, self.var_qs)
        ]).T
        self.z_waists = dz_waists + self.z
        self.z_waist = np.mean(dz_waists) + self.z
Exemplo n.º 6
0
Arquivo: fsq.py Projeto: draustin/otk
def calc_refracted_propagation_spherical(r_support,
                                         z12,
                                         normal12,
                                         k1,
                                         Er1,
                                         gradEr1,
                                         k2,
                                         z,
                                         r1_centers=(0, 0),
                                         qs_center=(0, ),
                                         f_nexts=(np.inf, np.inf),
                                         qfds=(1, 1)):
    """Refract"""
    Ir1 = mathx.abs_sqd(Er1)
    Igradphi1 = refract_field_gradient(normal12, k1, Er1, gradEr1, k2, Ir1)
    return calc_propagation_spherical(k2, r_support, z12, Er1, z, Igradphi1,
                                      r1_centers, qs_center, f_nexts, qfds)
Exemplo n.º 7
0
 def __init__(self, omega, Ef, omega_0, Et=None, It=None, phit=None, fwhm=None, *args, **kwargs):
     super().__init__(omega=omega, *args, **kwargs)
     if Et is None:
         Et = ft.trans(self.omega, -1, Ef, self.t, AXIS_TEMP) * np.exp(1j * omega_0 * self.t)
     if It is None:
         It = mathx.abs_sqd(Et)
     if phit is None:
         phit = mathx.unwrap(np.angle(Et), abs(self.t).argmin(), axis=AXIS_TEMP)
     self.Ef = Ef
     self.omega_0 = omega_0
     self.Et = Et
     self.It = It
     self.phit = phit
     if fwhm is None:
         t_half_max = mathx.peak_crossings(self.t, self.It, 0.5, AXIS_TEMP)
         fwhm = t_half_max[1] - t_half_max[0]
     self.fwhm = fwhm
Exemplo n.º 8
0
 def to_mode(key):
     mode = modes[key]
     polarization = self.frame[0, :]
     new_polarization = np.einsum('...i, ...ij', polarization,
                                  mode.matrix)
     pol_Er_factor = (v4hb.dot(new_polarization)**0.5).reshape(
         self.profile.Er.shape)
     # Take mean polarization.
     new_polarization = v4hb.normalize((new_polarization.reshape(
         (-1, 4)) * mathx.abs_sqd(self.profile.Er).reshape(
             (-1, 1))).sum(axis=0))
     Er_factor = pol_Er_factor * (mode.n / self.profile.n)**0.5
     if mode.direction == rt1.Directions.TRANSMITTED:
         return self.refract(normal, mode.n, Er_factor,
                             new_polarization)
     else:
         return self.reflect(normal, mode.n, Er_factor,
                             new_polarization)
Exemplo n.º 9
0
Arquivo: fsq.py Projeto: draustin/otk
def propagate_curved_to_plane_spherical(k,
                                        rs_support,
                                        Eri,
                                        z,
                                        ms,
                                        ri_centers=(0, 0),
                                        qs_center=(0, 0),
                                        ro_centers=None,
                                        kz_mode='local_xy',
                                        max_iterations=None,
                                        tol=None):
    """

    Args:
        k:
        rs_support:
        Eri:
        zx:
        ms:
        ri_centers:
        qs_center:
        zy:
        ro_centers:
        max_iterations:
        tol:

    Returns:

    """
    assert kz_mode in ('local_xy', 'paraxial')
    if ro_centers is None:
        Iri = mathx.abs_sqd(Eri)
        sumIri = Iri.sum()
        z_center = mathx.moment(z, Iri, 1, sumIri)
        ro_centers = math.adjust_r(k, ri_centers, z, qs_center,
                                   kz_mode)  # TODO should be z_center?
    Ero, propagator = invert_plane_to_curved_spherical(k, rs_support * ms, Eri,
                                                       -z, 1 / ms, ro_centers,
                                                       qs_center, ri_centers,
                                                       kz_mode, max_iterations,
                                                       tol)
    return Ero
Exemplo n.º 10
0
    def mask(self, f: np.ndarray, gradxyf: tuple, n: float = None):
        """Return self with real-space mask applied.

        Args:
            f: Mask amplitude sampled at same points as self.Er.
            gradxyf: Mask gradients along x and y.
            n: New refractive index (defaults to self.n).
        """
        Er = self.Er * f
        gradxyE = [
            gradE * f + self.Er * gradf
            for gradE, gradf in zip(self.gradxyE, gradxyf)
        ]
        Ir = mathx.abs_sqd(Er)
        Igradphi = fsq.calc_Igradphi(self.k, Er, gradxyE, Ir)
        # Mean transverse wavenumber is intensity-weighted average of transverse gradient of phase.
        qs_center = np.asarray([component.sum()
                                for component in Igradphi[:2]]) / Ir.sum()

        return self.change(Er=Er, gradxyE=gradxyE, n=n, qs_center=qs_center)
Exemplo n.º 11
0
Arquivo: fsq.py Projeto: draustin/otk
def calc_propagation_spherical(k,
                               r_support,
                               zi,
                               Er,
                               z,
                               Igradphi=None,
                               rs_center=(0, 0),
                               qs_center=(0, 0),
                               f_nexts=(np.inf, np.inf),
                               qfds=(1, 1)):
    assert np.isscalar(z)

    Ir = mathx.abs_sqd(Er)

    if Igradphi is None:
        Ek = math.fft2(Er)
        kx, ky = sa.calc_kxky(r_support, Ek.shape, qs_center)
        gradxEx = math.ifft2(Ek * 1j * kx)
        gradyEy = math.ifft2(Ek * 1j * ky)
        Igradphi = calc_Igradphi(k, Er, (gradxEx, gradyEy), Ir)

    zi_mean, rs_center, var_rs, qs_center, var_qs, phi_cs = calc_beam_properties(
        k, r_support, zi, Er, Igradphi, rs_center)

    if isinstance(z, str) and z == 'waist':
        return_z = True
        z, var_r0, Msqd, z_R = bvar.calc_waist(k, var_rs, phi_cs, var_qs)
        z = np.mean(z)
    else:
        return_z = False

    m = bvar.calc_propagation_ms(k, r_support, var_rs, phi_cs, var_qs,
                                 z - zi_mean, Er.shape, f_nexts, qfds)

    if return_z:
        return m, z, rs_center, qs_center, zi_mean, rs_center + qs_center / k * (
            z - zi_mean)
    else:
        return m, rs_center, qs_center, zi_mean, rs_center + qs_center / k * (
            z - zi_mean)
Exemplo n.º 12
0
    def __init__(self,
                 lamb: float,
                 n: float,
                 z_center: float,
                 rs_support,
                 Er,
                 gradxyE,
                 rs_center=(0, 0),
                 qs_center=(0, 0),
                 polarizationxy=(1, 0)):
        self.lamb = float(lamb)
        self.n = float(n)
        self.z_center = float(z_center)
        rs_support = sa.to_scalar_pair(rs_support)
        assert (rs_support > 0).all()
        self.rs_support = rs_support
        Er = np.asarray(Er).astype(complex)
        self.Er = Er
        assert not np.isnan(Er).any()
        assert len(gradxyE) == 2
        self.gradxyE = gradxyE
        self.rs_center = sa.to_scalar_pair(rs_center)
        self.qs_center = sa.to_scalar_pair(qs_center)

        self.Eq = math.fft2(Er)
        self.k = 2 * np.pi * self.n / self.lamb

        self.Ir = mathx.abs_sqd(Er)
        sumIr = self.Ir.sum()
        if np.isclose(sumIr, 0):
            raise NullProfileError()
        self.Igradphi = fsq.calc_Igradphi(self.k, Er, gradxyE, self.Ir)
        x, y = sa.calc_xy(rs_support, Er.shape, rs_center)
        self.x = x
        self.y = y
        self.r_center_indices = abs(x - rs_center[0]).argmin(), abs(
            y - rs_center[1]).argmin()
        self.delta_x, self.delta_y = self.rs_support / Er.shape
        self.power = sumIr * self.delta_x * self.delta_y
        mean_x = mathx.moment(x, self.Ir, 1, sumIr)
        mean_y = mathx.moment(y, self.Ir, 1, sumIr)
        self.centroid_rs = mean_x, mean_y
        var_x = mathx.moment(x - rs_center[0], self.Ir, 2, sumIr)
        var_y = mathx.moment(y - rs_center[1], self.Ir, 2, sumIr)
        self.var_rs = np.asarray((var_x, var_y))

        # Calculate phase of quadratic component at RMS distance from center. Proportional to A in Siegman IEE J. Quantum Electronics Vol. 27
        # 1991. Positive means diverging.
        phi_cx = 0.5 * (
            (x - rs_center[0]) *
            (self.Igradphi[0] - self.Ir * qs_center[0])).sum() / sumIr
        phi_cy = 0.5 * (
            (y - rs_center[1]) *
            (self.Igradphi[1] - self.Ir * qs_center[1])).sum() / sumIr
        self.phi_cs = np.asarray((phi_cx, phi_cy))
        self.rocs = mathx.divide0(self.k * self.var_rs, 2 * self.phi_cs,
                                  np.inf)

        xi, yi = np.unravel_index(self.Ir.argmax(), self.Ir.shape)
        self.peak_indices = xi, yi
        self.peak_Er = self.Er[xi, yi]
        self.peak_rs = np.asarray((self.x[xi], self.y[yi]))
        self.peak_qs = np.asarray([
            mathx.divide0((gradxE[xi, yi] * Er[xi, yi].conj()).imag,
                          self.Ir[xi, yi]) for gradxE in gradxyE
        ])

        self.kz_center = math.calc_kz(self.k, *self.qs_center)

        # Calculate 3D vectors.
        vector_center = v4hb.normalize(
            v4hb.stack_xyzw(*self.qs_center, self.kz_center, 0))
        polarizationz = -(polarizationxy *
                          vector_center[:2]).sum() / vector_center[2]
        origin_center = v4hb.stack_xyzw(*self.rs_center, self.z_center, 1)
        polarization = polarizationxy[0], polarizationxy[1], polarizationz, 0
        y = v4hb.cross(vector_center, polarization)
        self.frame = np.c_[polarization, y, vector_center, origin_center].T
Exemplo n.º 13
0
 def norm(self, E, conj=False):
     sc = self.Dk if conj else self.Dx
     return np.sum(mx.abs_sqd(E), axis=self.axis, keepdims=True) * sc
Exemplo n.º 14
0
Arquivo: fsq.py Projeto: draustin/otk
def propagate_arbitrary_curved_to_plane_spherical(k,
                                                  xi,
                                                  yi,
                                                  Eri,
                                                  roc_xi,
                                                  roc_yi,
                                                  zi,
                                                  ro_supports,
                                                  num_pointsso,
                                                  ri_centers=(0, 0),
                                                  qs_center=(0, 0),
                                                  ro_centers=None,
                                                  kz_mode='local_xy',
                                                  invert_kwargs=None):
    """

    Args:
        k:
        xi (Mx1 array):
        yi (N array):
        Eri (MxN array):
        roc_x (M*N array): Input radius of curvature along x.
        roc_y (M*N array): Input radius of curvature along y.
        zi (MxN array):
        ro_supports:
        num_pointsso:
        ri_centers:
        qs_center:
        ro_centers:
        kz_mode:
        invert_kwargs:

    Returns:
        Ero (array of size num_pointsso):
    """
    assert xi.shape == (Eri.shape[0], 1)
    assert yi.shape == (Eri.shape[1], )
    assert Eri.ndim == 2
    assert roc_xi.shape == Eri.shape
    assert roc_yi.shape == Eri.shape
    assert zi.shape == Eri.shape

    if ro_centers is None:
        z_center = mathx.moment(zi, mathx.abs_sqd(Eri), 1)
        ro_centers = math.adjust_r(k, ri_centers, z_center, qs_center, kz_mode)

    z = -zi
    roc_x = roc_xi + zi
    roc_y = roc_yi + zi
    Ero, propagator = invert_plane_to_curved_spherical_arbitrary(
        k, ro_supports, num_pointsso, Eri, z, xi, yi, roc_x, roc_y, ro_centers,
        qs_center, ri_centers, kz_mode, invert_kwargs)

    return Ero


# def propagate_plane_to_waist_spherical_paraxial(k, rs_support, Er, z, rs_center = (0, 0), qs_center = (0, 0), rocs = np.inf):
#     rs_support = to_pair(rs_support)
#     rocs = to_pair(rocs)
#     rs_center = np.asarray(rs_center)
#     qs_center = np.asarray(qs_center)
#     num_pointss = Er.shape[-2:]
#     ms_flat, zs_flat, ms = np.asarray([calc_curved_propagation(k, r_support, num_points, roc, z) for r_support, num_points, roc in zip(rs_support, num_pointss, rocs)]).T
#     Er_flat, r_centers_flat = propagate_plane_to_plane_spherical_paraxial(k, rs_support, Er, -zs_flat, 1/ms_flat, rs_center, qs_center, carrier = False)
#     return Er_flat, zs_flat, ms_flat, ms, r_centers_flat
#
# def propagate_plane_to_plane_spherical(k, rs_support, Er, z, rs_center = (0, 0), qs_center = (0, 0), rocs = np.inf):
#     rs_support = to_pair(rs_support)
#     rs_center = np.asarray(rs_center)
#     qs_center = np.asarray(qs_center)
#     rocs = to_pair(rocs)
#     num_pointss = Er.shape[-2:]
#     Er_flat, zs_flat, ms_flat, ms, r_centers_flat = propagate_plane_to_waist_spherical_paraxial(k, rs_support, Er, z, rs_center, qs_center, rocs)
#     r_supports_flat = rs_support/ms_flat
#
#     # See Dane's notebook 2 p105.
#     denominator = (k**2-qs_center[0]**2-qs_center[1]**2)**(3/2)
#     z_paraxial_x = z*k*(k**2-qs_center[1]**2)/denominator
#     z_paraxial_y = z*k*(k**2-qs_center[0]**2)/denominator
#     zs_paraxial = np.asarray((z_paraxial_x, z_paraxial_y))
#
#     kx_flat, ky_flat = [calc_q(r_support_flat, num_points, q_center, axis) for r_support_flat, num_points, q_center, axis in zip(r_supports_flat, num_pointss, qs_center, (-2, -1))]
#     extra_propagator = mathx.expj(calc_kz(k, kx_flat, ky_flat)*z+z_paraxial_x*kx_flat**2/(2*k)+z_paraxial_y*ky_flat**2/(2*k))
#
#     Eq_flat = fft2(Er_flat)
#     Eq_flat *= extra_propagator
#     Er_flat = ifft2(Eq_flat)
#
#     Er, _ = propagate_plane_to_plane_spherical_paraxial(k, r_supports_flat, Er_flat, zs_paraxial+zs_flat, ms*ms_flat, r_centers_flat, qs_center, carrier = False)
#     rp_centers = rs_center+z*qs_center/(k**2-qs_center**2)**0.5
#
#     return Er, ms, rp_centers
Exemplo n.º 15
0
Arquivo: fsq.py Projeto: draustin/otk
def calc_beam_properties(rs_support, z, Er, Igradphi, rs_center=(0, 0)):
    """Calculate real space and angular centroids, and curvature.

    Assumes that propagation is to +z. Positive ROC means diverging i.e. center of curvature is to left.

    Args:
        k:
        x:
        y:
        Er:
        Igradphi (tuple): I times gradient of phase along the x, y and z.
        rs_center:
        Ir:

    Returns:

    """
    x, y = sa.calc_xy(rs_support, Er.shape, rs_center)
    Ir = mathx.abs_sqd(Er)
    sumIr = Ir.sum()

    # Calculate centroid. Improve the input estimate rs_center.
    rs_center[0], rs_center[1], varx, vary, _ = mathx.mean_and_variance2(
        x, y, Ir, sumIr)

    # Mean transverse wavenumber is intensity-weighted average of transverse gradient of phase.
    qs_center = np.asarray([component.sum()
                            for component in Igradphi[:2]]) / sumIr

    meanz = mathx.moment(z, Ir, 1, sumIr)

    # Correct spatial phase for surface curvature - approximate propagation from z to meanz.
    Er = Er * mathx.expj((meanz - z) * mathx.divide0(Igradphi[2], Ir))

    # Do this twice, since on the first pass we are using qs_center from Igradphi which is just an estimate.
    for _ in range(2):
        # Calculate phase of quadratic component at RMS distance from center. Proportional to A in Siegman IEE J. Quantum Electronics Vol. 27
        # 1991. Positive means diverging.
        phi_cx = 0.5 * ((x - rs_center[0]) *
                        (Igradphi[0] - Ir * qs_center[0])).sum() / sumIr
        phi_cy = 0.5 * ((y - rs_center[1]) *
                        (Igradphi[1] - Ir * qs_center[1])).sum() / sumIr

        # Fourier transform Er with quadratic phase removed.
        Ek = math.fft2(Er *
                       mathx.expj(-(x - rs_center[0])**2 * phi_cx / varx) *
                       mathx.expj(-(y - rs_center[1])**2 * phi_cy / vary))
        kx, ky = sa.calc_kxky(rs_support, Er.shape, qs_center)

        # Calculate mean square sizes of Fourier transform with quadratic phase removed.
        #qs_center[0], qs_center[1], varkxp, varkyp, _ = mathx.mean_and_variance2(kx, ky, mathx.abs_sqd(Ek))
        qs_center[0] = mathx.moment(kx, abs(Ek), 1)
        qs_center[1] = mathx.moment(ky, abs(Ek), 1)

        Ik = mathx.abs_sqd(Ek)
        sumIk = Ik.sum()
        varkxp = mathx.moment(kx - qs_center[0], Ik, 2, sumIk)
        varkyp = mathx.moment(ky - qs_center[1], Ik, 2, sumIk)

        # Calculate angular variance.
        varkx = bvar.infer_angular_variance_spherical(varx, phi_cx, varkxp)
        varky = bvar.infer_angular_variance_spherical(vary, phi_cy, varkyp)

    return meanz, rs_center, np.asarray((varx, vary)), qs_center, np.asarray(
        (varkx, varky)), np.asarray((phi_cx, phi_cy))