K iY dZddlmZmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZmZdd lmZdd lmZmZmZdd lmZdd lmZdd lmZddlmZddgiZdZdZ dZ!dZ"GddeZ#Gdde#Z$ddZ%y)zFourier Series)oopi)Wild)Expr)Add)Tuple)S)DummySymbol)sympify)sincossinc) SeriesBase) SeqFormula)Interval) is_sequence)fourier_series matplotlibc$ddlm}|d|d|dz }}td|ztz|z|z }d|z|||z|z|z }|j |t j dz }|td|z|||z|z|z |dtffS)z,Returns the cos sequence in a Fourier seriesr integrate) sympy.integralsrrrsubsr Zerorr) funclimitsnrxLcos_termformulaa0s Z/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/sympy/series/fourier.pyfourier_cos_seqr's) !9fQi&)+qA1Q3r6!8a< H(lYth??!CG a 1 $B z!h,4(?F)KK !1bz+ ++cddlm}|d|d|dz }}td|ztz|z|z }t d|z|||z|z|z |dt fS)z,Returns the sin sequence in a Fourier seriesrrrr)rrr rrr)rrr rr!r"sin_terms r&fourier_sin_seqr+ sm) !9fQi&)+qA1Q3r6!8a< H a(lYth%GGq": ''r(cd}d\}}}|||t t}}}t|tr0t|dk(r|\}}}nt|dk(r ||}|\}}t |t r||t dt|ztjtjg}||vs||vr t dt|||fS)a Limits should be of the form (x, start, stop). x should be a symbol. Both start and stop should be bounded. Explanation =========== * If x is not given, x is determined from func. * If limits is None. Limit of the form (x, -pi, pi) is returned. Examples ======== >>> from sympy.series.fourier import _process_limits as pari >>> from sympy.abc import x >>> pari(x**2, (x, -2, 2)) (x, -2, 2) >>> pari(x**2, (-2, 2)) (x, -2, 2) >>> pari(x**2, None) (x, -pi, pi) c|j}t|dk(r|jS|s tdSt d|z)Nrkz specify dummy variables for %s. If the function contains more than one free symbol, a dummy variable should be supplied explicitly e.g. FourierSeries(m*n**2, (n, -pi, pi))) free_symbolslenpopr ValueError)rfrees r&_find_xz _process_limits.._find_x@sN   t9>88: : P r()NNNrzInvalid limits given: %sz.Both the start and end value should be bounded) rrrr0 isinstancer r2strr NegativeInfinityInfinityr )rrr4r!startstop unboundeds r&_process_limitsr=)s. &NAud ~ R$565! v;! #NAud [A  A KE4 a EMT\3c&kABB##QZZ0I TY.IJJ Aud# $$r(cB d} fd}ddlm}m}m}||||}|j } t dddg t d fd g| d D]8} | j d } | D]} || r || |rd |fccS:d |fS)Nc||jvSNr/)exprsr!s r&check_fxzfinite_check..check_fxcs****r(ct|ttfr2|jd}|j t |z z|zzyyy)NrTF)r6r rargsmatchr)_exprr!r" sincos_argsabs r& check_sincosz"finite_check..check_sincosfsJ ec3Z (**Q-K  BqD!a0< )r(r)TR2TR1 sincos_to_sumrIc|jSr@ is_Integerr.s r&zfinite_check..ss  r(c(|tjk7Sr@r rrRs r&rSzfinite_check..ssQVV r( propertiesrJc |jvSr@rAr.r!s r&rSzfinite_check..ts(?r(rFT)sympy.simplify.furLrMrN as_coeff_addr as_coeff_mul)fr!r"rCrKrLrMrNrG add_coeffs mul_coeffstrIrJs ` @@r& finite_checkrbas+:9 #c!f+ &E""$I S46KNOA S?BCA q\ ^^%a(  AQNl1a&;ax  ;r(ceZdZdZdZedZedZedZedZ edZ edZ ed Z ed Z ed Zed Zed ZdZddZddZdZdZdZdZdZdZdZdZdZy) FourierSeriesa9Represents Fourier sine/cosine series. Explanation =========== This class only represents a fourier series. No computation is performed. For how to compute Fourier series, see the :func:`fourier_series` docstring. See Also ======== sympy.series.fourier.fourier_series cNtt|}tj|g|Sr@)mapr r__new__)clsrEs r&rgzFourierSeries.__new__s"7D!||C'$''r(c |jdSNrrEselfs r&functionzFourierSeries.functionsyy|r(c&|jddSNrrrkrls r&r!zFourierSeries.xyy|Ar(cJ|jdd|jddfS)Nrrrkrls r&periodzFourierSeries.periods% ! Q1a11r(c&|jddS)Nrrrkrls r&r%zFourierSeries.a0rqr(c&|jddS)Nrrrkrls r&anzFourierSeries.anrqr(c&|jddS)Nrrkrls r&bnzFourierSeries.bnrqr(c"tdtSrj)rrrls r&intervalzFourierSeries.intervals2r(c.|jjSr@)rzinfrls r&r:zFourierSeries.start}}   r(c.|jjSr@)rzsuprls r&r;zFourierSeries.stopr}r(ctSr@)rrls r&lengthzFourierSeries.lengths r(cXt|jd|jdz dz S)Nrrr)absrsrls r&r"zFourierSeries.Ls'4;;q>DKKN23a77r(cB|j}|j|r|Syr@)r!has)rmoldnewr!s r& _eval_subszFourierSeries._eval_subss FF 771:K r(c| t|Sg}|D]=}t||k(r t |S|tjus-|j |?t |S)a Return the first n nonzero terms of the series. If ``n`` is None return an iterator. Parameters ========== n : int or None Amount of non-zero terms in approximation or None. Returns ======= Expr or iterator : Approximation of function expanded into Fourier series. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x, (x, -pi, pi)) >>> s.truncate(4) 2*sin(x) - sin(2*x) + 2*sin(3*x)/3 - sin(4*x)/2 See Also ======== sympy.series.fourier.FourierSeries.sigma_approximation )iterr0r rappendr)rmr termsras r&truncatezFourierSeries.truncatesf@ 9:  A5zQE{ Q  E{r(ct|d|Dcgc]/\}}|tjurtt|z|z |z1}}}t |Scc}}w)a Return :math:`\sigma`-approximation of Fourier series with respect to order n. Explanation =========== Sigma approximation adjusts a Fourier summation to eliminate the Gibbs phenomenon which would otherwise occur at discontinuities. A sigma-approximated summation for a Fourier series of a T-periodical function can be written as .. math:: s(\theta) = \frac{1}{2} a_0 + \sum _{k=1}^{m-1} \operatorname{sinc} \Bigl( \frac{k}{m} \Bigr) \cdot \left[ a_k \cos \Bigl( \frac{2\pi k}{T} \theta \Bigr) + b_k \sin \Bigl( \frac{2\pi k}{T} \theta \Bigr) \right], where :math:`a_0, a_k, b_k, k=1,\ldots,{m-1}` are standard Fourier series coefficients and :math:`\operatorname{sinc} \Bigl( \frac{k}{m} \Bigr)` is a Lanczos :math:`\sigma` factor (expressed in terms of normalized :math:`\operatorname{sinc}` function). Parameters ========== n : int Highest order of the terms taken into account in approximation. Returns ======= Expr : Sigma approximation of function expanded into Fourier series. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x, (x, -pi, pi)) >>> s.sigma_approximation(4) 2*sin(x)*sinc(pi/4) - 2*sin(2*x)/pi + 2*sin(3*x)*sinc(3*pi/4)/3 See Also ======== sympy.series.fourier.FourierSeries.truncate Notes ===== The behaviour of :meth:`~sympy.series.fourier.FourierSeries.sigma_approximation` is different from :meth:`~sympy.series.fourier.FourierSeries.truncate` - it takes all nonzero terms of degree smaller than n, rather than first n nonzero ones. References ========== .. [1] https://en.wikipedia.org/wiki/Gibbs_phenomenon .. [2] https://en.wikipedia.org/wiki/Sigma_approximation N) enumerater rrrr)rmr irars r&sigma_approximationz!FourierSeries.sigma_approximations\D3 f(x) + s This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.shift(1).truncate() -4*cos(x) + cos(2*x) + 1 + pi**2/3 '' should be independent of r) r r!r/r2r%rnrrErvrx)rmr_r!r%sfuncs r&shiftzFourierSeries.shift7sv*qz4661  1aHI I WWq[ !yy ! r477DGG.DEEr(ct||j}}||jvrtd|d||jj |||z}|j j |||z}|jj |||z}|j||jd|j||fS)a Shift x by a term independent of x. Explanation =========== f(x) -> f(x + s) This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.shiftx(1).truncate() -4*cos(x + 1) + cos(2*x + 2) + pi**2/3 rrr r r!r/r2rvrrxrnrrEr%rmr_r!rvrxrs r&shiftxzFourierSeries.shiftxV*qz4661  1aHI I WW\\!QU # WW\\!QU # ""1a!e,yy ! twwB.?@@r(cbt||j}}||jvrtd|d||jj |}|j j |}|j|z}|jd|z}|j||jd|||fS)a Scale the function by a term independent of x. Explanation =========== f(x) -> s * f(x) This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.scale(2).truncate() -8*cos(x) + 2*cos(2*x) + 2*pi**2/3 rrrr) r r!r/r2rv coeff_mulrxr%rEr)rmr_r!rvrxr%rs r&scalezFourierSeries.scalevs*qz4661  1aHI I WW  q ! WW  q ! WWq[ ! q yy ! r2rl;;r(ct||j}}||jvrtd|d||jj |||z}|j j |||z}|jj |||z}|j||jd|j||fS)a Scale x by a term independent of x. Explanation =========== f(x) -> f(s*x) This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.scalex(2).truncate() -4*cos(2*x) + cos(4*x) + pi**2/3 rrrrrs r&scalexzFourierSeries.scalexrr(c>|D]}|tjus|cSyr@rU)rmr!logxcdirras r&_eval_as_leading_termz#FourierSeries._eval_as_leading_terms! A r(c|dk(r |jS|jj||jj|zSrj)r%rvcoeffrx)rmpts r& _eval_termzFourierSeries._eval_terms7 777Nww}}R 477==#444r(c$|jdS)N)rrls r&__neg__zFourierSeries.__neg__szz"~r(ct|tr|j|jk7r td|j|j}}|j |j j ||z}|j|jvr|S|j|jz}|j|jz}|j|jz}|j||jd|||fSt||S)N(Both the series should have same periodsr)r6rdrsr2r!rnrr/rvrxr%rrEr)rmotherr!yrnrvrxr%s r&__add__zFourierSeries.__add__s e] +{{ell* !KLL66577qA}}u~~':':1a'@@HvvX222588#B588#B588#B99Xtyy|b"b\B B4r(c&|j| Sr@)r)rmrs r&__sub__zFourierSeries.__sub__s||UF##r(N)r5)__name__ __module__ __qualname____doc__rgpropertyrnr!rsr%rvrxrzr:r;rr"rrrrrrrrrrrrr(r&rdrds- (22!!!!88 *XDLF>A@.s  r(c&|tjuSr@rUrRs r&rSz-FiniteFourierSeries.__new__..sQRQWQWr(rVrJc |jvSr@rArYs r&rSz-FiniteFourierSeries.__new__..s0Gr()r r6rr0r[rZrrexpandrrrFrrr getr rrrg)rhr]rrBcerrrexprr%exp_lsr"rIrJrvrxpraqr!s @r&rgzFiniteFourierSeries.__new__s AJ5%(SZ1_%%'DAq .q1!d1g122E5UeY^_llnJBq AF1Iq )*Q.AS&<>W%Z[AS&G%JKABB GGAAaL1$4 556GGAAaL1$4 556 tbffQqT166&::BqtH tbffQqT166&::BqtH!GB "b"%E||CFE2232s%G c |jrdnd}|tt|jj j t|j j dzz }td|Srp)r%maxsetrvkeysunionrxr)rm_lengths r&rzzFiniteFourierSeries.interval&sYww!A3s477<<>*00TWW\\^1DEFJJ7##r(c4|j|jz Sr@)r;r:rls r&rzFiniteFourierSeries.length,syy4::%%r(c2t||j}}||jvrtd|d||j j |||z}|j j |||z}|j||jd|SNrrr r r!r/r2rrrnrrErmr_r!rGrs r&rzFiniteFourierSeries.shiftx0qz4661  1aHI I $$QA. ""1a!e,yy ! e44r(ct||j}}||jvrtd|d||j |z}|j |z}|j ||jd|Sr)r r!r/r2rrnrrErs r&rzFiniteFourierSeries.scale;shqz4661  1aHI I !# !yy ! e44r(c2t||j}}||jvrtd|d||j j |||z}|j j |||z}|j||jd|Srrrs r&rzFiniteFourierSeries.scalexFrr(c|dk(r |jS|jj|tjt |t |jz z|jzz|jj|tjt|t |jz z|jzzz}|Srj) r%rvrr rrrr"r!rxr )rmr_terms r&rzFiniteFourierSeries._eval_termQs 777N B'#bBK.@466.I*JJ''++b!&&)Cb466k0BTVV0K,LLM r(ct|tr4|jt|j|j ddSt|t r|j|jk7r td|j|j}}|j|jj||z}|j|jvr|St||j dSy)NrF)finiter)r) r6rdrrrnrErrsr2r!rr/)rmrr!rrns r&rzFiniteFourierSeries.__add__Ys e] +== tyy|7<">? ? 2 3{{ell* !KLL66577qA}}u~~':':1a'@@HvvX222!(499Q<@ @4r(N) rrrrrgrrzrrrrrrrr(r&rrsP$L"3H$$ && 5 5 5Ar(rNct|}t||}|d}||jvr|S|r6t|d|dz dz }t |||\}}|r t |||St d}|d|dzdz }|jr|j|| } || k(r2t|||\} } tddtf} t||| | | fS|| k(r?tj} tddtf} t|||} t||| | | fSt|||\} } t|||} t||| | | fS)a`Computes the Fourier trigonometric series expansion. Explanation =========== Fourier trigonometric series of $f(x)$ over the interval $(a, b)$ is defined as: .. math:: \frac{a_0}{2} + \sum_{n=1}^{\infty} (a_n \cos(\frac{2n \pi x}{L}) + b_n \sin(\frac{2n \pi x}{L})) where the coefficients are: .. math:: L = b - a .. math:: a_0 = \frac{2}{L} \int_{a}^{b}{f(x) dx} .. math:: a_n = \frac{2}{L} \int_{a}^{b}{f(x) \cos(\frac{2n \pi x}{L}) dx} .. math:: b_n = \frac{2}{L} \int_{a}^{b}{f(x) \sin(\frac{2n \pi x}{L}) dx} The condition whether the function $f(x)$ given should be periodic or not is more than necessary, because it is sufficient to consider the series to be converging to $f(x)$ only in the given interval, not throughout the whole real line. This also brings a lot of ease for the computation because you do not have to make $f(x)$ artificially periodic by wrapping it with piecewise, modulo operations, but you can shape the function to look like the desired periodic function only in the interval $(a, b)$, and the computed series will automatically become the series of the periodic version of $f(x)$. This property is illustrated in the examples section below. Parameters ========== limits : (sym, start, end), optional *sym* denotes the symbol the series is computed with respect to. *start* and *end* denotes the start and the end of the interval where the fourier series converges to the given function. Default range is specified as $-\pi$ and $\pi$. Returns ======= FourierSeries A symbolic object representing the Fourier trigonometric series. Examples ======== Computing the Fourier series of $f(x) = x^2$: >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> f = x**2 >>> s = fourier_series(f, (x, -pi, pi)) >>> s1 = s.truncate(n=3) >>> s1 -4*cos(x) + cos(2*x) + pi**2/3 Shifting of the Fourier series: >>> s.shift(1).truncate() -4*cos(x) + cos(2*x) + 1 + pi**2/3 >>> s.shiftx(1).truncate() -4*cos(x + 1) + cos(2*x + 2) + pi**2/3 Scaling of the Fourier series: >>> s.scale(2).truncate() -8*cos(x) + 2*cos(2*x) + 2*pi**2/3 >>> s.scalex(2).truncate() -4*cos(2*x) + cos(4*x) + pi**2/3 Computing the Fourier series of $f(x) = x$: This illustrates how truncating to the higher order gives better convergence. .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import fourier_series, pi, plot >>> from sympy.abc import x >>> f = x >>> s = fourier_series(f, (x, -pi, pi)) >>> s1 = s.truncate(n = 3) >>> s2 = s.truncate(n = 5) >>> s3 = s.truncate(n = 7) >>> p = plot(f, s1, s2, s3, (x, -pi, pi), show=False, legend=True) >>> p[0].line_color = (0, 0, 0) >>> p[0].label = 'x' >>> p[1].line_color = (0.7, 0.7, 0.7) >>> p[1].label = 'n=3' >>> p[2].line_color = (0.5, 0.5, 0.5) >>> p[2].label = 'n=5' >>> p[3].line_color = (0.3, 0.3, 0.3) >>> p[3].label = 'n=7' >>> p.show() This illustrates how the series converges to different sawtooth waves if the different ranges are specified. .. plot:: :context: close-figs :format: doctest :include-source: True >>> s1 = fourier_series(x, (x, -1, 1)).truncate(10) >>> s2 = fourier_series(x, (x, -pi, pi)).truncate(10) >>> s3 = fourier_series(x, (x, 0, 1)).truncate(10) >>> p = plot(x, s1, s2, s3, (x, -5, 5), show=False, legend=True) >>> p[0].line_color = (0, 0, 0) >>> p[0].label = 'x' >>> p[1].line_color = (0.7, 0.7, 0.7) >>> p[1].label = '[-1, 1]' >>> p[2].line_color = (0.5, 0.5, 0.5) >>> p[2].label = '[-pi, pi]' >>> p[3].line_color = (0.3, 0.3, 0.3) >>> p[3].label = '[0, 1]' >>> p.show() Notes ===== Computing Fourier series can be slow due to the integration required in computing an, bn. It is faster to compute Fourier series of a function by using shifting and scaling on an already computed Fourier series rather than computing again. e.g. If the Fourier series of ``x**2`` is known the Fourier series of ``x**2 - 1`` can be found by shifting by ``-1``. See Also ======== sympy.series.fourier.FourierSeries References ========== .. [1] https://mathworld.wolfram.com/FourierSeries.html rrrr )r r=r/rrbrr is_zerorr'rrrdr rr+) r]rrr!r" is_finiteres_fr centerneg_fr%rvrxs r&rrjshH  A Q 'Fq A q F1I% & *'1a0 5 &q&%8 8 c AQi&)#q (F ~~q1"  :$Q2FBA2w'B FRRL9 9 5&[BA2w'B FA.B FRRL9 9 Q *FB FA &B FRRL 11r()NT)&rsympy.core.numbersrrsympy.core.symbolrsympy.core.exprrsympy.core.addrsympy.core.containersrsympy.core.singletonr r r sympy.core.sympifyr (sympy.functions.elementary.trigonometricr rrsympy.series.series_classrsympy.series.sequencesrsympy.sets.setsrsympy.utilities.iterablesr__doctest_requires__r'r+r=rbrdrrrr(r&rs|'" '"+&CC0-$1,l^<+'5%p