L iKdZddlZddlZddlZddlmZmZddlmZm Z m Z gdZ dZ ddZ Gdd ZGd d eZdd d dZdddd ddZy)a Chirp z-transform. We provide two interfaces to the chirp z-transform: an object interface which precalculates part of the transform and can be applied efficiently to many different data sets, and a functional interface which is applied only to the given data set. Transforms ---------- CZT : callable (x, axis=-1) -> array Define a chirp z-transform that can be applied to different signals. ZoomFFT : callable (x, axis=-1) -> array Define a Fourier transform on a range of frequencies. Functions --------- czt : array Compute the chirp z-transform for a signal. zoom_fft : array Compute the Fourier transform on a range of frequencies. N)piarange)fftifft next_fast_len)cztzoom_fftCZTZoomFFT czt_pointsc|dkst|tjstd|d||}|S|dkst|tjstd|d|S)Nz#Invalid number of CZT data points (z1) specified. n must be positive and integer type.z%Invalid number of CZT output points (z1) specified. m must be positive and integer type.) isinstancenumbersIntegral ValueError)nms W/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/scipy/signal/_czt.py_validate_sizesr%s1uJq'"2"23$$%3'@@A A y  H QjG$4$45$$%3'@@A A Hctd|}t|}d|z}|%|tjdtz|z|z zSd|z}||| zzS)a Return the points at which the chirp z-transform is computed. Parameters ---------- m : int The number of points desired. w : complex, optional The ratio between points in each step. Defaults to equally spaced points around the entire unit circle. a : complex, optional The starting point in the complex plane. Default is 1+0j. Returns ------- out : ndarray The points in the Z plane at which `CZT` samples the z-transform, when called with arguments `m`, `w`, and `a`, as complex numbers. See Also -------- CZT : Class that creates a callable chirp z-transform function. czt : Convenience function for quickly calculating CZT. Examples -------- Plot the points of a 16-point FFT: >>> import numpy as np >>> from scipy.signal import czt_points >>> points = czt_points(16) >>> import matplotlib.pyplot as plt >>> plt.plot(points.real, points.imag, 'o') >>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3)) >>> plt.axis('equal') >>> plt.show() and a 91-point logarithmic spiral that crosses the unit circle: >>> m, w, a = 91, 0.995*np.exp(-1j*np.pi*.05), 0.8*np.exp(1j*np.pi/6) >>> points = czt_points(m, w, a) >>> plt.plot(points.real, points.imag, 'o') >>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3)) >>> plt.axis('equal') >>> plt.show() r?@)rrnpexpr)rwaks rr r 5sc^ 1Aq A aAy266"r'A+/*** !G1qb5yrc*eZdZdZddZdddZdZy) r a Create a callable chirp z-transform function. Transform to compute the frequency response around a spiral. Objects of this class are callables which can compute the chirp z-transform on their inputs. This object precalculates the constant chirps used in the given transform. Parameters ---------- n : int The size of the signal. m : int, optional The number of output points desired. Default is `n`. w : complex, optional The ratio between points in each step. This must be precise or the accumulated error will degrade the tail of the output sequence. Defaults to equally spaced points around the entire unit circle. a : complex, optional The starting point in the complex plane. Default is 1+0j. Returns ------- f : CZT Callable object ``f(x, axis=-1)`` for computing the chirp z-transform on `x`. See Also -------- czt : Convenience function for quickly calculating CZT. ZoomFFT : Class that creates a callable partial FFT function. Notes ----- The defaults are chosen such that ``f(x)`` is equivalent to ``fft.fft(x)`` and, if ``m > len(x)``, that ``f(x, m)`` is equivalent to ``fft.fft(x, m)``. If `w` does not lie on the unit circle, then the transform will be around a spiral with exponentially-increasing radius. Regardless, angle will increase linearly. For transforms that do lie on the unit circle, accuracy is better when using `ZoomFFT`, since any numerical error in `w` is accumulated for long data lengths, drifting away from the unit circle. The chirp z-transform can be faster than an equivalent FFT with zero padding. Try it with your own array sizes to see. However, the chirp z-transform is considerably less precise than the equivalent zero-padded FFT. As this CZT is implemented using the Bluestein algorithm, it can compute large prime-length Fourier transforms in O(N log N) time, rather than the O(N**2) time required by the direct DFT calculation. (`scipy.fft` also uses Bluestein's algorithm'.) (The name "chirp z-transform" comes from the use of a chirp in the Bluestein algorithm. It does not decompose signals into chirps, like other transforms with "chirp" in the name.) References ---------- .. [1] Leo I. Bluestein, "A linear filtering approach to the computation of the discrete Fourier transform," Northeast Electronics Research and Engineering Meeting Record 10, 218-219 (1968). .. [2] Rabiner, Schafer, and Rader, "The chirp z-transform algorithm and its application," Bell Syst. Tech. J. 48, 1249-1292 (1969). Examples -------- Compute multiple prime-length FFTs: >>> from scipy.signal import CZT >>> import numpy as np >>> a = np.random.rand(7) >>> b = np.random.rand(7) >>> c = np.random.rand(7) >>> czt_7 = CZT(n=7) >>> A = czt_7(a) >>> B = czt_7(b) >>> C = czt_7(c) Display the points at which the FFT is calculated: >>> czt_7.points() array([ 1.00000000+0.j , 0.62348980+0.78183148j, -0.22252093+0.97492791j, -0.90096887+0.43388374j, -0.90096887-0.43388374j, -0.22252093-0.97492791j, 0.62348980-0.78183148j]) >>> import matplotlib.pyplot as plt >>> plt.plot(czt_7.points().real, czt_7.points().imag, 'o') >>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3)) >>> plt.axis('equal') >>> plt.show() Nc t||}tt||tjt||dz }|Lt j dtz|z }tj dtz|dzd|zzz |z }n ||dzdz z}d|z}||c|_|_ ||c|_ |_ t||zdz }||d| z|d|z|_ ||_tdtj ||dz dd |d|fz ||_|d||_t'|dz ||zdz |_y) Ndtype?g@rrr)rrmaxrmin_scalar_typecmathrrrrrrr_Awk2_nfftrhstack_Fwk2_wk2slice_yidx)selfrrrrrwk2nffts r__init__z CZT.__init__sJ Aq ! 3q!9B$6$6Aq 1 }$E F 9 #b&(#A&&27q!t!n56:;Cad2g,C !GAAQUQY'2AYRa(  299c!A#a(mS!W%=>>E G 1Q3!A& rr'axisctj|}|j||jk7r(t d|jd|j|tj |j }d|g||dg<|j|}t|jt||jz|jz}|d|jf|jz}|j|S)a Calculate the chirp z-transform of a signal. Parameters ---------- x : array The signal to transform. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is used. Returns ------- out : ndarray An array of the same dimensions as `x`, but with the length of the transformed axis set to `m`. zCZT defined for length z, not r'.)rasarrayshaperrrndim transposerr.rr+r,r1r/)r2xr7trnspys r__call__z CZT.__call__s$ JJqM 774=DFF "6tvvhf ! 01 1 !&&!JtRj AKK  c!DJJ, ;; < c4::o  *q{{E""rcXt|j|j|jS)zO Return the points at which the chirp z-transform is computed. )r rrr)r2s rpointsz CZT.points s$&&$&&$&&11rNN?)__name__ __module__ __qualname____doc__r5r@rBrrr r ss_B'2#%#<2rr c eZdZdZdddddZy)r a; Create a callable zoom FFT transform function. This is a specialization of the chirp z-transform (`CZT`) for a set of equally-spaced frequencies around the unit circle, used to calculate a section of the FFT more efficiently than calculating the entire FFT and truncating. Parameters ---------- n : int The size of the signal. fn : array_like A length-2 sequence [`f1`, `f2`] giving the frequency range, or a scalar, for which the range [0, `fn`] is assumed. m : int, optional The number of points to evaluate. Default is `n`. fs : float, optional The sampling frequency. If ``fs=10`` represented 10 kHz, for example, then `f1` and `f2` would also be given in kHz. The default sampling frequency is 2, so `f1` and `f2` should be in the range [0, 1] to keep the transform below the Nyquist frequency. endpoint : bool, optional If True, `f2` is the last sample. Otherwise, it is not included. Default is False. Returns ------- f : ZoomFFT Callable object ``f(x, axis=-1)`` for computing the zoom FFT on `x`. See Also -------- zoom_fft : Convenience function for calculating a zoom FFT. Notes ----- The defaults are chosen such that ``f(x, 2)`` is equivalent to ``fft.fft(x)`` and, if ``m > len(x)``, that ``f(x, 2, m)`` is equivalent to ``fft.fft(x, m)``. Sampling frequency is 1/dt, the time step between samples in the signal `x`. The unit circle corresponds to frequencies from 0 up to the sampling frequency. The default sampling frequency of 2 means that `f1`, `f2` values up to the Nyquist frequency are in the range [0, 1). For `f1`, `f2` values expressed in radians, a sampling frequency of 2*pi should be used. Remember that a zoom FFT can only interpolate the points of the existing FFT. It cannot help to resolve two separate nearby frequencies. Frequency resolution can only be increased by increasing acquisition time. These functions are implemented using Bluestein's algorithm (as is `scipy.fft`). [2]_ References ---------- .. [1] Steve Alan Shilling, "A study of the chirp z-transform and its applications", pg 29 (1970) https://krex.k-state.edu/dspace/bitstream/handle/2097/7844/LD2668R41972S43.pdf .. [2] Leo I. Bluestein, "A linear filtering approach to the computation of the discrete Fourier transform," Northeast Electronics Research and Engineering Meeting Record 10, 218-219 (1968). Examples -------- To plot the transform results use something like the following: >>> import numpy as np >>> from scipy.signal import ZoomFFT >>> t = np.linspace(0, 1, 1021) >>> x = np.cos(2*np.pi*15*t) + np.sin(2*np.pi*17*t) >>> f1, f2 = 5, 27 >>> transform = ZoomFFT(len(x), [f1, f2], len(x), fs=1021) >>> X = transform(x) >>> f = np.linspace(f1, f2, len(x)) >>> import matplotlib.pyplot as plt >>> plt.plot(f, 20*np.log10(np.abs(X))) >>> plt.show() Nr"F)fsendpointc t||}tt||tjt||dz }tj |dk(r|\}}n(tj |dk(rd|}}n t d|||c|_|_|_ |r||z |z||dz zz } n||z |z } tjdtz|z|z } tjdtz| z|dzz |z } tjdtz|z | z|_ | |_||c|_|_tjdtz|z|z |d|z} | | d|z|_t%||zdz } | |_t)dtj*| |dz d d | d|fz | |_| d||_t1|dz ||zdz |_y) Nr"r#rgz(fn must be a scalar or 2-length sequencerr&r%rr')rrr(rr)sizerf1f2rKr*rrrrrrr+rr,rr-r.r/r0r1)r2rfnrrKrLrrOrPscalerr3akr4s rr5zZoomFFT.__init__gs Aq ! 3q!9B$6$6Aq 1 }$E F 772;! FB WWR[A "BGH H$&B!$' 2g]rQU|4E"WNE IIb2gl2o &ffrBwA-.233r6!8e+,A VVC"HrM"$q!u, -#bq'\ QUQY' 299c!A#a(mS!W%=>>E G 1Q3!A& rN)rErFrGrHr5rIrrr r sQf 'A 'rr r'r6cxtj|}t|j||||}|||S)a Compute the frequency response around a spiral in the Z plane. Parameters ---------- x : array The signal to transform. m : int, optional The number of output points desired. Default is the length of the input data. w : complex, optional The ratio between points in each step. This must be precise or the accumulated error will degrade the tail of the output sequence. Defaults to equally spaced points around the entire unit circle. a : complex, optional The starting point in the complex plane. Default is 1+0j. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is used. Returns ------- out : ndarray An array of the same dimensions as `x`, but with the length of the transformed axis set to `m`. See Also -------- CZT : Class that creates a callable chirp z-transform function. zoom_fft : Convenience function for partial FFT calculations. Notes ----- The defaults are chosen such that ``signal.czt(x)`` is equivalent to ``fft.fft(x)`` and, if ``m > len(x)``, that ``signal.czt(x, m)`` is equivalent to ``fft.fft(x, m)``. If the transform needs to be repeated, use `CZT` to construct a specialized transform function which can be reused without recomputing constants. An example application is in system identification, repeatedly evaluating small slices of the z-transform of a system, around where a pole is expected to exist, to refine the estimate of the pole's true location. [1]_ References ---------- .. [1] Steve Alan Shilling, "A study of the chirp z-transform and its applications", pg 20 (1970) https://krex.k-state.edu/dspace/bitstream/handle/2097/7844/LD2668R41972S43.pdf Examples -------- Generate a sinusoid: >>> import numpy as np >>> f1, f2, fs = 8, 10, 200 # Hz >>> t = np.linspace(0, 1, fs, endpoint=False) >>> x = np.sin(2*np.pi*t*f2) >>> import matplotlib.pyplot as plt >>> plt.plot(t, x) >>> plt.axis([0, 1, -1.1, 1.1]) >>> plt.show() Its discrete Fourier transform has all of its energy in a single frequency bin: >>> from scipy.fft import rfft, rfftfreq >>> from scipy.signal import czt, czt_points >>> plt.plot(rfftfreq(fs, 1/fs), abs(rfft(x))) >>> plt.margins(0, 0.1) >>> plt.show() However, if the sinusoid is logarithmically-decaying: >>> x = np.exp(-t*f1) * np.sin(2*np.pi*t*f2) >>> plt.plot(t, x) >>> plt.axis([0, 1, -1.1, 1.1]) >>> plt.show() the DFT will have spectral leakage: >>> plt.plot(rfftfreq(fs, 1/fs), abs(rfft(x))) >>> plt.margins(0, 0.1) >>> plt.show() While the DFT always samples the z-transform around the unit circle, the chirp z-transform allows us to sample the Z-transform along any logarithmic spiral, such as a circle with radius smaller than unity: >>> M = fs // 2 # Just positive frequencies, like rfft >>> a = np.exp(-f1/fs) # Starting point of the circle, radius < 1 >>> w = np.exp(-1j*np.pi/M) # "Step size" of circle >>> points = czt_points(M + 1, w, a) # M + 1 to include Nyquist >>> plt.plot(points.real, points.imag, '.') >>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3)) >>> plt.axis('equal'); plt.axis([-1.05, 1.05, -0.05, 1.05]) >>> plt.show() With the correct radius, this transforms the decaying sinusoid (and others with the same decay rate) without spectral leakage: >>> z_vals = czt(x, M + 1, w, a) # Include Nyquist for comparison to rfft >>> freqs = np.angle(points)*fs/(2*np.pi) # angle = omega, radius = sigma >>> plt.plot(freqs, abs(z_vals)) >>> plt.margins(0, 0.1) >>> plt.show() )rrrr6)rr9r r:)r=rrrr7 transforms rrrs7Z 1 AAGGDMQ!q1I QT ""rr"F)rKrLr7cztj|}t|j|||||}|||S)a Compute the DFT of `x` only for frequencies in range `fn`. Parameters ---------- x : array The signal to transform. fn : array_like A length-2 sequence [`f1`, `f2`] giving the frequency range, or a scalar, for which the range [0, `fn`] is assumed. m : int, optional The number of points to evaluate. The default is the length of `x`. fs : float, optional The sampling frequency. If ``fs=10`` represented 10 kHz, for example, then `f1` and `f2` would also be given in kHz. The default sampling frequency is 2, so `f1` and `f2` should be in the range [0, 1] to keep the transform below the Nyquist frequency. endpoint : bool, optional If True, `f2` is the last sample. Otherwise, it is not included. Default is False. axis : int, optional Axis over which to compute the FFT. If not given, the last axis is used. Returns ------- out : ndarray The transformed signal. The Fourier transform will be calculated at the points f1, f1+df, f1+2df, ..., f2, where df=(f2-f1)/m. See Also -------- ZoomFFT : Class that creates a callable partial FFT function. Notes ----- The defaults are chosen such that ``signal.zoom_fft(x, 2)`` is equivalent to ``fft.fft(x)`` and, if ``m > len(x)``, that ``signal.zoom_fft(x, 2, m)`` is equivalent to ``fft.fft(x, m)``. To graph the magnitude of the resulting transform, use:: plot(linspace(f1, f2, m, endpoint=False), abs(zoom_fft(x, [f1, f2], m))) If the transform needs to be repeated, use `ZoomFFT` to construct a specialized transform function which can be reused without recomputing constants. Examples -------- To plot the transform results use something like the following: >>> import numpy as np >>> from scipy.signal import zoom_fft >>> t = np.linspace(0, 1, 1021) >>> x = np.cos(2*np.pi*15*t) + np.sin(2*np.pi*17*t) >>> f1, f2 = 5, 27 >>> X = zoom_fft(x, [f1, f2], len(x), fs=1021) >>> f = np.linspace(f1, f2, len(x)) >>> import matplotlib.pyplot as plt >>> plt.plot(f, 20*np.log10(np.abs(X))) >>> plt.show() )rrKrLr6)rr9r r:)r=rQrrKrLr7rVs rr r s9B 1 A rQ2II QT ""r)NrDrCrT)rHr*rnumpyrrr scipy.fftrrr__all__rr r r rr rIrrr[sk2 .. =  ;|]2]2@t'ct'no#2o#dC#!e"C#r