Loop over the first axis applying ramp processing.

    *rampdata* is assumed to be a 3D numpy.ndarray containing the
    result of a nIR observation in folow-up-the-ramp mode.
    The shape of the array must be of the form N_s x M x N, with N_s being
    the number of samples.

    :param fowlerdata: Convertible to a 3D numpy.ndarray
    :param ti: Integration time.
    :param gain: Detector gain.
    :param ron: Detector readout noise in counts.
    :param badpixels: An optional MxN mask of dtype 'uint8'.
    :param dtype: The dtype of the float outputs.
    :param saturation: The saturation level of the detector.
    :param blank: Invalid values in output are substituted by *blank*.
    :returns: A tuple of signal, variance of the signal, numper of pixels used
        and badpixel mask.
    :raises: ValueError

def ramp_array(rampdata, ti, gain=1.0, ron=1.0,
               badpixels=None, dtype='float64',
               saturation=65631, blank=0, nsig=None, normalize=False):
    """Loop over the first axis applying ramp processing.

    *rampdata* is assumed to be a 3D numpy.ndarray containing the
    result of a nIR observation in folow-up-the-ramp mode.
    The shape of the array must be of the form N_s x M x N, with N_s being
    the number of samples.

    :param fowlerdata: Convertible to a 3D numpy.ndarray
    :param ti: Integration time.
    :param gain: Detector gain.
    :param ron: Detector readout noise in counts.
    :param badpixels: An optional MxN mask of dtype 'uint8'.
    :param dtype: The dtype of the float outputs.
    :param saturation: The saturation level of the detector.
    :param blank: Invalid values in output are substituted by *blank*.
    :returns: A tuple of signal, variance of the signal, numper of pixels used
        and badpixel mask.
    :raises: ValueError
    """

    import numina.array._nirproc as _nirproc
    if ti <= 0:
        raise ValueError("invalid parameter, ti <= 0.0")

    if gain <= 0:
        raise ValueError("invalid parameter, gain <= 0.0")

    if ron <= 0:
        raise ValueError("invalid parameter, ron < 0.0")

    if saturation <= 0:
        raise ValueError("invalid parameter, saturation <= 0")

    rampdata = numpy.asarray(rampdata)
    if rampdata.ndim != 3:
        raise ValueError('rampdata must be 3D')

    # change byteorder
    ndtype = rampdata.dtype.newbyteorder('=')
    rampdata = numpy.asarray(rampdata, dtype=ndtype)
    # type of the output
    fdtype = numpy.result_type(rampdata.dtype, dtype)
    # Type of the mask
    mdtype = numpy.dtype('uint8')
    fshape = (rampdata.shape[1], rampdata.shape[2])

    if badpixels is None:
        badpixels = numpy.zeros(fshape, dtype=mdtype)
    else:
        if badpixels.shape != fshape:
            msg = 'shape of badpixels is not compatible with shape of rampdata'
            raise ValueError(msg)
        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_ramp_intl(
        rampdata, ti, gain, ron, badpixels,
        saturation, blank, result, var, npix, mask
    )
    return result, var, npix, mask