def fowler_array(fowlerdata, ti=0.0, ts=0.0, gain=1.0, ron=1.0,
                 badpixels=None, dtype='float64',
                 saturation=65631, blank=0, normalize=False):
    import numina.array._nirproc as _nirproc
    if gain <= 0:
        raise ValueError("invalid parameter, gain <= 0.0")
    if ron <= 0:
        raise ValueError("invalid parameter, ron < 0.0")
    if ti < 0:
        raise ValueError("invalid parameter, ti < 0.0")
    if ts < 0:
        raise ValueError("invalid parameter, ts < 0.0")
    if saturation <= 0:
        raise ValueError("invalid parameter, saturation <= 0")
    fowlerdata = numpy.asarray(fowlerdata)
    if fowlerdata.ndim != 3:
        raise ValueError('fowlerdata must be 3D')
    npairs = fowlerdata.shape[0] // 2
    if 2 * npairs != fowlerdata.shape[0]:
        raise ValueError('axis-0 in fowlerdata must be even')
    ndtype = fowlerdata.dtype.newbyteorder('=')
    fowlerdata = numpy.asarray(fowlerdata, dtype=ndtype)
    fdtype = numpy.result_type(fowlerdata.dtype, dtype)
    mdtype = numpy.dtype('uint8')
    fshape = (fowlerdata.shape[1], fowlerdata.shape[2])
    if badpixels is None:
        badpixels = numpy.zeros(fshape, dtype=mdtype)
    else:
        if badpixels.shape != fshape:
            raise ValueError('shape of badpixels is not '
                             'compatible with shape of fowlerdata')
        if badpixels.dtype != mdtype:
            raise ValueError('dtype of badpixels must be uint8')
    result = numpy.empty(fshape, dtype=fdtype)
    var = numpy.empty_like(result)
    npix = numpy.empty(fshape, dtype=mdtype)
    mask = badpixels.copy()
    _nirproc._process_fowler_intl(
        fowlerdata, ti, ts,  gain, ron,
        badpixels, saturation, blank,
        result, var, npix, mask
    )
    return result, var, npix, mask