1# mypy: allow-untyped-decorators 2# mypy: allow-untyped-defs 3from typing import Optional, Iterable 4 5import torch 6from math import sqrt 7 8from torch import Tensor 9from torch._torch_docs import factory_common_args, parse_kwargs, merge_dicts 10 11__all__ = [ 12 'bartlett', 13 'blackman', 14 'cosine', 15 'exponential', 16 'gaussian', 17 'general_cosine', 18 'general_hamming', 19 'hamming', 20 'hann', 21 'kaiser', 22 'nuttall', 23] 24 25window_common_args = merge_dicts( 26 parse_kwargs( 27 """ 28 M (int): the length of the window. 29 In other words, the number of points of the returned window. 30 sym (bool, optional): If `False`, returns a periodic window suitable for use in spectral analysis. 31 If `True`, returns a symmetric window suitable for use in filter design. Default: `True`. 32""" 33 ), 34 factory_common_args, 35 { 36 "normalization": "The window is normalized to 1 (maximum value is 1). However, the 1 doesn't appear if " 37 ":attr:`M` is even and :attr:`sym` is `True`.", 38 } 39) 40 41 42def _add_docstr(*args): 43 r"""Adds docstrings to a given decorated function. 44 45 Specially useful when then docstrings needs string interpolation, e.g., with 46 str.format(). 47 REMARK: Do not use this function if the docstring doesn't need string 48 interpolation, just write a conventional docstring. 49 50 Args: 51 args (str): 52 """ 53 54 def decorator(o): 55 o.__doc__ = "".join(args) 56 return o 57 58 return decorator 59 60 61def _window_function_checks(function_name: str, M: int, dtype: torch.dtype, layout: torch.layout) -> None: 62 r"""Performs common checks for all the defined windows. 63 This function should be called before computing any window. 64 65 Args: 66 function_name (str): name of the window function. 67 M (int): length of the window. 68 dtype (:class:`torch.dtype`): the desired data type of returned tensor. 69 layout (:class:`torch.layout`): the desired layout of returned tensor. 70 """ 71 if M < 0: 72 raise ValueError(f'{function_name} requires non-negative window length, got M={M}') 73 if layout is not torch.strided: 74 raise ValueError(f'{function_name} is implemented for strided tensors only, got: {layout}') 75 if dtype not in [torch.float32, torch.float64]: 76 raise ValueError(f'{function_name} expects float32 or float64 dtypes, got: {dtype}') 77 78 79@_add_docstr( 80 r""" 81Computes a window with an exponential waveform. 82Also known as Poisson window. 83 84The exponential window is defined as follows: 85 86.. math:: 87 w_n = \exp{\left(-\frac{|n - c|}{\tau}\right)} 88 89where `c` is the ``center`` of the window. 90 """, 91 r""" 92 93{normalization} 94 95Args: 96 {M} 97 98Keyword args: 99 center (float, optional): where the center of the window will be located. 100 Default: `M / 2` if `sym` is `False`, else `(M - 1) / 2`. 101 tau (float, optional): the decay value. 102 Tau is generally associated with a percentage, that means, that the value should 103 vary within the interval (0, 100]. If tau is 100, it is considered the uniform window. 104 Default: 1.0. 105 {sym} 106 {dtype} 107 {layout} 108 {device} 109 {requires_grad} 110 111Examples:: 112 113 >>> # Generates a symmetric exponential window of size 10 and with a decay value of 1.0. 114 >>> # The center will be at (M - 1) / 2, where M is 10. 115 >>> torch.signal.windows.exponential(10) 116 tensor([0.0111, 0.0302, 0.0821, 0.2231, 0.6065, 0.6065, 0.2231, 0.0821, 0.0302, 0.0111]) 117 118 >>> # Generates a periodic exponential window and decay factor equal to .5 119 >>> torch.signal.windows.exponential(10, sym=False,tau=.5) 120 tensor([4.5400e-05, 3.3546e-04, 2.4788e-03, 1.8316e-02, 1.3534e-01, 1.0000e+00, 1.3534e-01, 1.8316e-02, 2.4788e-03, 3.3546e-04]) 121 """.format( 122 **window_common_args 123 ), 124) 125def exponential( 126 M: int, 127 *, 128 center: Optional[float] = None, 129 tau: float = 1.0, 130 sym: bool = True, 131 dtype: Optional[torch.dtype] = None, 132 layout: torch.layout = torch.strided, 133 device: Optional[torch.device] = None, 134 requires_grad: bool = False 135) -> Tensor: 136 if dtype is None: 137 dtype = torch.get_default_dtype() 138 139 _window_function_checks('exponential', M, dtype, layout) 140 141 if tau <= 0: 142 raise ValueError(f'Tau must be positive, got: {tau} instead.') 143 144 if sym and center is not None: 145 raise ValueError('Center must be None for symmetric windows') 146 147 if M == 0: 148 return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 149 150 if center is None: 151 center = (M if not sym and M > 1 else M - 1) / 2.0 152 153 constant = 1 / tau 154 155 k = torch.linspace(start=-center * constant, 156 end=(-center + (M - 1)) * constant, 157 steps=M, 158 dtype=dtype, 159 layout=layout, 160 device=device, 161 requires_grad=requires_grad) 162 163 return torch.exp(-torch.abs(k)) 164 165 166@_add_docstr( 167 r""" 168Computes a window with a simple cosine waveform, following the same implementation as SciPy. 169This window is also known as the sine window. 170 171The cosine window is defined as follows: 172 173.. math:: 174 w_n = \sin\left(\frac{\pi (n + 0.5)}{M}\right) 175 176This formula differs from the typical cosine window formula by incorporating a 0.5 term in the numerator, 177which shifts the sample positions. This adjustment results in a window that starts and ends with non-zero values. 178 179""", 180 r""" 181 182{normalization} 183 184Args: 185 {M} 186 187Keyword args: 188 {sym} 189 {dtype} 190 {layout} 191 {device} 192 {requires_grad} 193 194Examples:: 195 196 >>> # Generates a symmetric cosine window. 197 >>> torch.signal.windows.cosine(10) 198 tensor([0.1564, 0.4540, 0.7071, 0.8910, 0.9877, 0.9877, 0.8910, 0.7071, 0.4540, 0.1564]) 199 200 >>> # Generates a periodic cosine window. 201 >>> torch.signal.windows.cosine(10, sym=False) 202 tensor([0.1423, 0.4154, 0.6549, 0.8413, 0.9595, 1.0000, 0.9595, 0.8413, 0.6549, 0.4154]) 203""".format( 204 **window_common_args, 205 ), 206) 207def cosine( 208 M: int, 209 *, 210 sym: bool = True, 211 dtype: Optional[torch.dtype] = None, 212 layout: torch.layout = torch.strided, 213 device: Optional[torch.device] = None, 214 requires_grad: bool = False 215) -> Tensor: 216 if dtype is None: 217 dtype = torch.get_default_dtype() 218 219 _window_function_checks('cosine', M, dtype, layout) 220 221 if M == 0: 222 return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 223 224 start = 0.5 225 constant = torch.pi / (M + 1 if not sym and M > 1 else M) 226 227 k = torch.linspace(start=start * constant, 228 end=(start + (M - 1)) * constant, 229 steps=M, 230 dtype=dtype, 231 layout=layout, 232 device=device, 233 requires_grad=requires_grad) 234 235 return torch.sin(k) 236 237 238@_add_docstr( 239 r""" 240Computes a window with a gaussian waveform. 241 242The gaussian window is defined as follows: 243 244.. math:: 245 w_n = \exp{\left(-\left(\frac{n}{2\sigma}\right)^2\right)} 246 """, 247 r""" 248 249{normalization} 250 251Args: 252 {M} 253 254Keyword args: 255 std (float, optional): the standard deviation of the gaussian. It controls how narrow or wide the window is. 256 Default: 1.0. 257 {sym} 258 {dtype} 259 {layout} 260 {device} 261 {requires_grad} 262 263Examples:: 264 265 >>> # Generates a symmetric gaussian window with a standard deviation of 1.0. 266 >>> torch.signal.windows.gaussian(10) 267 tensor([4.0065e-05, 2.1875e-03, 4.3937e-02, 3.2465e-01, 8.8250e-01, 8.8250e-01, 3.2465e-01, 4.3937e-02, 2.1875e-03, 4.0065e-05]) 268 269 >>> # Generates a periodic gaussian window and standard deviation equal to 0.9. 270 >>> torch.signal.windows.gaussian(10, sym=False,std=0.9) 271 tensor([1.9858e-07, 5.1365e-05, 3.8659e-03, 8.4658e-02, 5.3941e-01, 1.0000e+00, 5.3941e-01, 8.4658e-02, 3.8659e-03, 5.1365e-05]) 272""".format( 273 **window_common_args, 274 ), 275) 276def gaussian( 277 M: int, 278 *, 279 std: float = 1.0, 280 sym: bool = True, 281 dtype: Optional[torch.dtype] = None, 282 layout: torch.layout = torch.strided, 283 device: Optional[torch.device] = None, 284 requires_grad: bool = False 285) -> Tensor: 286 if dtype is None: 287 dtype = torch.get_default_dtype() 288 289 _window_function_checks('gaussian', M, dtype, layout) 290 291 if std <= 0: 292 raise ValueError(f'Standard deviation must be positive, got: {std} instead.') 293 294 if M == 0: 295 return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 296 297 start = -(M if not sym and M > 1 else M - 1) / 2.0 298 299 constant = 1 / (std * sqrt(2)) 300 301 k = torch.linspace(start=start * constant, 302 end=(start + (M - 1)) * constant, 303 steps=M, 304 dtype=dtype, 305 layout=layout, 306 device=device, 307 requires_grad=requires_grad) 308 309 return torch.exp(-k ** 2) 310 311 312@_add_docstr( 313 r""" 314Computes the Kaiser window. 315 316The Kaiser window is defined as follows: 317 318.. math:: 319 w_n = I_0 \left( \beta \sqrt{1 - \left( {\frac{n - N/2}{N/2}} \right) ^2 } \right) / I_0( \beta ) 320 321where ``I_0`` is the zeroth order modified Bessel function of the first kind (see :func:`torch.special.i0`), and 322``N = M - 1 if sym else M``. 323 """, 324 r""" 325 326{normalization} 327 328Args: 329 {M} 330 331Keyword args: 332 beta (float, optional): shape parameter for the window. Must be non-negative. Default: 12.0 333 {sym} 334 {dtype} 335 {layout} 336 {device} 337 {requires_grad} 338 339Examples:: 340 341 >>> # Generates a symmetric gaussian window with a standard deviation of 1.0. 342 >>> torch.signal.windows.kaiser(5) 343 tensor([4.0065e-05, 2.1875e-03, 4.3937e-02, 3.2465e-01, 8.8250e-01, 8.8250e-01, 3.2465e-01, 4.3937e-02, 2.1875e-03, 4.0065e-05]) 344 >>> # Generates a periodic gaussian window and standard deviation equal to 0.9. 345 >>> torch.signal.windows.kaiser(5, sym=False,std=0.9) 346 tensor([1.9858e-07, 5.1365e-05, 3.8659e-03, 8.4658e-02, 5.3941e-01, 1.0000e+00, 5.3941e-01, 8.4658e-02, 3.8659e-03, 5.1365e-05]) 347""".format( 348 **window_common_args, 349 ), 350) 351def kaiser( 352 M: int, 353 *, 354 beta: float = 12.0, 355 sym: bool = True, 356 dtype: Optional[torch.dtype] = None, 357 layout: torch.layout = torch.strided, 358 device: Optional[torch.device] = None, 359 requires_grad: bool = False 360) -> Tensor: 361 if dtype is None: 362 dtype = torch.get_default_dtype() 363 364 _window_function_checks('kaiser', M, dtype, layout) 365 366 if beta < 0: 367 raise ValueError(f'beta must be non-negative, got: {beta} instead.') 368 369 if M == 0: 370 return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 371 372 if M == 1: 373 return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 374 375 # Avoid NaNs by casting `beta` to the appropriate dtype. 376 beta = torch.tensor(beta, dtype=dtype, device=device) 377 378 start = -beta 379 constant = 2.0 * beta / (M if not sym else M - 1) 380 end = torch.minimum(beta, start + (M - 1) * constant) 381 382 k = torch.linspace(start=start, 383 end=end, 384 steps=M, 385 dtype=dtype, 386 layout=layout, 387 device=device, 388 requires_grad=requires_grad) 389 390 return torch.i0(torch.sqrt(beta * beta - torch.pow(k, 2))) / torch.i0(beta) 391 392 393@_add_docstr( 394 r""" 395Computes the Hamming window. 396 397The Hamming window is defined as follows: 398 399.. math:: 400 w_n = \alpha - \beta\ \cos \left( \frac{2 \pi n}{M - 1} \right) 401 """, 402 r""" 403 404{normalization} 405 406Arguments: 407 {M} 408 409Keyword args: 410 {sym} 411 alpha (float, optional): The coefficient :math:`\alpha` in the equation above. 412 beta (float, optional): The coefficient :math:`\beta` in the equation above. 413 {dtype} 414 {layout} 415 {device} 416 {requires_grad} 417 418Examples:: 419 420 >>> # Generates a symmetric Hamming window. 421 >>> torch.signal.windows.hamming(10) 422 tensor([0.0800, 0.1876, 0.4601, 0.7700, 0.9723, 0.9723, 0.7700, 0.4601, 0.1876, 0.0800]) 423 424 >>> # Generates a periodic Hamming window. 425 >>> torch.signal.windows.hamming(10, sym=False) 426 tensor([0.0800, 0.1679, 0.3979, 0.6821, 0.9121, 1.0000, 0.9121, 0.6821, 0.3979, 0.1679]) 427""".format( 428 **window_common_args 429 ), 430) 431def hamming(M: int, 432 *, 433 sym: bool = True, 434 dtype: Optional[torch.dtype] = None, 435 layout: torch.layout = torch.strided, 436 device: Optional[torch.device] = None, 437 requires_grad: bool = False) -> Tensor: 438 return general_hamming(M, sym=sym, dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 439 440 441@_add_docstr( 442 r""" 443Computes the Hann window. 444 445The Hann window is defined as follows: 446 447.. math:: 448 w_n = \frac{1}{2}\ \left[1 - \cos \left( \frac{2 \pi n}{M - 1} \right)\right] = 449 \sin^2 \left( \frac{\pi n}{M - 1} \right) 450 """, 451 r""" 452 453{normalization} 454 455Arguments: 456 {M} 457 458Keyword args: 459 {sym} 460 {dtype} 461 {layout} 462 {device} 463 {requires_grad} 464 465Examples:: 466 467 >>> # Generates a symmetric Hann window. 468 >>> torch.signal.windows.hann(10) 469 tensor([0.0000, 0.1170, 0.4132, 0.7500, 0.9698, 0.9698, 0.7500, 0.4132, 0.1170, 0.0000]) 470 471 >>> # Generates a periodic Hann window. 472 >>> torch.signal.windows.hann(10, sym=False) 473 tensor([0.0000, 0.0955, 0.3455, 0.6545, 0.9045, 1.0000, 0.9045, 0.6545, 0.3455, 0.0955]) 474""".format( 475 **window_common_args 476 ), 477) 478def hann(M: int, 479 *, 480 sym: bool = True, 481 dtype: Optional[torch.dtype] = None, 482 layout: torch.layout = torch.strided, 483 device: Optional[torch.device] = None, 484 requires_grad: bool = False) -> Tensor: 485 return general_hamming(M, 486 alpha=0.5, 487 sym=sym, 488 dtype=dtype, 489 layout=layout, 490 device=device, 491 requires_grad=requires_grad) 492 493 494@_add_docstr( 495 r""" 496Computes the Blackman window. 497 498The Blackman window is defined as follows: 499 500.. math:: 501 w_n = 0.42 - 0.5 \cos \left( \frac{2 \pi n}{M - 1} \right) + 0.08 \cos \left( \frac{4 \pi n}{M - 1} \right) 502 """, 503 r""" 504 505{normalization} 506 507Arguments: 508 {M} 509 510Keyword args: 511 {sym} 512 {dtype} 513 {layout} 514 {device} 515 {requires_grad} 516 517Examples:: 518 519 >>> # Generates a symmetric Blackman window. 520 >>> torch.signal.windows.blackman(5) 521 tensor([-1.4901e-08, 3.4000e-01, 1.0000e+00, 3.4000e-01, -1.4901e-08]) 522 523 >>> # Generates a periodic Blackman window. 524 >>> torch.signal.windows.blackman(5, sym=False) 525 tensor([-1.4901e-08, 2.0077e-01, 8.4923e-01, 8.4923e-01, 2.0077e-01]) 526""".format( 527 **window_common_args 528 ), 529) 530def blackman(M: int, 531 *, 532 sym: bool = True, 533 dtype: Optional[torch.dtype] = None, 534 layout: torch.layout = torch.strided, 535 device: Optional[torch.device] = None, 536 requires_grad: bool = False) -> Tensor: 537 if dtype is None: 538 dtype = torch.get_default_dtype() 539 540 _window_function_checks('blackman', M, dtype, layout) 541 542 return general_cosine(M, a=[0.42, 0.5, 0.08], sym=sym, dtype=dtype, layout=layout, device=device, 543 requires_grad=requires_grad) 544 545 546@_add_docstr( 547 r""" 548Computes the Bartlett window. 549 550The Bartlett window is defined as follows: 551 552.. math:: 553 w_n = 1 - \left| \frac{2n}{M - 1} - 1 \right| = \begin{cases} 554 \frac{2n}{M - 1} & \text{if } 0 \leq n \leq \frac{M - 1}{2} \\ 555 2 - \frac{2n}{M - 1} & \text{if } \frac{M - 1}{2} < n < M \\ \end{cases} 556 """, 557 r""" 558 559{normalization} 560 561Arguments: 562 {M} 563 564Keyword args: 565 {sym} 566 {dtype} 567 {layout} 568 {device} 569 {requires_grad} 570 571Examples:: 572 573 >>> # Generates a symmetric Bartlett window. 574 >>> torch.signal.windows.bartlett(10) 575 tensor([0.0000, 0.2222, 0.4444, 0.6667, 0.8889, 0.8889, 0.6667, 0.4444, 0.2222, 0.0000]) 576 577 >>> # Generates a periodic Bartlett window. 578 >>> torch.signal.windows.bartlett(10, sym=False) 579 tensor([0.0000, 0.2000, 0.4000, 0.6000, 0.8000, 1.0000, 0.8000, 0.6000, 0.4000, 0.2000]) 580""".format( 581 **window_common_args 582 ), 583) 584def bartlett(M: int, 585 *, 586 sym: bool = True, 587 dtype: Optional[torch.dtype] = None, 588 layout: torch.layout = torch.strided, 589 device: Optional[torch.device] = None, 590 requires_grad: bool = False) -> Tensor: 591 if dtype is None: 592 dtype = torch.get_default_dtype() 593 594 _window_function_checks('bartlett', M, dtype, layout) 595 596 if M == 0: 597 return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 598 599 if M == 1: 600 return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 601 602 start = -1 603 constant = 2 / (M if not sym else M - 1) 604 605 k = torch.linspace(start=start, 606 end=start + (M - 1) * constant, 607 steps=M, 608 dtype=dtype, 609 layout=layout, 610 device=device, 611 requires_grad=requires_grad) 612 613 return 1 - torch.abs(k) 614 615 616@_add_docstr( 617 r""" 618Computes the general cosine window. 619 620The general cosine window is defined as follows: 621 622.. math:: 623 w_n = \sum^{M-1}_{i=0} (-1)^i a_i \cos{ \left( \frac{2 \pi i n}{M - 1}\right)} 624 """, 625 r""" 626 627{normalization} 628 629Arguments: 630 {M} 631 632Keyword args: 633 a (Iterable): the coefficients associated to each of the cosine functions. 634 {sym} 635 {dtype} 636 {layout} 637 {device} 638 {requires_grad} 639 640Examples:: 641 642 >>> # Generates a symmetric general cosine window with 3 coefficients. 643 >>> torch.signal.windows.general_cosine(10, a=[0.46, 0.23, 0.31], sym=True) 644 tensor([0.5400, 0.3376, 0.1288, 0.4200, 0.9136, 0.9136, 0.4200, 0.1288, 0.3376, 0.5400]) 645 646 >>> # Generates a periodic general cosine window wit 2 coefficients. 647 >>> torch.signal.windows.general_cosine(10, a=[0.5, 1 - 0.5], sym=False) 648 tensor([0.0000, 0.0955, 0.3455, 0.6545, 0.9045, 1.0000, 0.9045, 0.6545, 0.3455, 0.0955]) 649""".format( 650 **window_common_args 651 ), 652) 653def general_cosine(M, *, 654 a: Iterable, 655 sym: bool = True, 656 dtype: Optional[torch.dtype] = None, 657 layout: torch.layout = torch.strided, 658 device: Optional[torch.device] = None, 659 requires_grad: bool = False) -> Tensor: 660 if dtype is None: 661 dtype = torch.get_default_dtype() 662 663 _window_function_checks('general_cosine', M, dtype, layout) 664 665 if M == 0: 666 return torch.empty((0,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 667 668 if M == 1: 669 return torch.ones((1,), dtype=dtype, layout=layout, device=device, requires_grad=requires_grad) 670 671 if not isinstance(a, Iterable): 672 raise TypeError("Coefficients must be a list/tuple") 673 674 if not a: 675 raise ValueError("Coefficients cannot be empty") 676 677 constant = 2 * torch.pi / (M if not sym else M - 1) 678 679 k = torch.linspace(start=0, 680 end=(M - 1) * constant, 681 steps=M, 682 dtype=dtype, 683 layout=layout, 684 device=device, 685 requires_grad=requires_grad) 686 687 a_i = torch.tensor([(-1) ** i * w for i, w in enumerate(a)], device=device, dtype=dtype, requires_grad=requires_grad) 688 i = torch.arange(a_i.shape[0], dtype=a_i.dtype, device=a_i.device, requires_grad=a_i.requires_grad) 689 return (a_i.unsqueeze(-1) * torch.cos(i.unsqueeze(-1) * k)).sum(0) 690 691 692@_add_docstr( 693 r""" 694Computes the general Hamming window. 695 696The general Hamming window is defined as follows: 697 698.. math:: 699 w_n = \alpha - (1 - \alpha) \cos{ \left( \frac{2 \pi n}{M-1} \right)} 700 """, 701 r""" 702 703{normalization} 704 705Arguments: 706 {M} 707 708Keyword args: 709 alpha (float, optional): the window coefficient. Default: 0.54. 710 {sym} 711 {dtype} 712 {layout} 713 {device} 714 {requires_grad} 715 716Examples:: 717 718 >>> # Generates a symmetric Hamming window with the general Hamming window. 719 >>> torch.signal.windows.general_hamming(10, sym=True) 720 tensor([0.0800, 0.1876, 0.4601, 0.7700, 0.9723, 0.9723, 0.7700, 0.4601, 0.1876, 0.0800]) 721 722 >>> # Generates a periodic Hann window with the general Hamming window. 723 >>> torch.signal.windows.general_hamming(10, alpha=0.5, sym=False) 724 tensor([0.0000, 0.0955, 0.3455, 0.6545, 0.9045, 1.0000, 0.9045, 0.6545, 0.3455, 0.0955]) 725""".format( 726 **window_common_args 727 ), 728) 729def general_hamming(M, 730 *, 731 alpha: float = 0.54, 732 sym: bool = True, 733 dtype: Optional[torch.dtype] = None, 734 layout: torch.layout = torch.strided, 735 device: Optional[torch.device] = None, 736 requires_grad: bool = False) -> Tensor: 737 return general_cosine(M, 738 a=[alpha, 1. - alpha], 739 sym=sym, 740 dtype=dtype, 741 layout=layout, 742 device=device, 743 requires_grad=requires_grad) 744 745 746@_add_docstr( 747 r""" 748Computes the minimum 4-term Blackman-Harris window according to Nuttall. 749 750.. math:: 751 w_n = 1 - 0.36358 \cos{(z_n)} + 0.48917 \cos{(2z_n)} - 0.13659 \cos{(3z_n)} + 0.01064 \cos{(4z_n)} 752 753where :math:`z_n = \frac{2 \pi n}{M}`. 754 """, 755 """ 756 757{normalization} 758 759Arguments: 760 {M} 761 762Keyword args: 763 {sym} 764 {dtype} 765 {layout} 766 {device} 767 {requires_grad} 768 769References:: 770 771 - A. Nuttall, "Some windows with very good sidelobe behavior," 772 IEEE Transactions on Acoustics, Speech, and Signal Processing, vol. 29, no. 1, pp. 84-91, 773 Feb 1981. https://doi.org/10.1109/TASSP.1981.1163506 774 775 - Heinzel G. et al., "Spectrum and spectral density estimation by the Discrete Fourier transform (DFT), 776 including a comprehensive list of window functions and some new flat-top windows", 777 February 15, 2002 https://holometer.fnal.gov/GH_FFT.pdf 778 779Examples:: 780 781 >>> # Generates a symmetric Nutall window. 782 >>> torch.signal.windows.general_hamming(5, sym=True) 783 tensor([3.6280e-04, 2.2698e-01, 1.0000e+00, 2.2698e-01, 3.6280e-04]) 784 785 >>> # Generates a periodic Nuttall window. 786 >>> torch.signal.windows.general_hamming(5, sym=False) 787 tensor([3.6280e-04, 1.1052e-01, 7.9826e-01, 7.9826e-01, 1.1052e-01]) 788""".format( 789 **window_common_args 790 ), 791) 792def nuttall( 793 M: int, 794 *, 795 sym: bool = True, 796 dtype: Optional[torch.dtype] = None, 797 layout: torch.layout = torch.strided, 798 device: Optional[torch.device] = None, 799 requires_grad: bool = False 800) -> Tensor: 801 return general_cosine(M, 802 a=[0.3635819, 0.4891775, 0.1365995, 0.0106411], 803 sym=sym, 804 dtype=dtype, 805 layout=layout, 806 device=device, 807 requires_grad=requires_grad) 808