<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def sine_psd(data, delta, number_of_tapers=None, number_of_iterations=2, degree_of_smoothing=1.0, statistics=False, verbose=False):
 """ Wrapper method for the sine_psd subroutine in the library by German A. Prieto. The subroutine is in charge of estimating the adaptive sine multitaper as in Riedel and Sidorenko (1995). It outputs the power spectral density (PSD). This is done by performing a MSE adaptive estimation. First a pilot spectral estimate is used, and S" is estimated, in order to get te number of tapers to use, using (13) of Riedel and Sidorenko for a min square error spectrum. Unlike the prolate spheroidal multitapers, the sine multitaper adaptive process introduces a variable resolution and error in the frequency domain. Complete error information is contained in the output variables as the corridor of 1-standard-deviation errors, and in the number of tapers used at each frequency. The errors are estimated in the simplest way, from the number of degrees of freedom (two per taper), not by jack-knifing. The frequency resolution is found from K*fN/Nf where fN is the Nyquist frequency and Nf is the number of frequencies estimated. The adaptive process used is as follows. A quadratic fit to the log PSD within an adaptively determined frequency band is used to find an estimate of the local second derivative of the spectrum. This is used in an equation like R & S (13) for the MSE taper number, with the difference that a parabolic weighting is applied with increasing taper order. Because the FFTs of the tapered series can be found by resampling the FFT of the original time series (doubled in length and padded with zeros) only one FFT is required per series, no matter how many tapers are used. This makes the program fast. Compared with the Thomson multitaper programs, this code is not only fast but simple and short. The spectra associated with the sine tapers are weighted before averaging with a parabolically varying weight. The expression for the optimal number of tapers given by R & S must be modified since it gives an unbounded result near points where S" vanishes, which happens at many points in most spectra. This program restricts the rate of growth of the number of tapers so that a neighboring covering interval estimate is never completely contained in the next such interval. This method SHOULD not be used for sharp cutoffs or deep valleys, or small sample sizes. Instead use Thomson multitaper in mtspec in this same library. :param data: :class:`numpy.ndarray` Array with the data. :param delta: float Sample spacing of the data. :param number_of_tapers: integer/None, optional Number of tapers to use. If none is given, the library will perform an adaptive taper estimation with a varying number of tapers for each frequency. Defaults to None. :param number_of_iterations: integer, optional Number of iterations to perform. Values less than 2 will be set to 2. Defaults to 2. :param degree_of_smoothing: float, optional Degree of smoothing. Defaults to 1.0. :param statistics: bool, optional Calculates and returns statistics. See the notes in the docstring for further details. :param verbose: bool, optional Passed to the fortran library. Defaults to False. :return: Returns a list with :class:`numpy.ndarray`. See the note below for details. .. note:: This method will at return at least two arrays: The calculated spectrum and the corresponding frequencies. If statistics is True is will also return (in the given order) (multidimensional) arrays containing the 1-std errors (a simple dof estimate) and the number of tapers used for each frequency point. """

    # Verbose mode on or off.
    if verbose is True:
        verbose = C.byref(C.c_char('y'))
    else:
        verbose = None
    # Set the number of tapers so it can be read by the library.
    if number_of_tapers is None:
        number_of_tapers = 0
    # initialize _MtspecType to save some space
    mt = _MtspecType("float32")
    # Transform the data to work with the library.
    data = np.require(data, dtype=mt.float, requirements=[mt.order])
    # Some variables necessary to call the library.
    npts = len(data)
    number_of_frequency_bins = int(npts / 2) + 1
    # Create output arrays.
    frequency_bins = mt.empty(number_of_frequency_bins)
    spectrum = mt.empty(number_of_frequency_bins)
    # Create optional arrays or set to None.
    if statistics is True:
        # here an exception, mt sets the type float32, here we need int32
        # that is do all the type and POINTER definition once by hand
        tapers_per_freq_point = np.empty(number_of_frequency_bins,
                                         dtype='int32', order=mt.order)
        tapers_per_freq_point_p = \
            tapers_per_freq_point.ctypes.data_as(C.POINTER(C.c_int))
        errors = mt.empty((number_of_frequency_bins, 2))
    else:
        tapers_per_freq_point_p = errors = None
    # Call the library. Fortran passes pointers!
    mtspeclib.sine_psd_(
        C.byref(C.c_int(npts)),
        C.byref(C.c_float(delta)), mt.p(data),
        C.byref(C.c_int(number_of_tapers)),
        C.byref(C.c_int(number_of_iterations)),
        C.byref(C.c_float(degree_of_smoothing)),
        C.byref(C.c_int(number_of_frequency_bins)),
        mt.p(frequency_bins), mt.p(spectrum),
        tapers_per_freq_point_p, mt.p(errors), verbose)
    # Calculate return values.
    return_values = [spectrum, frequency_bins]
    if statistics is True:
        return_values.extend([errors, tapers_per_freq_point])
    return return_values