o
    װi>                     @   s   d dl Z d dlmZ d dlmZ d dlmZ d dlmZm	Z	m
Z
 d dlmZmZ dZe jedd	d
 dD dd
 dD  dZdd Zd ddZd!ddZd"ddZdd Zdd Zd!ddZd"ddZdS )#    N)get_typename)_normalize_axis_index)lfilter)
axis_sliceaxis_assignaxis_reverse)collapse_2dapply_iir_sosaj
  
#include <cupy/math_constants.h>
#include <cupy/carray.cuh>

template<typename T>
__device__ T _compute_symiirorder2_fwd_hc(
        const int k, const T cs, const T r, const T omega) {
    T base;

    if(k < 0) {
        return 0;
    }

    if(omega == 0.0) {
        base = cs * pow(r, ((T) k)) * (k + 1);
    } else if(omega == M_PI) {
        base = cs * pow(r, ((T) k)) * (k + 1) * (1 - 2 * (k % 2));
    } else {
        base = (cs * pow(r, ((T) k)) * sin(omega * (k + 1)) /
                sin(omega));
    }
    return base;
}

template<typename T>
__global__ void compute_symiirorder2_fwd_sc(
        const int n, const int off, const T* cs_ptr, const T* r_ptr,
        const T* omega_ptr, const double precision, bool* valid, T* out) {

    int idx = blockDim.x * blockIdx.x + threadIdx.x;
    if(idx + off >= n) {
        return;
    }

    const T cs = cs_ptr[0];
    const T r = r_ptr[0];
    const T omega = omega_ptr[0];

    T val = _compute_symiirorder2_fwd_hc<T>(idx + off + 1, cs, r, omega);
    T err = val * val;

    out[idx] = val;
    valid[idx] = err <= precision;
}

template<typename T>
__device__ T _compute_symiirorder2_bwd_hs(
        const int ki, const T cs, const T rsq, const T omega) {
    T c0;
    T gamma;

    T cssq = cs * cs;
    int k = abs(ki);
    T rsupk = pow(rsq, ((T) k) / ((T) 2.0));


    if(omega == 0.0) {
        c0 = (1 + rsq) / ((1 - rsq) * (1 - rsq) * (1 - rsq)) * cssq;
        gamma = (1 - rsq) / (1 + rsq);
        return c0 * rsupk * (1 + gamma * k);
    }

    if(omega == M_PI) {
        c0 = (1 + rsq) / ((1 - rsq) * (1 - rsq) * (1 - rsq)) * cssq;
        gamma = (1 - rsq) / (1 + rsq) * (1 - 2 * (k % 2));
        return c0 * rsupk * (1 + gamma * k);
    }

    c0 = (cssq * (1.0 + rsq) / (1.0 - rsq) /
                (1 - 2 * rsq * cos(2 * omega) + rsq * rsq));
    gamma = (1.0 - rsq) / (1.0 + rsq) / tan(omega);
    return c0 * rsupk * (cos(omega * k) + gamma * sin(omega * k));
}

template<typename T>
__global__ void compute_symiirorder2_bwd_sc(
        const int n, const int off, const int l_off, const int r_off,
        const T* cs_ptr, const T* rsq_ptr, const T* omega_ptr,
        const double precision, bool* valid, T* out) {

    int idx = blockDim.x * blockIdx.x + threadIdx.x;
    if(idx + off >= n) {
        return;
    }

    const T cs = cs_ptr[0];
    const T rsq = rsq_ptr[0];
    const T omega = omega_ptr[0];

    T v1 = _compute_symiirorder2_bwd_hs<T>(idx + l_off + off, cs, rsq, omega);
    T v2 = _compute_symiirorder2_bwd_hs<T>(idx + r_off + off, cs, rsq, omega);

    T diff = v1 + v2;
    T err = diff * diff;
    out[idx] = diff;
    valid[idx] = err <= precision;
}
)z
-std=c++11c                 C      g | ]}d | dqS )zcompute_symiirorder2_bwd_sc<> .0tr   r   O/home/ubuntu/.local/lib/python3.10/site-packages/cupyx/scipy/signal/_splines.py
<listcomp>q       r   )floatdoublec                 C   r
   )zcompute_symiirorder2_fwd_sc<r   r   r   r   r   r   r   s   r   )codeoptionsname_expressionsc                 G   s>   dd |D }d |}|r| d| dn|}| |}|S )Nc                 S   s   g | ]}t |jqS r   )r   dtype)r   argr   r   r   r   x   s    z$_get_module_func.<locals>.<listcomp>z, <r   )joinget_function)module	func_nametemplate_argsargs_dtypestemplatekernel_namekernelr   r   r   _get_module_funcw   s
   

r$   c              
   C   sb   t | d d | }t j}|jdkr/t |d |kt jt||d d | |d | |d}|S )Nr      axis)cupywherenansizer   )	all_validcum_polynoffr(   indiceszir   r   r   _find_initial_cond   s   
r3         c                 C   s|  t || j}| j}| j}| jdkrt| |\} }t|dkr#td|dks+|dkrM| jttju r7d}n| jttj	u rCd}n
dt
| jj  }||9 }tjd|d d | jd	}|| }|t| }	tj||  dd
t| dddd
 }
|	|k}t||
|d }tt|rtdd}|dkrd| jd df}tj|| jd	}t||dd}tjdddd| df }t|}tt| d||| jdd\}}tj||f }| |d  t|d }t||dd}tj|ddd| df }t|}tt|ddd||| jd\}}|dkrtjt||f }n	tjt||f }|dkr<||}t|d|}|jjs<| }|S )Nr&   |z1| must be less than 1.0              ?ư>gMbP?
   r%   r   r'   r   ;Sum to find symmetric boundary conditions did not converge.r&      r=      F)r2   r   	apply_firstepr2   r   )r   ndimshaper   r)   abs
ValueErrorr   float64float32finfoiexparange	conjugatecumsumr   r3   anyisnanzerosr   r_
atleast_2dr	   c_r   reshapemoveaxisflagsc_contiguouscopy)inputc0z1	precisionr(   input_shape
input_ndimpospow_z1diffr.   r-   r2   zi_shapeall_zicoefy1_outr   r   r   _symiirorder1_nd   sn   








ri   c                 C   s  t |g| j}t |g| j}t |dkrtd|dks#|dkr*t | jj}||9 }t jd| jd | jd}|| }|t 	| }t 
||  | d  }||k}t||| j}	t |	rdtdt jd| f }
|
| j}
tt jd| jd|
| dd |	d	\}}t j|	|f }| |d  |d
  }	t jd| f }
|
| j}
t||
|dd
 ddd
 |	d	\}}t j|ddd
 |	f S )aR  
    Implement a smoothing IIR filter with mirror-symmetric boundary conditions
    using a cascade of first-order sections.  The second section uses a
    reversed sequence.  This implements a system with the following
    transfer function and mirror-symmetric boundary conditions::

                           c0
           H(z) = ---------------------
                   (1-z1/z) (1 - z1 z)

    The resulting signal will have mirror symmetric boundary conditions
    as well.

    Parameters
    ----------
    input : ndarray
        The input signal.
    c0, z1 : scalar
        Parameters in the transfer function.
    precision :
        Specifies the precision for calculating initial conditions
        of the recursive filter based on mirror-symmetric input.

    Returns
    -------
    output : ndarray
        The filtered signal.
    r&   r5   r6   r7   r:   r   r;   Nr2   r%   )r)   asarrayr   rF   rG   rJ   
resolutionrL   r,   rM   rN   r3   rP   rR   astyper   ones)rZ   r[   r\   r]   r`   ra   rb   r.   r-   r2   arf   rg   rh   r   r   r   symiirorder1   s8   

&rp   c                 C   s   d }|dkr|t ||  | d  }n0|t jkr-|t ||  | d  dd| d    }n|t ||  t || d   t | }t | dk d|S )Nr6   r&      r   )r)   powerpisinr*   )kcsromegabaser   r   r   _compute_symiirorder2_fwd_hc  s   
* rz   c                 C   sL  || }t | } t || d }|dkr9d| d| d|  d|   | }d| d|  }|| d||    S |t jkrjd| d| d|  d|   | }d| d|  dd| d    }|| d||    S |d|  d|  dd| t d|   ||   }d| d|  t | }|| t ||  |t ||     S )Ng       @r6   r&   rq   r7   )r)   rF   rr   rs   costanrt   )ru   rv   rsqrx   cssqrsupkr[   gammar   r   r   _compute_symiirorder2_bwd_hs&  s    
$
$  (r   c                  C   sb  |dkrt d|dks|dkr2| jttju rd}n| jttju r(d}n
dt| jj  }t|| j}| j	}| j}| jdkrJt
| |\} }d}|| }d	| t| }	| }
tdd	| t|  | }t||j}t||j}t||j}||9 }ttd
|}tj|d f|jd}tj|d ftjd}tjd	| jd}t||||}tj}tj}td| j	d d	 |D ]}|d|d f| j	d d	 |||||||f t| ||| }|d d d |j	d  }|dd  d |j	d  }t|r)tj|| dd|d t| dd  }t|d d d |j	d  || j	d |}t|ratj|| dd|d t| dd	  |d t| dd  }t|dd  d |j	d  || j	d |}tttj||f sq nqtttj||f rt dd}|dkrd| j	d df}ttj|ddd|	 |
 f }|| j}tj|| jd}t||d	d}t||dd}t t| d	||| jd\}}|dkrtj!|||f }ntj|||f }ttd|}tj|f|jd}tj|ftjd}t"| }tj}td| j	d d |D ]W}|d|f| j	d d |dd|t||jt||j|||f
 t|||| }tj|d |j	d  | dd}t|d |j	d  || j	d |}tt|sc nqtt|rrt dtj}td| j	d d |D ]Q}|d|f| j#d |dd	|t||jt||j|||f
 t|||| }tj|d |j	d  | dd}t|d |j# || j#|}tt|s nqtt|rt dt||d	d}t||dd}t t|ddd||d\}}|dkrtj!t"|||f }n
tjt"|||f }|dkr/|$|}t%|d|}|j&j's/|( }|S )Nr7   zr must be less than 1.0r6   gdy=r8   r9   r&      rq   compute_symiirorder2_fwd_scr:   r   r%   )r&   r'   r;   r<   r=   r>   rC   compute_symiirorder2_bwd_scrA   rj   ))rG   r   r)   rH   rI   rJ   rK   r   rD   rE   r   r{   
atleast_1drk   r$   SYMIIR2_MODULEemptybool_rL   rz   r+   ranger   rP   rN   r3   rO   rR   rS   rm   rQ   r   r	   rT   r   r,   rU   rV   rW   rX   rY   ) rZ   rw   rx   r]   r(   r^   r_   block_szr}   a2a3rv   r   rb   r-   starting_diffy0rf   iinput_slicediff_y0diff_y1cum_poly_y0cum_poly_y1rc   sosrd   y_fwdrg   r   	rev_inputrh   r   r   r   _symiirorder2_nd;  s  
 



 

 



r   c                 C   s   t | |||S )ak  
    Implement a smoothing IIR filter with mirror-symmetric boundary conditions
    using a cascade of second-order sections.  The second section uses a
    reversed sequence.  This implements the following transfer function::

                                  cs^2
         H(z) = ---------------------------------------
                (1 - a2/z - a3/z^2) (1 - a2 z - a3 z^2 )

    where::

          a2 = 2 * r * cos(omega)
          a3 = - r ** 2
          cs = 1 - 2 * r * cos(omega) + r ** 2

    Parameters
    ----------
    input : ndarray
        The input signal.
    r, omega : float
        Parameters in the transfer function.
    precision : float
        Specifies the precision for calculating initial conditions
        of the recursive filter based on mirror-symmetric input.

    Returns
    -------
    output : ndarray
        The filtered signal.
    )r   )rZ   rw   rx   r]   r   r   r   symiirorder2  s   r   )r   r%   )r4   r%   )r4   )r)   cupy._core._scalarr   cupy._core.internalr   cupyx.scipy.signal._signaltoolsr   cupyx.scipy.signal._arraytoolsr   r   r   cupyx.scipy.signal._iir_utilsr   r	   SYMIIR2_KERNEL	RawModuler   r$   r3   ri   rp   rz   r   r   r   r   r   r   r   <module>   s4   c


JF
 