windows.py 22 KB

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