Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""The suite of window functions.""" 

2 

3import operator 

4import warnings 

5 

6import numpy as np 

7from scipy import linalg, special, fft as sp_fft 

8 

9__all__ = ['boxcar', 'triang', 'parzen', 'bohman', 'blackman', 'nuttall', 

10 'blackmanharris', 'flattop', 'bartlett', 'hanning', 'barthann', 

11 'hamming', 'kaiser', 'gaussian', 'general_cosine','general_gaussian', 

12 'general_hamming', 'chebwin', 'slepian', 'cosine', 'hann', 

13 'exponential', 'tukey', 'dpss', 'get_window'] 

14 

15 

16def _len_guards(M): 

17 """Handle small or incorrect window lengths""" 

18 if int(M) != M or M < 0: 

19 raise ValueError('Window length M must be a non-negative integer') 

20 return M <= 1 

21 

22 

23def _extend(M, sym): 

24 """Extend window by 1 sample if needed for DFT-even symmetry""" 

25 if not sym: 

26 return M + 1, True 

27 else: 

28 return M, False 

29 

30 

31def _truncate(w, needed): 

32 """Truncate window by 1 sample if needed for DFT-even symmetry""" 

33 if needed: 

34 return w[:-1] 

35 else: 

36 return w 

37 

38 

39def general_cosine(M, a, sym=True): 

40 r""" 

41 Generic weighted sum of cosine terms window 

42 

43 Parameters 

44 ---------- 

45 M : int 

46 Number of points in the output window 

47 a : array_like 

48 Sequence of weighting coefficients. This uses the convention of being 

49 centered on the origin, so these will typically all be positive 

50 numbers, not alternating sign. 

51 sym : bool, optional 

52 When True (default), generates a symmetric window, for use in filter 

53 design. 

54 When False, generates a periodic window, for use in spectral analysis. 

55 

56 References 

57 ---------- 

58 .. [1] A. Nuttall, "Some windows with very good sidelobe behavior," IEEE 

59 Transactions on Acoustics, Speech, and Signal Processing, vol. 29, 

60 no. 1, pp. 84-91, Feb 1981. :doi:`10.1109/TASSP.1981.1163506`. 

61 .. [2] Heinzel G. et al., "Spectrum and spectral density estimation by the 

62 Discrete Fourier transform (DFT), including a comprehensive list of 

63 window functions and some new flat-top windows", February 15, 2002 

64 https://holometer.fnal.gov/GH_FFT.pdf 

65 

66 Examples 

67 -------- 

68 Heinzel describes a flat-top window named "HFT90D" with formula: [2]_ 

69 

70 .. math:: w_j = 1 - 1.942604 \cos(z) + 1.340318 \cos(2z) 

71 - 0.440811 \cos(3z) + 0.043097 \cos(4z) 

72 

73 where 

74 

75 .. math:: z = \frac{2 \pi j}{N}, j = 0...N - 1 

76 

77 Since this uses the convention of starting at the origin, to reproduce the 

78 window, we need to convert every other coefficient to a positive number: 

79 

80 >>> HFT90D = [1, 1.942604, 1.340318, 0.440811, 0.043097] 

81 

82 The paper states that the highest sidelobe is at -90.2 dB. Reproduce 

83 Figure 42 by plotting the window and its frequency response, and confirm 

84 the sidelobe level in red: 

85 

86 >>> from scipy.signal.windows import general_cosine 

87 >>> from scipy.fft import fft, fftshift 

88 >>> import matplotlib.pyplot as plt 

89 

90 >>> window = general_cosine(1000, HFT90D, sym=False) 

91 >>> plt.plot(window) 

92 >>> plt.title("HFT90D window") 

93 >>> plt.ylabel("Amplitude") 

94 >>> plt.xlabel("Sample") 

95 

96 >>> plt.figure() 

97 >>> A = fft(window, 10000) / (len(window)/2.0) 

98 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

99 >>> response = np.abs(fftshift(A / abs(A).max())) 

100 >>> response = 20 * np.log10(np.maximum(response, 1e-10)) 

101 >>> plt.plot(freq, response) 

102 >>> plt.axis([-50/1000, 50/1000, -140, 0]) 

103 >>> plt.title("Frequency response of the HFT90D window") 

104 >>> plt.ylabel("Normalized magnitude [dB]") 

105 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

106 >>> plt.axhline(-90.2, color='red') 

107 >>> plt.show() 

108 """ 

109 if _len_guards(M): 

110 return np.ones(M) 

111 M, needs_trunc = _extend(M, sym) 

112 

113 fac = np.linspace(-np.pi, np.pi, M) 

114 w = np.zeros(M) 

115 for k in range(len(a)): 

116 w += a[k] * np.cos(k * fac) 

117 

118 return _truncate(w, needs_trunc) 

119 

120 

121def boxcar(M, sym=True): 

122 """Return a boxcar or rectangular window. 

123 

124 Also known as a rectangular window or Dirichlet window, this is equivalent 

125 to no window at all. 

126 

127 Parameters 

128 ---------- 

129 M : int 

130 Number of points in the output window. If zero or less, an empty 

131 array is returned. 

132 sym : bool, optional 

133 Whether the window is symmetric. (Has no effect for boxcar.) 

134 

135 Returns 

136 ------- 

137 w : ndarray 

138 The window, with the maximum value normalized to 1. 

139 

140 Examples 

141 -------- 

142 Plot the window and its frequency response: 

143 

144 >>> from scipy import signal 

145 >>> from scipy.fft import fft, fftshift 

146 >>> import matplotlib.pyplot as plt 

147 

148 >>> window = signal.boxcar(51) 

149 >>> plt.plot(window) 

150 >>> plt.title("Boxcar window") 

151 >>> plt.ylabel("Amplitude") 

152 >>> plt.xlabel("Sample") 

153 

154 >>> plt.figure() 

155 >>> A = fft(window, 2048) / (len(window)/2.0) 

156 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

157 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

158 >>> plt.plot(freq, response) 

159 >>> plt.axis([-0.5, 0.5, -120, 0]) 

160 >>> plt.title("Frequency response of the boxcar window") 

161 >>> plt.ylabel("Normalized magnitude [dB]") 

162 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

163 

164 """ 

165 if _len_guards(M): 

166 return np.ones(M) 

167 M, needs_trunc = _extend(M, sym) 

168 

169 w = np.ones(M, float) 

170 

171 return _truncate(w, needs_trunc) 

172 

173 

174def triang(M, sym=True): 

175 """Return a triangular window. 

176 

177 Parameters 

178 ---------- 

179 M : int 

180 Number of points in the output window. If zero or less, an empty 

181 array is returned. 

182 sym : bool, optional 

183 When True (default), generates a symmetric window, for use in filter 

184 design. 

185 When False, generates a periodic window, for use in spectral analysis. 

186 

187 Returns 

188 ------- 

189 w : ndarray 

190 The window, with the maximum value normalized to 1 (though the value 1 

191 does not appear if `M` is even and `sym` is True). 

192 

193 See Also 

194 -------- 

195 bartlett : A triangular window that touches zero 

196 

197 Examples 

198 -------- 

199 Plot the window and its frequency response: 

200 

201 >>> from scipy import signal 

202 >>> from scipy.fft import fft, fftshift 

203 >>> import matplotlib.pyplot as plt 

204 

205 >>> window = signal.triang(51) 

206 >>> plt.plot(window) 

207 >>> plt.title("Triangular window") 

208 >>> plt.ylabel("Amplitude") 

209 >>> plt.xlabel("Sample") 

210 

211 >>> plt.figure() 

212 >>> A = fft(window, 2048) / (len(window)/2.0) 

213 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

214 >>> response = np.abs(fftshift(A / abs(A).max())) 

215 >>> response = 20 * np.log10(np.maximum(response, 1e-10)) 

216 >>> plt.plot(freq, response) 

217 >>> plt.axis([-0.5, 0.5, -120, 0]) 

218 >>> plt.title("Frequency response of the triangular window") 

219 >>> plt.ylabel("Normalized magnitude [dB]") 

220 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

221 

222 """ 

223 if _len_guards(M): 

224 return np.ones(M) 

225 M, needs_trunc = _extend(M, sym) 

226 

227 n = np.arange(1, (M + 1) // 2 + 1) 

228 if M % 2 == 0: 

229 w = (2 * n - 1.0) / M 

230 w = np.r_[w, w[::-1]] 

231 else: 

232 w = 2 * n / (M + 1.0) 

233 w = np.r_[w, w[-2::-1]] 

234 

235 return _truncate(w, needs_trunc) 

236 

237 

238def parzen(M, sym=True): 

239 """Return a Parzen window. 

240 

241 Parameters 

242 ---------- 

243 M : int 

244 Number of points in the output window. If zero or less, an empty 

245 array is returned. 

246 sym : bool, optional 

247 When True (default), generates a symmetric window, for use in filter 

248 design. 

249 When False, generates a periodic window, for use in spectral analysis. 

250 

251 Returns 

252 ------- 

253 w : ndarray 

254 The window, with the maximum value normalized to 1 (though the value 1 

255 does not appear if `M` is even and `sym` is True). 

256 

257 References 

258 ---------- 

259 .. [1] E. Parzen, "Mathematical Considerations in the Estimation of 

260 Spectra", Technometrics, Vol. 3, No. 2 (May, 1961), pp. 167-190 

261 

262 Examples 

263 -------- 

264 Plot the window and its frequency response: 

265 

266 >>> from scipy import signal 

267 >>> from scipy.fft import fft, fftshift 

268 >>> import matplotlib.pyplot as plt 

269 

270 >>> window = signal.parzen(51) 

271 >>> plt.plot(window) 

272 >>> plt.title("Parzen window") 

273 >>> plt.ylabel("Amplitude") 

274 >>> plt.xlabel("Sample") 

275 

276 >>> plt.figure() 

277 >>> A = fft(window, 2048) / (len(window)/2.0) 

278 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

279 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

280 >>> plt.plot(freq, response) 

281 >>> plt.axis([-0.5, 0.5, -120, 0]) 

282 >>> plt.title("Frequency response of the Parzen window") 

283 >>> plt.ylabel("Normalized magnitude [dB]") 

284 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

285 

286 """ 

287 if _len_guards(M): 

288 return np.ones(M) 

289 M, needs_trunc = _extend(M, sym) 

290 

291 n = np.arange(-(M - 1) / 2.0, (M - 1) / 2.0 + 0.5, 1.0) 

292 na = np.extract(n < -(M - 1) / 4.0, n) 

293 nb = np.extract(abs(n) <= (M - 1) / 4.0, n) 

294 wa = 2 * (1 - np.abs(na) / (M / 2.0)) ** 3.0 

295 wb = (1 - 6 * (np.abs(nb) / (M / 2.0)) ** 2.0 + 

296 6 * (np.abs(nb) / (M / 2.0)) ** 3.0) 

297 w = np.r_[wa, wb, wa[::-1]] 

298 

299 return _truncate(w, needs_trunc) 

300 

301 

302def bohman(M, sym=True): 

303 """Return a Bohman window. 

304 

305 Parameters 

306 ---------- 

307 M : int 

308 Number of points in the output window. If zero or less, an empty 

309 array is returned. 

310 sym : bool, optional 

311 When True (default), generates a symmetric window, for use in filter 

312 design. 

313 When False, generates a periodic window, for use in spectral analysis. 

314 

315 Returns 

316 ------- 

317 w : ndarray 

318 The window, with the maximum value normalized to 1 (though the value 1 

319 does not appear if `M` is even and `sym` is True). 

320 

321 Examples 

322 -------- 

323 Plot the window and its frequency response: 

324 

325 >>> from scipy import signal 

326 >>> from scipy.fft import fft, fftshift 

327 >>> import matplotlib.pyplot as plt 

328 

329 >>> window = signal.bohman(51) 

330 >>> plt.plot(window) 

331 >>> plt.title("Bohman window") 

332 >>> plt.ylabel("Amplitude") 

333 >>> plt.xlabel("Sample") 

334 

335 >>> plt.figure() 

336 >>> A = fft(window, 2048) / (len(window)/2.0) 

337 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

338 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

339 >>> plt.plot(freq, response) 

340 >>> plt.axis([-0.5, 0.5, -120, 0]) 

341 >>> plt.title("Frequency response of the Bohman window") 

342 >>> plt.ylabel("Normalized magnitude [dB]") 

343 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

344 

345 """ 

346 if _len_guards(M): 

347 return np.ones(M) 

348 M, needs_trunc = _extend(M, sym) 

349 

350 fac = np.abs(np.linspace(-1, 1, M)[1:-1]) 

351 w = (1 - fac) * np.cos(np.pi * fac) + 1.0 / np.pi * np.sin(np.pi * fac) 

352 w = np.r_[0, w, 0] 

353 

354 return _truncate(w, needs_trunc) 

355 

356 

357def blackman(M, sym=True): 

358 r""" 

359 Return a Blackman window. 

360 

361 The Blackman window is a taper formed by using the first three terms of 

362 a summation of cosines. It was designed to have close to the minimal 

363 leakage possible. It is close to optimal, only slightly worse than a 

364 Kaiser window. 

365 

366 Parameters 

367 ---------- 

368 M : int 

369 Number of points in the output window. If zero or less, an empty 

370 array is returned. 

371 sym : bool, optional 

372 When True (default), generates a symmetric window, for use in filter 

373 design. 

374 When False, generates a periodic window, for use in spectral analysis. 

375 

376 Returns 

377 ------- 

378 w : ndarray 

379 The window, with the maximum value normalized to 1 (though the value 1 

380 does not appear if `M` is even and `sym` is True). 

381 

382 Notes 

383 ----- 

384 The Blackman window is defined as 

385 

386 .. math:: w(n) = 0.42 - 0.5 \cos(2\pi n/M) + 0.08 \cos(4\pi n/M) 

387 

388 The "exact Blackman" window was designed to null out the third and fourth 

389 sidelobes, but has discontinuities at the boundaries, resulting in a 

390 6 dB/oct fall-off. This window is an approximation of the "exact" window, 

391 which does not null the sidelobes as well, but is smooth at the edges, 

392 improving the fall-off rate to 18 dB/oct. [3]_ 

393 

394 Most references to the Blackman window come from the signal processing 

395 literature, where it is used as one of many windowing functions for 

396 smoothing values. It is also known as an apodization (which means 

397 "removing the foot", i.e. smoothing discontinuities at the beginning 

398 and end of the sampled signal) or tapering function. It is known as a 

399 "near optimal" tapering function, almost as good (by some measures) 

400 as the Kaiser window. 

401 

402 References 

403 ---------- 

404 .. [1] Blackman, R.B. and Tukey, J.W., (1958) The measurement of power 

405 spectra, Dover Publications, New York. 

406 .. [2] Oppenheim, A.V., and R.W. Schafer. Discrete-Time Signal Processing. 

407 Upper Saddle River, NJ: Prentice-Hall, 1999, pp. 468-471. 

408 .. [3] Harris, Fredric J. (Jan 1978). "On the use of Windows for Harmonic 

409 Analysis with the Discrete Fourier Transform". Proceedings of the 

410 IEEE 66 (1): 51-83. :doi:`10.1109/PROC.1978.10837`. 

411 

412 Examples 

413 -------- 

414 Plot the window and its frequency response: 

415 

416 >>> from scipy import signal 

417 >>> from scipy.fft import fft, fftshift 

418 >>> import matplotlib.pyplot as plt 

419 

420 >>> window = signal.blackman(51) 

421 >>> plt.plot(window) 

422 >>> plt.title("Blackman window") 

423 >>> plt.ylabel("Amplitude") 

424 >>> plt.xlabel("Sample") 

425 

426 >>> plt.figure() 

427 >>> A = fft(window, 2048) / (len(window)/2.0) 

428 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

429 >>> response = np.abs(fftshift(A / abs(A).max())) 

430 >>> response = 20 * np.log10(np.maximum(response, 1e-10)) 

431 >>> plt.plot(freq, response) 

432 >>> plt.axis([-0.5, 0.5, -120, 0]) 

433 >>> plt.title("Frequency response of the Blackman window") 

434 >>> plt.ylabel("Normalized magnitude [dB]") 

435 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

436 

437 """ 

438 # Docstring adapted from NumPy's blackman function 

439 return general_cosine(M, [0.42, 0.50, 0.08], sym) 

440 

441 

442def nuttall(M, sym=True): 

443 """Return a minimum 4-term Blackman-Harris window according to Nuttall. 

444 

445 This variation is called "Nuttall4c" by Heinzel. [2]_ 

446 

447 Parameters 

448 ---------- 

449 M : int 

450 Number of points in the output window. If zero or less, an empty 

451 array is returned. 

452 sym : bool, optional 

453 When True (default), generates a symmetric window, for use in filter 

454 design. 

455 When False, generates a periodic window, for use in spectral analysis. 

456 

457 Returns 

458 ------- 

459 w : ndarray 

460 The window, with the maximum value normalized to 1 (though the value 1 

461 does not appear if `M` is even and `sym` is True). 

462 

463 References 

464 ---------- 

465 .. [1] A. Nuttall, "Some windows with very good sidelobe behavior," IEEE 

466 Transactions on Acoustics, Speech, and Signal Processing, vol. 29, 

467 no. 1, pp. 84-91, Feb 1981. :doi:`10.1109/TASSP.1981.1163506`. 

468 .. [2] Heinzel G. et al., "Spectrum and spectral density estimation by the 

469 Discrete Fourier transform (DFT), including a comprehensive list of 

470 window functions and some new flat-top windows", February 15, 2002 

471 https://holometer.fnal.gov/GH_FFT.pdf 

472 

473 Examples 

474 -------- 

475 Plot the window and its frequency response: 

476 

477 >>> from scipy import signal 

478 >>> from scipy.fft import fft, fftshift 

479 >>> import matplotlib.pyplot as plt 

480 

481 >>> window = signal.nuttall(51) 

482 >>> plt.plot(window) 

483 >>> plt.title("Nuttall window") 

484 >>> plt.ylabel("Amplitude") 

485 >>> plt.xlabel("Sample") 

486 

487 >>> plt.figure() 

488 >>> A = fft(window, 2048) / (len(window)/2.0) 

489 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

490 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

491 >>> plt.plot(freq, response) 

492 >>> plt.axis([-0.5, 0.5, -120, 0]) 

493 >>> plt.title("Frequency response of the Nuttall window") 

494 >>> plt.ylabel("Normalized magnitude [dB]") 

495 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

496 

497 """ 

498 return general_cosine(M, [0.3635819, 0.4891775, 0.1365995, 0.0106411], sym) 

499 

500 

501def blackmanharris(M, sym=True): 

502 """Return a minimum 4-term Blackman-Harris window. 

503 

504 Parameters 

505 ---------- 

506 M : int 

507 Number of points in the output window. If zero or less, an empty 

508 array is returned. 

509 sym : bool, optional 

510 When True (default), generates a symmetric window, for use in filter 

511 design. 

512 When False, generates a periodic window, for use in spectral analysis. 

513 

514 Returns 

515 ------- 

516 w : ndarray 

517 The window, with the maximum value normalized to 1 (though the value 1 

518 does not appear if `M` is even and `sym` is True). 

519 

520 Examples 

521 -------- 

522 Plot the window and its frequency response: 

523 

524 >>> from scipy import signal 

525 >>> from scipy.fft import fft, fftshift 

526 >>> import matplotlib.pyplot as plt 

527 

528 >>> window = signal.blackmanharris(51) 

529 >>> plt.plot(window) 

530 >>> plt.title("Blackman-Harris window") 

531 >>> plt.ylabel("Amplitude") 

532 >>> plt.xlabel("Sample") 

533 

534 >>> plt.figure() 

535 >>> A = fft(window, 2048) / (len(window)/2.0) 

536 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

537 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

538 >>> plt.plot(freq, response) 

539 >>> plt.axis([-0.5, 0.5, -120, 0]) 

540 >>> plt.title("Frequency response of the Blackman-Harris window") 

541 >>> plt.ylabel("Normalized magnitude [dB]") 

542 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

543 

544 """ 

545 return general_cosine(M, [0.35875, 0.48829, 0.14128, 0.01168], sym) 

546 

547 

548def flattop(M, sym=True): 

549 """Return a flat top window. 

550 

551 Parameters 

552 ---------- 

553 M : int 

554 Number of points in the output window. If zero or less, an empty 

555 array is returned. 

556 sym : bool, optional 

557 When True (default), generates a symmetric window, for use in filter 

558 design. 

559 When False, generates a periodic window, for use in spectral analysis. 

560 

561 Returns 

562 ------- 

563 w : ndarray 

564 The window, with the maximum value normalized to 1 (though the value 1 

565 does not appear if `M` is even and `sym` is True). 

566 

567 Notes 

568 ----- 

569 Flat top windows are used for taking accurate measurements of signal 

570 amplitude in the frequency domain, with minimal scalloping error from the 

571 center of a frequency bin to its edges, compared to others. This is a 

572 5th-order cosine window, with the 5 terms optimized to make the main lobe 

573 maximally flat. [1]_ 

574 

575 References 

576 ---------- 

577 .. [1] D'Antona, Gabriele, and A. Ferrero, "Digital Signal Processing for 

578 Measurement Systems", Springer Media, 2006, p. 70 

579 :doi:`10.1007/0-387-28666-7`. 

580 

581 Examples 

582 -------- 

583 Plot the window and its frequency response: 

584 

585 >>> from scipy import signal 

586 >>> from scipy.fft import fft, fftshift 

587 >>> import matplotlib.pyplot as plt 

588 

589 >>> window = signal.flattop(51) 

590 >>> plt.plot(window) 

591 >>> plt.title("Flat top window") 

592 >>> plt.ylabel("Amplitude") 

593 >>> plt.xlabel("Sample") 

594 

595 >>> plt.figure() 

596 >>> A = fft(window, 2048) / (len(window)/2.0) 

597 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

598 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

599 >>> plt.plot(freq, response) 

600 >>> plt.axis([-0.5, 0.5, -120, 0]) 

601 >>> plt.title("Frequency response of the flat top window") 

602 >>> plt.ylabel("Normalized magnitude [dB]") 

603 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

604 

605 """ 

606 a = [0.21557895, 0.41663158, 0.277263158, 0.083578947, 0.006947368] 

607 return general_cosine(M, a, sym) 

608 

609 

610def bartlett(M, sym=True): 

611 r""" 

612 Return a Bartlett window. 

613 

614 The Bartlett window is very similar to a triangular window, except 

615 that the end points are at zero. It is often used in signal 

616 processing for tapering a signal, without generating too much 

617 ripple in the frequency domain. 

618 

619 Parameters 

620 ---------- 

621 M : int 

622 Number of points in the output window. If zero or less, an empty 

623 array is returned. 

624 sym : bool, optional 

625 When True (default), generates a symmetric window, for use in filter 

626 design. 

627 When False, generates a periodic window, for use in spectral analysis. 

628 

629 Returns 

630 ------- 

631 w : ndarray 

632 The triangular window, with the first and last samples equal to zero 

633 and the maximum value normalized to 1 (though the value 1 does not 

634 appear if `M` is even and `sym` is True). 

635 

636 See Also 

637 -------- 

638 triang : A triangular window that does not touch zero at the ends 

639 

640 Notes 

641 ----- 

642 The Bartlett window is defined as 

643 

644 .. math:: w(n) = \frac{2}{M-1} \left( 

645 \frac{M-1}{2} - \left|n - \frac{M-1}{2}\right| 

646 \right) 

647 

648 Most references to the Bartlett window come from the signal 

649 processing literature, where it is used as one of many windowing 

650 functions for smoothing values. Note that convolution with this 

651 window produces linear interpolation. It is also known as an 

652 apodization (which means"removing the foot", i.e. smoothing 

653 discontinuities at the beginning and end of the sampled signal) or 

654 tapering function. The Fourier transform of the Bartlett is the product 

655 of two sinc functions. 

656 Note the excellent discussion in Kanasewich. [2]_ 

657 

658 References 

659 ---------- 

660 .. [1] M.S. Bartlett, "Periodogram Analysis and Continuous Spectra", 

661 Biometrika 37, 1-16, 1950. 

662 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", 

663 The University of Alberta Press, 1975, pp. 109-110. 

664 .. [3] A.V. Oppenheim and R.W. Schafer, "Discrete-Time Signal 

665 Processing", Prentice-Hall, 1999, pp. 468-471. 

666 .. [4] Wikipedia, "Window function", 

667 https://en.wikipedia.org/wiki/Window_function 

668 .. [5] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, 

669 "Numerical Recipes", Cambridge University Press, 1986, page 429. 

670 

671 Examples 

672 -------- 

673 Plot the window and its frequency response: 

674 

675 >>> from scipy import signal 

676 >>> from scipy.fft import fft, fftshift 

677 >>> import matplotlib.pyplot as plt 

678 

679 >>> window = signal.bartlett(51) 

680 >>> plt.plot(window) 

681 >>> plt.title("Bartlett window") 

682 >>> plt.ylabel("Amplitude") 

683 >>> plt.xlabel("Sample") 

684 

685 >>> plt.figure() 

686 >>> A = fft(window, 2048) / (len(window)/2.0) 

687 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

688 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

689 >>> plt.plot(freq, response) 

690 >>> plt.axis([-0.5, 0.5, -120, 0]) 

691 >>> plt.title("Frequency response of the Bartlett window") 

692 >>> plt.ylabel("Normalized magnitude [dB]") 

693 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

694 

695 """ 

696 # Docstring adapted from NumPy's bartlett function 

697 if _len_guards(M): 

698 return np.ones(M) 

699 M, needs_trunc = _extend(M, sym) 

700 

701 n = np.arange(0, M) 

702 w = np.where(np.less_equal(n, (M - 1) / 2.0), 

703 2.0 * n / (M - 1), 2.0 - 2.0 * n / (M - 1)) 

704 

705 return _truncate(w, needs_trunc) 

706 

707 

708def hann(M, sym=True): 

709 r""" 

710 Return a Hann window. 

711 

712 The Hann window is a taper formed by using a raised cosine or sine-squared 

713 with ends that touch zero. 

714 

715 Parameters 

716 ---------- 

717 M : int 

718 Number of points in the output window. If zero or less, an empty 

719 array is returned. 

720 sym : bool, optional 

721 When True (default), generates a symmetric window, for use in filter 

722 design. 

723 When False, generates a periodic window, for use in spectral analysis. 

724 

725 Returns 

726 ------- 

727 w : ndarray 

728 The window, with the maximum value normalized to 1 (though the value 1 

729 does not appear if `M` is even and `sym` is True). 

730 

731 Notes 

732 ----- 

733 The Hann window is defined as 

734 

735 .. math:: w(n) = 0.5 - 0.5 \cos\left(\frac{2\pi{n}}{M-1}\right) 

736 \qquad 0 \leq n \leq M-1 

737 

738 The window was named for Julius von Hann, an Austrian meteorologist. It is 

739 also known as the Cosine Bell. It is sometimes erroneously referred to as 

740 the "Hanning" window, from the use of "hann" as a verb in the original 

741 paper and confusion with the very similar Hamming window. 

742 

743 Most references to the Hann window come from the signal processing 

744 literature, where it is used as one of many windowing functions for 

745 smoothing values. It is also known as an apodization (which means 

746 "removing the foot", i.e. smoothing discontinuities at the beginning 

747 and end of the sampled signal) or tapering function. 

748 

749 References 

750 ---------- 

751 .. [1] Blackman, R.B. and Tukey, J.W., (1958) The measurement of power 

752 spectra, Dover Publications, New York. 

753 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", 

754 The University of Alberta Press, 1975, pp. 106-108. 

755 .. [3] Wikipedia, "Window function", 

756 https://en.wikipedia.org/wiki/Window_function 

757 .. [4] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, 

758 "Numerical Recipes", Cambridge University Press, 1986, page 425. 

759 

760 Examples 

761 -------- 

762 Plot the window and its frequency response: 

763 

764 >>> from scipy import signal 

765 >>> from scipy.fft import fft, fftshift 

766 >>> import matplotlib.pyplot as plt 

767 

768 >>> window = signal.hann(51) 

769 >>> plt.plot(window) 

770 >>> plt.title("Hann window") 

771 >>> plt.ylabel("Amplitude") 

772 >>> plt.xlabel("Sample") 

773 

774 >>> plt.figure() 

775 >>> A = fft(window, 2048) / (len(window)/2.0) 

776 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

777 >>> response = np.abs(fftshift(A / abs(A).max())) 

778 >>> response = 20 * np.log10(np.maximum(response, 1e-10)) 

779 >>> plt.plot(freq, response) 

780 >>> plt.axis([-0.5, 0.5, -120, 0]) 

781 >>> plt.title("Frequency response of the Hann window") 

782 >>> plt.ylabel("Normalized magnitude [dB]") 

783 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

784 

785 """ 

786 # Docstring adapted from NumPy's hanning function 

787 return general_hamming(M, 0.5, sym) 

788 

789 

790@np.deprecate(new_name='scipy.signal.windows.hann') 

791def hanning(*args, **kwargs): 

792 return hann(*args, **kwargs) 

793 

794 

795def tukey(M, alpha=0.5, sym=True): 

796 r"""Return a Tukey window, also known as a tapered cosine window. 

797 

798 Parameters 

799 ---------- 

800 M : int 

801 Number of points in the output window. If zero or less, an empty 

802 array is returned. 

803 alpha : float, optional 

804 Shape parameter of the Tukey window, representing the fraction of the 

805 window inside the cosine tapered region. 

806 If zero, the Tukey window is equivalent to a rectangular window. 

807 If one, the Tukey window is equivalent to a Hann window. 

808 sym : bool, optional 

809 When True (default), generates a symmetric window, for use in filter 

810 design. 

811 When False, generates a periodic window, for use in spectral analysis. 

812 

813 Returns 

814 ------- 

815 w : ndarray 

816 The window, with the maximum value normalized to 1 (though the value 1 

817 does not appear if `M` is even and `sym` is True). 

818 

819 References 

820 ---------- 

821 .. [1] Harris, Fredric J. (Jan 1978). "On the use of Windows for Harmonic 

822 Analysis with the Discrete Fourier Transform". Proceedings of the 

823 IEEE 66 (1): 51-83. :doi:`10.1109/PROC.1978.10837` 

824 .. [2] Wikipedia, "Window function", 

825 https://en.wikipedia.org/wiki/Window_function#Tukey_window 

826 

827 Examples 

828 -------- 

829 Plot the window and its frequency response: 

830 

831 >>> from scipy import signal 

832 >>> from scipy.fft import fft, fftshift 

833 >>> import matplotlib.pyplot as plt 

834 

835 >>> window = signal.tukey(51) 

836 >>> plt.plot(window) 

837 >>> plt.title("Tukey window") 

838 >>> plt.ylabel("Amplitude") 

839 >>> plt.xlabel("Sample") 

840 >>> plt.ylim([0, 1.1]) 

841 

842 >>> plt.figure() 

843 >>> A = fft(window, 2048) / (len(window)/2.0) 

844 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

845 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

846 >>> plt.plot(freq, response) 

847 >>> plt.axis([-0.5, 0.5, -120, 0]) 

848 >>> plt.title("Frequency response of the Tukey window") 

849 >>> plt.ylabel("Normalized magnitude [dB]") 

850 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

851 

852 """ 

853 if _len_guards(M): 

854 return np.ones(M) 

855 

856 if alpha <= 0: 

857 return np.ones(M, 'd') 

858 elif alpha >= 1.0: 

859 return hann(M, sym=sym) 

860 

861 M, needs_trunc = _extend(M, sym) 

862 

863 n = np.arange(0, M) 

864 width = int(np.floor(alpha*(M-1)/2.0)) 

865 n1 = n[0:width+1] 

866 n2 = n[width+1:M-width-1] 

867 n3 = n[M-width-1:] 

868 

869 w1 = 0.5 * (1 + np.cos(np.pi * (-1 + 2.0*n1/alpha/(M-1)))) 

870 w2 = np.ones(n2.shape) 

871 w3 = 0.5 * (1 + np.cos(np.pi * (-2.0/alpha + 1 + 2.0*n3/alpha/(M-1)))) 

872 

873 w = np.concatenate((w1, w2, w3)) 

874 

875 return _truncate(w, needs_trunc) 

876 

877 

878def barthann(M, sym=True): 

879 """Return a modified Bartlett-Hann window. 

880 

881 Parameters 

882 ---------- 

883 M : int 

884 Number of points in the output window. If zero or less, an empty 

885 array is returned. 

886 sym : bool, optional 

887 When True (default), generates a symmetric window, for use in filter 

888 design. 

889 When False, generates a periodic window, for use in spectral analysis. 

890 

891 Returns 

892 ------- 

893 w : ndarray 

894 The window, with the maximum value normalized to 1 (though the value 1 

895 does not appear if `M` is even and `sym` is True). 

896 

897 Examples 

898 -------- 

899 Plot the window and its frequency response: 

900 

901 >>> from scipy import signal 

902 >>> from scipy.fft import fft, fftshift 

903 >>> import matplotlib.pyplot as plt 

904 

905 >>> window = signal.barthann(51) 

906 >>> plt.plot(window) 

907 >>> plt.title("Bartlett-Hann window") 

908 >>> plt.ylabel("Amplitude") 

909 >>> plt.xlabel("Sample") 

910 

911 >>> plt.figure() 

912 >>> A = fft(window, 2048) / (len(window)/2.0) 

913 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

914 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

915 >>> plt.plot(freq, response) 

916 >>> plt.axis([-0.5, 0.5, -120, 0]) 

917 >>> plt.title("Frequency response of the Bartlett-Hann window") 

918 >>> plt.ylabel("Normalized magnitude [dB]") 

919 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

920 

921 """ 

922 if _len_guards(M): 

923 return np.ones(M) 

924 M, needs_trunc = _extend(M, sym) 

925 

926 n = np.arange(0, M) 

927 fac = np.abs(n / (M - 1.0) - 0.5) 

928 w = 0.62 - 0.48 * fac + 0.38 * np.cos(2 * np.pi * fac) 

929 

930 return _truncate(w, needs_trunc) 

931 

932 

933def general_hamming(M, alpha, sym=True): 

934 r"""Return a generalized Hamming window. 

935 

936 The generalized Hamming window is constructed by multiplying a rectangular 

937 window by one period of a cosine function [1]_. 

938 

939 Parameters 

940 ---------- 

941 M : int 

942 Number of points in the output window. If zero or less, an empty 

943 array is returned. 

944 alpha : float 

945 The window coefficient, :math:`\alpha` 

946 sym : bool, optional 

947 When True (default), generates a symmetric window, for use in filter 

948 design. 

949 When False, generates a periodic window, for use in spectral analysis. 

950 

951 Returns 

952 ------- 

953 w : ndarray 

954 The window, with the maximum value normalized to 1 (though the value 1 

955 does not appear if `M` is even and `sym` is True). 

956 

957 Notes 

958 ----- 

959 The generalized Hamming window is defined as 

960 

961 .. math:: w(n) = \alpha - \left(1 - \alpha\right) \cos\left(\frac{2\pi{n}}{M-1}\right) 

962 \qquad 0 \leq n \leq M-1 

963 

964 Both the common Hamming window and Hann window are special cases of the 

965 generalized Hamming window with :math:`\alpha` = 0.54 and :math:`\alpha` = 

966 0.5, respectively [2]_. 

967 

968 See Also 

969 -------- 

970 hamming, hann 

971 

972 Examples 

973 -------- 

974 The Sentinel-1A/B Instrument Processing Facility uses generalized Hamming 

975 windows in the processing of spaceborne Synthetic Aperture Radar (SAR) 

976 data [3]_. The facility uses various values for the :math:`\alpha` 

977 parameter based on operating mode of the SAR instrument. Some common 

978 :math:`\alpha` values include 0.75, 0.7 and 0.52 [4]_. As an example, we 

979 plot these different windows. 

980 

981 >>> from scipy.signal.windows import general_hamming 

982 >>> from scipy.fft import fft, fftshift 

983 >>> import matplotlib.pyplot as plt 

984 

985 >>> fig1, spatial_plot = plt.subplots() 

986 >>> spatial_plot.set_title("Generalized Hamming Windows") 

987 >>> spatial_plot.set_ylabel("Amplitude") 

988 >>> spatial_plot.set_xlabel("Sample") 

989 

990 >>> fig2, freq_plot = plt.subplots() 

991 >>> freq_plot.set_title("Frequency Responses") 

992 >>> freq_plot.set_ylabel("Normalized magnitude [dB]") 

993 >>> freq_plot.set_xlabel("Normalized frequency [cycles per sample]") 

994 

995 >>> for alpha in [0.75, 0.7, 0.52]: 

996 ... window = general_hamming(41, alpha) 

997 ... spatial_plot.plot(window, label="{:.2f}".format(alpha)) 

998 ... A = fft(window, 2048) / (len(window)/2.0) 

999 ... freq = np.linspace(-0.5, 0.5, len(A)) 

1000 ... response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1001 ... freq_plot.plot(freq, response, label="{:.2f}".format(alpha)) 

1002 >>> freq_plot.legend(loc="upper right") 

1003 >>> spatial_plot.legend(loc="upper right") 

1004 

1005 References 

1006 ---------- 

1007 .. [1] DSPRelated, "Generalized Hamming Window Family", 

1008 https://www.dsprelated.com/freebooks/sasp/Generalized_Hamming_Window_Family.html 

1009 .. [2] Wikipedia, "Window function", 

1010 https://en.wikipedia.org/wiki/Window_function 

1011 .. [3] Riccardo Piantanida ESA, "Sentinel-1 Level 1 Detailed Algorithm 

1012 Definition", 

1013 https://sentinel.esa.int/documents/247904/1877131/Sentinel-1-Level-1-Detailed-Algorithm-Definition 

1014 .. [4] Matthieu Bourbigot ESA, "Sentinel-1 Product Definition", 

1015 https://sentinel.esa.int/documents/247904/1877131/Sentinel-1-Product-Definition 

1016 """ 

1017 return general_cosine(M, [alpha, 1. - alpha], sym) 

1018 

1019 

1020def hamming(M, sym=True): 

1021 r"""Return a Hamming window. 

1022 

1023 The Hamming window is a taper formed by using a raised cosine with 

1024 non-zero endpoints, optimized to minimize the nearest side lobe. 

1025 

1026 Parameters 

1027 ---------- 

1028 M : int 

1029 Number of points in the output window. If zero or less, an empty 

1030 array is returned. 

1031 sym : bool, optional 

1032 When True (default), generates a symmetric window, for use in filter 

1033 design. 

1034 When False, generates a periodic window, for use in spectral analysis. 

1035 

1036 Returns 

1037 ------- 

1038 w : ndarray 

1039 The window, with the maximum value normalized to 1 (though the value 1 

1040 does not appear if `M` is even and `sym` is True). 

1041 

1042 Notes 

1043 ----- 

1044 The Hamming window is defined as 

1045 

1046 .. math:: w(n) = 0.54 - 0.46 \cos\left(\frac{2\pi{n}}{M-1}\right) 

1047 \qquad 0 \leq n \leq M-1 

1048 

1049 The Hamming was named for R. W. Hamming, an associate of J. W. Tukey and 

1050 is described in Blackman and Tukey. It was recommended for smoothing the 

1051 truncated autocovariance function in the time domain. 

1052 Most references to the Hamming window come from the signal processing 

1053 literature, where it is used as one of many windowing functions for 

1054 smoothing values. It is also known as an apodization (which means 

1055 "removing the foot", i.e. smoothing discontinuities at the beginning 

1056 and end of the sampled signal) or tapering function. 

1057 

1058 References 

1059 ---------- 

1060 .. [1] Blackman, R.B. and Tukey, J.W., (1958) The measurement of power 

1061 spectra, Dover Publications, New York. 

1062 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", The 

1063 University of Alberta Press, 1975, pp. 109-110. 

1064 .. [3] Wikipedia, "Window function", 

1065 https://en.wikipedia.org/wiki/Window_function 

1066 .. [4] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, 

1067 "Numerical Recipes", Cambridge University Press, 1986, page 425. 

1068 

1069 Examples 

1070 -------- 

1071 Plot the window and its frequency response: 

1072 

1073 >>> from scipy import signal 

1074 >>> from scipy.fft import fft, fftshift 

1075 >>> import matplotlib.pyplot as plt 

1076 

1077 >>> window = signal.hamming(51) 

1078 >>> plt.plot(window) 

1079 >>> plt.title("Hamming window") 

1080 >>> plt.ylabel("Amplitude") 

1081 >>> plt.xlabel("Sample") 

1082 

1083 >>> plt.figure() 

1084 >>> A = fft(window, 2048) / (len(window)/2.0) 

1085 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1086 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1087 >>> plt.plot(freq, response) 

1088 >>> plt.axis([-0.5, 0.5, -120, 0]) 

1089 >>> plt.title("Frequency response of the Hamming window") 

1090 >>> plt.ylabel("Normalized magnitude [dB]") 

1091 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1092 

1093 """ 

1094 # Docstring adapted from NumPy's hamming function 

1095 return general_hamming(M, 0.54, sym) 

1096 

1097 

1098def kaiser(M, beta, sym=True): 

1099 r"""Return a Kaiser window. 

1100 

1101 The Kaiser window is a taper formed by using a Bessel function. 

1102 

1103 Parameters 

1104 ---------- 

1105 M : int 

1106 Number of points in the output window. If zero or less, an empty 

1107 array is returned. 

1108 beta : float 

1109 Shape parameter, determines trade-off between main-lobe width and 

1110 side lobe level. As beta gets large, the window narrows. 

1111 sym : bool, optional 

1112 When True (default), generates a symmetric window, for use in filter 

1113 design. 

1114 When False, generates a periodic window, for use in spectral analysis. 

1115 

1116 Returns 

1117 ------- 

1118 w : ndarray 

1119 The window, with the maximum value normalized to 1 (though the value 1 

1120 does not appear if `M` is even and `sym` is True). 

1121 

1122 Notes 

1123 ----- 

1124 The Kaiser window is defined as 

1125 

1126 .. math:: w(n) = I_0\left( \beta \sqrt{1-\frac{4n^2}{(M-1)^2}} 

1127 \right)/I_0(\beta) 

1128 

1129 with 

1130 

1131 .. math:: \quad -\frac{M-1}{2} \leq n \leq \frac{M-1}{2}, 

1132 

1133 where :math:`I_0` is the modified zeroth-order Bessel function. 

1134 

1135 The Kaiser was named for Jim Kaiser, who discovered a simple approximation 

1136 to the DPSS window based on Bessel functions. 

1137 The Kaiser window is a very good approximation to the Digital Prolate 

1138 Spheroidal Sequence, or Slepian window, which is the transform which 

1139 maximizes the energy in the main lobe of the window relative to total 

1140 energy. 

1141 

1142 The Kaiser can approximate other windows by varying the beta parameter. 

1143 (Some literature uses alpha = beta/pi.) [4]_ 

1144 

1145 ==== ======================= 

1146 beta Window shape 

1147 ==== ======================= 

1148 0 Rectangular 

1149 5 Similar to a Hamming 

1150 6 Similar to a Hann 

1151 8.6 Similar to a Blackman 

1152 ==== ======================= 

1153 

1154 A beta value of 14 is probably a good starting point. Note that as beta 

1155 gets large, the window narrows, and so the number of samples needs to be 

1156 large enough to sample the increasingly narrow spike, otherwise NaNs will 

1157 be returned. 

1158 

1159 Most references to the Kaiser window come from the signal processing 

1160 literature, where it is used as one of many windowing functions for 

1161 smoothing values. It is also known as an apodization (which means 

1162 "removing the foot", i.e. smoothing discontinuities at the beginning 

1163 and end of the sampled signal) or tapering function. 

1164 

1165 References 

1166 ---------- 

1167 .. [1] J. F. Kaiser, "Digital Filters" - Ch 7 in "Systems analysis by 

1168 digital computer", Editors: F.F. Kuo and J.F. Kaiser, p 218-285. 

1169 John Wiley and Sons, New York, (1966). 

1170 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", The 

1171 University of Alberta Press, 1975, pp. 177-178. 

1172 .. [3] Wikipedia, "Window function", 

1173 https://en.wikipedia.org/wiki/Window_function 

1174 .. [4] F. J. Harris, "On the use of windows for harmonic analysis with the 

1175 discrete Fourier transform," Proceedings of the IEEE, vol. 66, 

1176 no. 1, pp. 51-83, Jan. 1978. :doi:`10.1109/PROC.1978.10837`. 

1177 

1178 Examples 

1179 -------- 

1180 Plot the window and its frequency response: 

1181 

1182 >>> from scipy import signal 

1183 >>> from scipy.fft import fft, fftshift 

1184 >>> import matplotlib.pyplot as plt 

1185 

1186 >>> window = signal.kaiser(51, beta=14) 

1187 >>> plt.plot(window) 

1188 >>> plt.title(r"Kaiser window ($\beta$=14)") 

1189 >>> plt.ylabel("Amplitude") 

1190 >>> plt.xlabel("Sample") 

1191 

1192 >>> plt.figure() 

1193 >>> A = fft(window, 2048) / (len(window)/2.0) 

1194 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1195 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1196 >>> plt.plot(freq, response) 

1197 >>> plt.axis([-0.5, 0.5, -120, 0]) 

1198 >>> plt.title(r"Frequency response of the Kaiser window ($\beta$=14)") 

1199 >>> plt.ylabel("Normalized magnitude [dB]") 

1200 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1201 

1202 """ 

1203 # Docstring adapted from NumPy's kaiser function 

1204 if _len_guards(M): 

1205 return np.ones(M) 

1206 M, needs_trunc = _extend(M, sym) 

1207 

1208 n = np.arange(0, M) 

1209 alpha = (M - 1) / 2.0 

1210 w = (special.i0(beta * np.sqrt(1 - ((n - alpha) / alpha) ** 2.0)) / 

1211 special.i0(beta)) 

1212 

1213 return _truncate(w, needs_trunc) 

1214 

1215 

1216def gaussian(M, std, sym=True): 

1217 r"""Return a Gaussian window. 

1218 

1219 Parameters 

1220 ---------- 

1221 M : int 

1222 Number of points in the output window. If zero or less, an empty 

1223 array is returned. 

1224 std : float 

1225 The standard deviation, sigma. 

1226 sym : bool, optional 

1227 When True (default), generates a symmetric window, for use in filter 

1228 design. 

1229 When False, generates a periodic window, for use in spectral analysis. 

1230 

1231 Returns 

1232 ------- 

1233 w : ndarray 

1234 The window, with the maximum value normalized to 1 (though the value 1 

1235 does not appear if `M` is even and `sym` is True). 

1236 

1237 Notes 

1238 ----- 

1239 The Gaussian window is defined as 

1240 

1241 .. math:: w(n) = e^{ -\frac{1}{2}\left(\frac{n}{\sigma}\right)^2 } 

1242 

1243 Examples 

1244 -------- 

1245 Plot the window and its frequency response: 

1246 

1247 >>> from scipy import signal 

1248 >>> from scipy.fft import fft, fftshift 

1249 >>> import matplotlib.pyplot as plt 

1250 

1251 >>> window = signal.gaussian(51, std=7) 

1252 >>> plt.plot(window) 

1253 >>> plt.title(r"Gaussian window ($\sigma$=7)") 

1254 >>> plt.ylabel("Amplitude") 

1255 >>> plt.xlabel("Sample") 

1256 

1257 >>> plt.figure() 

1258 >>> A = fft(window, 2048) / (len(window)/2.0) 

1259 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1260 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1261 >>> plt.plot(freq, response) 

1262 >>> plt.axis([-0.5, 0.5, -120, 0]) 

1263 >>> plt.title(r"Frequency response of the Gaussian window ($\sigma$=7)") 

1264 >>> plt.ylabel("Normalized magnitude [dB]") 

1265 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1266 

1267 """ 

1268 if _len_guards(M): 

1269 return np.ones(M) 

1270 M, needs_trunc = _extend(M, sym) 

1271 

1272 n = np.arange(0, M) - (M - 1.0) / 2.0 

1273 sig2 = 2 * std * std 

1274 w = np.exp(-n ** 2 / sig2) 

1275 

1276 return _truncate(w, needs_trunc) 

1277 

1278 

1279def general_gaussian(M, p, sig, sym=True): 

1280 r"""Return a window with a generalized Gaussian shape. 

1281 

1282 Parameters 

1283 ---------- 

1284 M : int 

1285 Number of points in the output window. If zero or less, an empty 

1286 array is returned. 

1287 p : float 

1288 Shape parameter. p = 1 is identical to `gaussian`, p = 0.5 is 

1289 the same shape as the Laplace distribution. 

1290 sig : float 

1291 The standard deviation, sigma. 

1292 sym : bool, optional 

1293 When True (default), generates a symmetric window, for use in filter 

1294 design. 

1295 When False, generates a periodic window, for use in spectral analysis. 

1296 

1297 Returns 

1298 ------- 

1299 w : ndarray 

1300 The window, with the maximum value normalized to 1 (though the value 1 

1301 does not appear if `M` is even and `sym` is True). 

1302 

1303 Notes 

1304 ----- 

1305 The generalized Gaussian window is defined as 

1306 

1307 .. math:: w(n) = e^{ -\frac{1}{2}\left|\frac{n}{\sigma}\right|^{2p} } 

1308 

1309 the half-power point is at 

1310 

1311 .. math:: (2 \log(2))^{1/(2 p)} \sigma 

1312 

1313 Examples 

1314 -------- 

1315 Plot the window and its frequency response: 

1316 

1317 >>> from scipy import signal 

1318 >>> from scipy.fft import fft, fftshift 

1319 >>> import matplotlib.pyplot as plt 

1320 

1321 >>> window = signal.general_gaussian(51, p=1.5, sig=7) 

1322 >>> plt.plot(window) 

1323 >>> plt.title(r"Generalized Gaussian window (p=1.5, $\sigma$=7)") 

1324 >>> plt.ylabel("Amplitude") 

1325 >>> plt.xlabel("Sample") 

1326 

1327 >>> plt.figure() 

1328 >>> A = fft(window, 2048) / (len(window)/2.0) 

1329 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1330 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1331 >>> plt.plot(freq, response) 

1332 >>> plt.axis([-0.5, 0.5, -120, 0]) 

1333 >>> plt.title(r"Freq. resp. of the gen. Gaussian " 

1334 ... r"window (p=1.5, $\sigma$=7)") 

1335 >>> plt.ylabel("Normalized magnitude [dB]") 

1336 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1337 

1338 """ 

1339 if _len_guards(M): 

1340 return np.ones(M) 

1341 M, needs_trunc = _extend(M, sym) 

1342 

1343 n = np.arange(0, M) - (M - 1.0) / 2.0 

1344 w = np.exp(-0.5 * np.abs(n / sig) ** (2 * p)) 

1345 

1346 return _truncate(w, needs_trunc) 

1347 

1348 

1349# `chebwin` contributed by Kumar Appaiah. 

1350def chebwin(M, at, sym=True): 

1351 r"""Return a Dolph-Chebyshev window. 

1352 

1353 Parameters 

1354 ---------- 

1355 M : int 

1356 Number of points in the output window. If zero or less, an empty 

1357 array is returned. 

1358 at : float 

1359 Attenuation (in dB). 

1360 sym : bool, optional 

1361 When True (default), generates a symmetric window, for use in filter 

1362 design. 

1363 When False, generates a periodic window, for use in spectral analysis. 

1364 

1365 Returns 

1366 ------- 

1367 w : ndarray 

1368 The window, with the maximum value always normalized to 1 

1369 

1370 Notes 

1371 ----- 

1372 This window optimizes for the narrowest main lobe width for a given order 

1373 `M` and sidelobe equiripple attenuation `at`, using Chebyshev 

1374 polynomials. It was originally developed by Dolph to optimize the 

1375 directionality of radio antenna arrays. 

1376 

1377 Unlike most windows, the Dolph-Chebyshev is defined in terms of its 

1378 frequency response: 

1379 

1380 .. math:: W(k) = \frac 

1381 {\cos\{M \cos^{-1}[\beta \cos(\frac{\pi k}{M})]\}} 

1382 {\cosh[M \cosh^{-1}(\beta)]} 

1383 

1384 where 

1385 

1386 .. math:: \beta = \cosh \left [\frac{1}{M} 

1387 \cosh^{-1}(10^\frac{A}{20}) \right ] 

1388 

1389 and 0 <= abs(k) <= M-1. A is the attenuation in decibels (`at`). 

1390 

1391 The time domain window is then generated using the IFFT, so 

1392 power-of-two `M` are the fastest to generate, and prime number `M` are 

1393 the slowest. 

1394 

1395 The equiripple condition in the frequency domain creates impulses in the 

1396 time domain, which appear at the ends of the window. 

1397 

1398 References 

1399 ---------- 

1400 .. [1] C. Dolph, "A current distribution for broadside arrays which 

1401 optimizes the relationship between beam width and side-lobe level", 

1402 Proceedings of the IEEE, Vol. 34, Issue 6 

1403 .. [2] Peter Lynch, "The Dolph-Chebyshev Window: A Simple Optimal Filter", 

1404 American Meteorological Society (April 1997) 

1405 http://mathsci.ucd.ie/~plynch/Publications/Dolph.pdf 

1406 .. [3] F. J. Harris, "On the use of windows for harmonic analysis with the 

1407 discrete Fourier transforms", Proceedings of the IEEE, Vol. 66, 

1408 No. 1, January 1978 

1409 

1410 Examples 

1411 -------- 

1412 Plot the window and its frequency response: 

1413 

1414 >>> from scipy import signal 

1415 >>> from scipy.fft import fft, fftshift 

1416 >>> import matplotlib.pyplot as plt 

1417 

1418 >>> window = signal.chebwin(51, at=100) 

1419 >>> plt.plot(window) 

1420 >>> plt.title("Dolph-Chebyshev window (100 dB)") 

1421 >>> plt.ylabel("Amplitude") 

1422 >>> plt.xlabel("Sample") 

1423 

1424 >>> plt.figure() 

1425 >>> A = fft(window, 2048) / (len(window)/2.0) 

1426 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1427 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1428 >>> plt.plot(freq, response) 

1429 >>> plt.axis([-0.5, 0.5, -120, 0]) 

1430 >>> plt.title("Frequency response of the Dolph-Chebyshev window (100 dB)") 

1431 >>> plt.ylabel("Normalized magnitude [dB]") 

1432 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1433 

1434 """ 

1435 if np.abs(at) < 45: 

1436 warnings.warn("This window is not suitable for spectral analysis " 

1437 "for attenuation values lower than about 45dB because " 

1438 "the equivalent noise bandwidth of a Chebyshev window " 

1439 "does not grow monotonically with increasing sidelobe " 

1440 "attenuation when the attenuation is smaller than " 

1441 "about 45 dB.") 

1442 if _len_guards(M): 

1443 return np.ones(M) 

1444 M, needs_trunc = _extend(M, sym) 

1445 

1446 # compute the parameter beta 

1447 order = M - 1.0 

1448 beta = np.cosh(1.0 / order * np.arccosh(10 ** (np.abs(at) / 20.))) 

1449 k = np.r_[0:M] * 1.0 

1450 x = beta * np.cos(np.pi * k / M) 

1451 # Find the window's DFT coefficients 

1452 # Use analytic definition of Chebyshev polynomial instead of expansion 

1453 # from scipy.special. Using the expansion in scipy.special leads to errors. 

1454 p = np.zeros(x.shape) 

1455 p[x > 1] = np.cosh(order * np.arccosh(x[x > 1])) 

1456 p[x < -1] = (2 * (M % 2) - 1) * np.cosh(order * np.arccosh(-x[x < -1])) 

1457 p[np.abs(x) <= 1] = np.cos(order * np.arccos(x[np.abs(x) <= 1])) 

1458 

1459 # Appropriate IDFT and filling up 

1460 # depending on even/odd M 

1461 if M % 2: 

1462 w = np.real(sp_fft.fft(p)) 

1463 n = (M + 1) // 2 

1464 w = w[:n] 

1465 w = np.concatenate((w[n - 1:0:-1], w)) 

1466 else: 

1467 p = p * np.exp(1.j * np.pi / M * np.r_[0:M]) 

1468 w = np.real(sp_fft.fft(p)) 

1469 n = M // 2 + 1 

1470 w = np.concatenate((w[n - 1:0:-1], w[1:n])) 

1471 w = w / max(w) 

1472 

1473 return _truncate(w, needs_trunc) 

1474 

1475 

1476def slepian(M, width, sym=True): 

1477 """Return a digital Slepian (DPSS) window. 

1478 

1479 Used to maximize the energy concentration in the main lobe. Also called 

1480 the digital prolate spheroidal sequence (DPSS). 

1481 

1482 .. note:: Deprecated in SciPy 1.1. 

1483 `slepian` will be removed in a future version of SciPy, it is 

1484 replaced by `dpss`, which uses the standard definition of a 

1485 digital Slepian window. 

1486 

1487 Parameters 

1488 ---------- 

1489 M : int 

1490 Number of points in the output window. If zero or less, an empty 

1491 array is returned. 

1492 width : float 

1493 Bandwidth 

1494 sym : bool, optional 

1495 When True (default), generates a symmetric window, for use in filter 

1496 design. 

1497 When False, generates a periodic window, for use in spectral analysis. 

1498 

1499 Returns 

1500 ------- 

1501 w : ndarray 

1502 The window, with the maximum value always normalized to 1 

1503 

1504 See Also 

1505 -------- 

1506 dpss 

1507 

1508 References 

1509 ---------- 

1510 .. [1] D. Slepian & H. O. Pollak: "Prolate spheroidal wave functions, 

1511 Fourier analysis and uncertainty-I," Bell Syst. Tech. J., vol.40, 

1512 pp.43-63, 1961. https://archive.org/details/bstj40-1-43 

1513 .. [2] H. J. Landau & H. O. Pollak: "Prolate spheroidal wave functions, 

1514 Fourier analysis and uncertainty-II," Bell Syst. Tech. J. , vol.40, 

1515 pp.65-83, 1961. https://archive.org/details/bstj40-1-65 

1516 

1517 Examples 

1518 -------- 

1519 Plot the window and its frequency response: 

1520 

1521 >>> from scipy import signal 

1522 >>> from scipy.fft import fft, fftshift 

1523 >>> import matplotlib.pyplot as plt 

1524 

1525 >>> window = signal.slepian(51, width=0.3) 

1526 >>> plt.plot(window) 

1527 >>> plt.title("Slepian (DPSS) window (BW=0.3)") 

1528 >>> plt.ylabel("Amplitude") 

1529 >>> plt.xlabel("Sample") 

1530 

1531 >>> plt.figure() 

1532 >>> A = fft(window, 2048) / (len(window)/2.0) 

1533 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1534 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1535 >>> plt.plot(freq, response) 

1536 >>> plt.axis([-0.5, 0.5, -120, 0]) 

1537 >>> plt.title("Frequency response of the Slepian window (BW=0.3)") 

1538 >>> plt.ylabel("Normalized magnitude [dB]") 

1539 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1540 

1541 """ 

1542 warnings.warn('slepian is deprecated and will be removed in a future ' 

1543 'version, use dpss instead', DeprecationWarning) 

1544 if _len_guards(M): 

1545 return np.ones(M) 

1546 M, needs_trunc = _extend(M, sym) 

1547 

1548 # our width is the full bandwidth 

1549 width = width / 2 

1550 # to match the old version 

1551 width = width / 2 

1552 m = np.arange(M, dtype='d') 

1553 H = np.zeros((2, M)) 

1554 H[0, 1:] = m[1:] * (M - m[1:]) / 2 

1555 H[1, :] = ((M - 1 - 2 * m) / 2)**2 * np.cos(2 * np.pi * width) 

1556 

1557 _, win = linalg.eig_banded(H, select='i', select_range=(M-1, M-1)) 

1558 win = win.ravel() / win.max() 

1559 

1560 return _truncate(win, needs_trunc) 

1561 

1562 

1563def cosine(M, sym=True): 

1564 """Return a window with a simple cosine shape. 

1565 

1566 Parameters 

1567 ---------- 

1568 M : int 

1569 Number of points in the output window. If zero or less, an empty 

1570 array is returned. 

1571 sym : bool, optional 

1572 When True (default), generates a symmetric window, for use in filter 

1573 design. 

1574 When False, generates a periodic window, for use in spectral analysis. 

1575 

1576 Returns 

1577 ------- 

1578 w : ndarray 

1579 The window, with the maximum value normalized to 1 (though the value 1 

1580 does not appear if `M` is even and `sym` is True). 

1581 

1582 Notes 

1583 ----- 

1584 

1585 .. versionadded:: 0.13.0 

1586 

1587 Examples 

1588 -------- 

1589 Plot the window and its frequency response: 

1590 

1591 >>> from scipy import signal 

1592 >>> from scipy.fft import fft, fftshift 

1593 >>> import matplotlib.pyplot as plt 

1594 

1595 >>> window = signal.cosine(51) 

1596 >>> plt.plot(window) 

1597 >>> plt.title("Cosine window") 

1598 >>> plt.ylabel("Amplitude") 

1599 >>> plt.xlabel("Sample") 

1600 

1601 >>> plt.figure() 

1602 >>> A = fft(window, 2048) / (len(window)/2.0) 

1603 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1604 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1605 >>> plt.plot(freq, response) 

1606 >>> plt.axis([-0.5, 0.5, -120, 0]) 

1607 >>> plt.title("Frequency response of the cosine window") 

1608 >>> plt.ylabel("Normalized magnitude [dB]") 

1609 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1610 >>> plt.show() 

1611 

1612 """ 

1613 if _len_guards(M): 

1614 return np.ones(M) 

1615 M, needs_trunc = _extend(M, sym) 

1616 

1617 w = np.sin(np.pi / M * (np.arange(0, M) + .5)) 

1618 

1619 return _truncate(w, needs_trunc) 

1620 

1621 

1622def exponential(M, center=None, tau=1., sym=True): 

1623 r"""Return an exponential (or Poisson) window. 

1624 

1625 Parameters 

1626 ---------- 

1627 M : int 

1628 Number of points in the output window. If zero or less, an empty 

1629 array is returned. 

1630 center : float, optional 

1631 Parameter defining the center location of the window function. 

1632 The default value if not given is ``center = (M-1) / 2``. This 

1633 parameter must take its default value for symmetric windows. 

1634 tau : float, optional 

1635 Parameter defining the decay. For ``center = 0`` use 

1636 ``tau = -(M-1) / ln(x)`` if ``x`` is the fraction of the window 

1637 remaining at the end. 

1638 sym : bool, optional 

1639 When True (default), generates a symmetric window, for use in filter 

1640 design. 

1641 When False, generates a periodic window, for use in spectral analysis. 

1642 

1643 Returns 

1644 ------- 

1645 w : ndarray 

1646 The window, with the maximum value normalized to 1 (though the value 1 

1647 does not appear if `M` is even and `sym` is True). 

1648 

1649 Notes 

1650 ----- 

1651 The Exponential window is defined as 

1652 

1653 .. math:: w(n) = e^{-|n-center| / \tau} 

1654 

1655 References 

1656 ---------- 

1657 S. Gade and H. Herlufsen, "Windows to FFT analysis (Part I)", 

1658 Technical Review 3, Bruel & Kjaer, 1987. 

1659 

1660 Examples 

1661 -------- 

1662 Plot the symmetric window and its frequency response: 

1663 

1664 >>> from scipy import signal 

1665 >>> from scipy.fft import fft, fftshift 

1666 >>> import matplotlib.pyplot as plt 

1667 

1668 >>> M = 51 

1669 >>> tau = 3.0 

1670 >>> window = signal.exponential(M, tau=tau) 

1671 >>> plt.plot(window) 

1672 >>> plt.title("Exponential Window (tau=3.0)") 

1673 >>> plt.ylabel("Amplitude") 

1674 >>> plt.xlabel("Sample") 

1675 

1676 >>> plt.figure() 

1677 >>> A = fft(window, 2048) / (len(window)/2.0) 

1678 >>> freq = np.linspace(-0.5, 0.5, len(A)) 

1679 >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max()))) 

1680 >>> plt.plot(freq, response) 

1681 >>> plt.axis([-0.5, 0.5, -35, 0]) 

1682 >>> plt.title("Frequency response of the Exponential window (tau=3.0)") 

1683 >>> plt.ylabel("Normalized magnitude [dB]") 

1684 >>> plt.xlabel("Normalized frequency [cycles per sample]") 

1685 

1686 This function can also generate non-symmetric windows: 

1687 

1688 >>> tau2 = -(M-1) / np.log(0.01) 

1689 >>> window2 = signal.exponential(M, 0, tau2, False) 

1690 >>> plt.figure() 

1691 >>> plt.plot(window2) 

1692 >>> plt.ylabel("Amplitude") 

1693 >>> plt.xlabel("Sample") 

1694 """ 

1695 if sym and center is not None: 

1696 raise ValueError("If sym==True, center must be None.") 

1697 if _len_guards(M): 

1698 return np.ones(M) 

1699 M, needs_trunc = _extend(M, sym) 

1700 

1701 if center is None: 

1702 center = (M-1) / 2 

1703 

1704 n = np.arange(0, M) 

1705 w = np.exp(-np.abs(n-center) / tau) 

1706 

1707 return _truncate(w, needs_trunc) 

1708 

1709 

1710def dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False): 

1711 """ 

1712 Compute the Discrete Prolate Spheroidal Sequences (DPSS). 

1713 

1714 DPSS (or Slepian sequences) are often used in multitaper power spectral 

1715 density estimation (see [1]_). The first window in the sequence can be 

1716 used to maximize the energy concentration in the main lobe, and is also 

1717 called the Slepian window. 

1718 

1719 Parameters 

1720 ---------- 

1721 M : int 

1722 Window length. 

1723 NW : float 

1724 Standardized half bandwidth corresponding to ``2*NW = BW/f0 = BW*N*dt`` 

1725 where ``dt`` is taken as 1. 

1726 Kmax : int | None, optional 

1727 Number of DPSS windows to return (orders ``0`` through ``Kmax-1``). 

1728 If None (default), return only a single window of shape ``(M,)`` 

1729 instead of an array of windows of shape ``(Kmax, M)``. 

1730 sym : bool, optional 

1731 When True (default), generates a symmetric window, for use in filter 

1732 design. 

1733 When False, generates a periodic window, for use in spectral analysis. 

1734 norm : {2, 'approximate', 'subsample'} | None, optional 

1735 If 'approximate' or 'subsample', then the windows are normalized by the 

1736 maximum, and a correction scale-factor for even-length windows 

1737 is applied either using ``M**2/(M**2+NW)`` ("approximate") or 

1738 a FFT-based subsample shift ("subsample"), see Notes for details. 

1739 If None, then "approximate" is used when ``Kmax=None`` and 2 otherwise 

1740 (which uses the l2 norm). 

1741 return_ratios : bool, optional 

1742 If True, also return the concentration ratios in addition to the 

1743 windows. 

1744 

1745 Returns 

1746 ------- 

1747 v : ndarray, shape (Kmax, N) or (N,) 

1748 The DPSS windows. Will be 1D if `Kmax` is None. 

1749 r : ndarray, shape (Kmax,) or float, optional 

1750 The concentration ratios for the windows. Only returned if 

1751 `return_ratios` evaluates to True. Will be 0D if `Kmax` is None. 

1752 

1753 Notes 

1754 ----- 

1755 This computation uses the tridiagonal eigenvector formulation given 

1756 in [2]_. 

1757 

1758 The default normalization for ``Kmax=None``, i.e. window-generation mode, 

1759 simply using the l-infinity norm would create a window with two unity 

1760 values, which creates slight normalization differences between even and odd 

1761 orders. The approximate correction of ``M**2/float(M**2+NW)`` for even 

1762 sample numbers is used to counteract this effect (see Examples below). 

1763 

1764 For very long signals (e.g., 1e6 elements), it can be useful to compute 

1765 windows orders of magnitude shorter and use interpolation (e.g., 

1766 `scipy.interpolate.interp1d`) to obtain tapers of length `M`, 

1767 but this in general will not preserve orthogonality between the tapers. 

1768 

1769 .. versionadded:: 1.1 

1770 

1771 References 

1772 ---------- 

1773 .. [1] Percival DB, Walden WT. Spectral Analysis for Physical Applications: 

1774 Multitaper and Conventional Univariate Techniques. 

1775 Cambridge University Press; 1993. 

1776 .. [2] Slepian, D. Prolate spheroidal wave functions, Fourier analysis, and 

1777 uncertainty V: The discrete case. Bell System Technical Journal, 

1778 Volume 57 (1978), 1371430. 

1779 .. [3] Kaiser, JF, Schafer RW. On the Use of the I0-Sinh Window for 

1780 Spectrum Analysis. IEEE Transactions on Acoustics, Speech and 

1781 Signal Processing. ASSP-28 (1): 105-107; 1980. 

1782 

1783 Examples 

1784 -------- 

1785 We can compare the window to `kaiser`, which was invented as an alternative 

1786 that was easier to calculate [3]_ (example adapted from 

1787 `here <https://ccrma.stanford.edu/~jos/sasp/Kaiser_DPSS_Windows_Compared.html>`_): 

1788 

1789 >>> import numpy as np 

1790 >>> import matplotlib.pyplot as plt 

1791 >>> from scipy.signal import windows, freqz 

1792 >>> N = 51 

1793 >>> fig, axes = plt.subplots(3, 2, figsize=(5, 7)) 

1794 >>> for ai, alpha in enumerate((1, 3, 5)): 

1795 ... win_dpss = windows.dpss(N, alpha) 

1796 ... beta = alpha*np.pi 

1797 ... win_kaiser = windows.kaiser(N, beta) 

1798 ... for win, c in ((win_dpss, 'k'), (win_kaiser, 'r')): 

1799 ... win /= win.sum() 

1800 ... axes[ai, 0].plot(win, color=c, lw=1.) 

1801 ... axes[ai, 0].set(xlim=[0, N-1], title=r'$\\alpha$ = %s' % alpha, 

1802 ... ylabel='Amplitude') 

1803 ... w, h = freqz(win) 

1804 ... axes[ai, 1].plot(w, 20 * np.log10(np.abs(h)), color=c, lw=1.) 

1805 ... axes[ai, 1].set(xlim=[0, np.pi], 

1806 ... title=r'$\\beta$ = %0.2f' % beta, 

1807 ... ylabel='Magnitude (dB)') 

1808 >>> for ax in axes.ravel(): 

1809 ... ax.grid(True) 

1810 >>> axes[2, 1].legend(['DPSS', 'Kaiser']) 

1811 >>> fig.tight_layout() 

1812 >>> plt.show() 

1813 

1814 And here are examples of the first four windows, along with their 

1815 concentration ratios: 

1816 

1817 >>> M = 512 

1818 >>> NW = 2.5 

1819 >>> win, eigvals = windows.dpss(M, NW, 4, return_ratios=True) 

1820 >>> fig, ax = plt.subplots(1) 

1821 >>> ax.plot(win.T, linewidth=1.) 

1822 >>> ax.set(xlim=[0, M-1], ylim=[-0.1, 0.1], xlabel='Samples', 

1823 ... title='DPSS, M=%d, NW=%0.1f' % (M, NW)) 

1824 >>> ax.legend(['win[%d] (%0.4f)' % (ii, ratio) 

1825 ... for ii, ratio in enumerate(eigvals)]) 

1826 >>> fig.tight_layout() 

1827 >>> plt.show() 

1828 

1829 Using a standard :math:`l_{\\infty}` norm would produce two unity values 

1830 for even `M`, but only one unity value for odd `M`. This produces uneven 

1831 window power that can be counteracted by the approximate correction 

1832 ``M**2/float(M**2+NW)``, which can be selected by using 

1833 ``norm='approximate'`` (which is the same as ``norm=None`` when 

1834 ``Kmax=None``, as is the case here). Alternatively, the slower 

1835 ``norm='subsample'`` can be used, which uses subsample shifting in the 

1836 frequency domain (FFT) to compute the correction: 

1837 

1838 >>> Ms = np.arange(1, 41) 

1839 >>> factors = (50, 20, 10, 5, 2.0001) 

1840 >>> energy = np.empty((3, len(Ms), len(factors))) 

1841 >>> for mi, M in enumerate(Ms): 

1842 ... for fi, factor in enumerate(factors): 

1843 ... NW = M / float(factor) 

1844 ... # Corrected using empirical approximation (default) 

1845 ... win = windows.dpss(M, NW) 

1846 ... energy[0, mi, fi] = np.sum(win ** 2) / np.sqrt(M) 

1847 ... # Corrected using subsample shifting 

1848 ... win = windows.dpss(M, NW, norm='subsample') 

1849 ... energy[1, mi, fi] = np.sum(win ** 2) / np.sqrt(M) 

1850 ... # Uncorrected (using l-infinity norm) 

1851 ... win /= win.max() 

1852 ... energy[2, mi, fi] = np.sum(win ** 2) / np.sqrt(M) 

1853 >>> fig, ax = plt.subplots(1) 

1854 >>> hs = ax.plot(Ms, energy[2], '-o', markersize=4, 

1855 ... markeredgecolor='none') 

1856 >>> leg = [hs[-1]] 

1857 >>> for hi, hh in enumerate(hs): 

1858 ... h1 = ax.plot(Ms, energy[0, :, hi], '-o', markersize=4, 

1859 ... color=hh.get_color(), markeredgecolor='none', 

1860 ... alpha=0.66) 

1861 ... h2 = ax.plot(Ms, energy[1, :, hi], '-o', markersize=4, 

1862 ... color=hh.get_color(), markeredgecolor='none', 

1863 ... alpha=0.33) 

1864 ... if hi == len(hs) - 1: 

1865 ... leg.insert(0, h1[0]) 

1866 ... leg.insert(0, h2[0]) 

1867 >>> ax.set(xlabel='M (samples)', ylabel=r'Power / $\\sqrt{M}$') 

1868 >>> ax.legend(leg, ['Uncorrected', r'Corrected: $\\frac{M^2}{M^2+NW}$', 

1869 ... 'Corrected (subsample)']) 

1870 >>> fig.tight_layout() 

1871 

1872 """ # noqa: E501 

1873 if _len_guards(M): 

1874 return np.ones(M) 

1875 if norm is None: 

1876 norm = 'approximate' if Kmax is None else 2 

1877 known_norms = (2, 'approximate', 'subsample') 

1878 if norm not in known_norms: 

1879 raise ValueError('norm must be one of %s, got %s' 

1880 % (known_norms, norm)) 

1881 if Kmax is None: 

1882 singleton = True 

1883 Kmax = 1 

1884 else: 

1885 singleton = False 

1886 Kmax = operator.index(Kmax) 

1887 if not 0 < Kmax <= M: 

1888 raise ValueError('Kmax must be greater than 0 and less than M') 

1889 if NW >= M/2.: 

1890 raise ValueError('NW must be less than M/2.') 

1891 if NW <= 0: 

1892 raise ValueError('NW must be positive') 

1893 M, needs_trunc = _extend(M, sym) 

1894 W = float(NW) / M 

1895 nidx = np.arange(M) 

1896 

1897 # Here we want to set up an optimization problem to find a sequence 

1898 # whose energy is maximally concentrated within band [-W,W]. 

1899 # Thus, the measure lambda(T,W) is the ratio between the energy within 

1900 # that band, and the total energy. This leads to the eigen-system 

1901 # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest 

1902 # eigenvalue is the sequence with maximally concentrated energy. The 

1903 # collection of eigenvectors of this system are called Slepian 

1904 # sequences, or discrete prolate spheroidal sequences (DPSS). Only the 

1905 # first K, K = 2NW/dt orders of DPSS will exhibit good spectral 

1906 # concentration 

1907 # [see https://en.wikipedia.org/wiki/Spectral_concentration_problem] 

1908 

1909 # Here we set up an alternative symmetric tri-diagonal eigenvalue 

1910 # problem such that 

1911 # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1) 

1912 # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1] 

1913 # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1] 

1914 # [see Percival and Walden, 1993] 

1915 d = ((M - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W) 

1916 e = nidx[1:] * (M - nidx[1:]) / 2. 

1917 

1918 # only calculate the highest Kmax eigenvalues 

1919 w, windows = linalg.eigh_tridiagonal( 

1920 d, e, select='i', select_range=(M - Kmax, M - 1)) 

1921 w = w[::-1] 

1922 windows = windows[:, ::-1].T 

1923 

1924 # By convention (Percival and Walden, 1993 pg 379) 

1925 # * symmetric tapers (k=0,2,4,...) should have a positive average. 

1926 fix_even = (windows[::2].sum(axis=1) < 0) 

1927 for i, f in enumerate(fix_even): 

1928 if f: 

1929 windows[2 * i] *= -1 

1930 # * antisymmetric tapers should begin with a positive lobe 

1931 # (this depends on the definition of "lobe", here we'll take the first 

1932 # point above the numerical noise, which should be good enough for 

1933 # sufficiently smooth functions, and more robust than relying on an 

1934 # algorithm that uses max(abs(w)), which is susceptible to numerical 

1935 # noise problems) 

1936 thresh = max(1e-7, 1. / M) 

1937 for i, w in enumerate(windows[1::2]): 

1938 if w[w * w > thresh][0] < 0: 

1939 windows[2 * i + 1] *= -1 

1940 

1941 # Now find the eigenvalues of the original spectral concentration problem 

1942 # Use the autocorr sequence technique from Percival and Walden, 1993 pg 390 

1943 if return_ratios: 

1944 dpss_rxx = _fftautocorr(windows) 

1945 r = 4 * W * np.sinc(2 * W * nidx) 

1946 r[0] = 2 * W 

1947 ratios = np.dot(dpss_rxx, r) 

1948 if singleton: 

1949 ratios = ratios[0] 

1950 # Deal with sym and Kmax=None 

1951 if norm != 2: 

1952 windows /= windows.max() 

1953 if M % 2 == 0: 

1954 if norm == 'approximate': 

1955 correction = M**2 / float(M**2 + NW) 

1956 else: 

1957 s = sp_fft.rfft(windows[0]) 

1958 shift = -(1 - 1./M) * np.arange(1, M//2 + 1) 

1959 s[1:] *= 2 * np.exp(-1j * np.pi * shift) 

1960 correction = M / s.real.sum() 

1961 windows *= correction 

1962 # else we're already l2 normed, so do nothing 

1963 if needs_trunc: 

1964 windows = windows[:, :-1] 

1965 if singleton: 

1966 windows = windows[0] 

1967 return (windows, ratios) if return_ratios else windows 

1968 

1969 

1970def _fftautocorr(x): 

1971 """Compute the autocorrelation of a real array and crop the result.""" 

1972 N = x.shape[-1] 

1973 use_N = sp_fft.next_fast_len(2*N-1) 

1974 x_fft = sp_fft.rfft(x, use_N, axis=-1) 

1975 cxy = sp_fft.irfft(x_fft * x_fft.conj(), n=use_N)[:, :N] 

1976 # Or equivalently (but in most cases slower): 

1977 # cxy = np.array([np.convolve(xx, yy[::-1], mode='full') 

1978 # for xx, yy in zip(x, x)])[:, N-1:2*N-1] 

1979 return cxy 

1980 

1981 

1982_win_equiv_raw = { 

1983 ('barthann', 'brthan', 'bth'): (barthann, False), 

1984 ('bartlett', 'bart', 'brt'): (bartlett, False), 

1985 ('blackman', 'black', 'blk'): (blackman, False), 

1986 ('blackmanharris', 'blackharr', 'bkh'): (blackmanharris, False), 

1987 ('bohman', 'bman', 'bmn'): (bohman, False), 

1988 ('boxcar', 'box', 'ones', 

1989 'rect', 'rectangular'): (boxcar, False), 

1990 ('chebwin', 'cheb'): (chebwin, True), 

1991 ('cosine', 'halfcosine'): (cosine, False), 

1992 ('exponential', 'poisson'): (exponential, True), 

1993 ('flattop', 'flat', 'flt'): (flattop, False), 

1994 ('gaussian', 'gauss', 'gss'): (gaussian, True), 

1995 ('general gaussian', 'general_gaussian', 

1996 'general gauss', 'general_gauss', 'ggs'): (general_gaussian, True), 

1997 ('hamming', 'hamm', 'ham'): (hamming, False), 

1998 ('hanning', 'hann', 'han'): (hann, False), 

1999 ('kaiser', 'ksr'): (kaiser, True), 

2000 ('nuttall', 'nutl', 'nut'): (nuttall, False), 

2001 ('parzen', 'parz', 'par'): (parzen, False), 

2002 ('slepian', 'slep', 'optimal', 'dpss', 'dss'): (slepian, True), 

2003 ('triangle', 'triang', 'tri'): (triang, False), 

2004 ('tukey', 'tuk'): (tukey, True), 

2005} 

2006 

2007# Fill dict with all valid window name strings 

2008_win_equiv = {} 

2009for k, v in _win_equiv_raw.items(): 

2010 for key in k: 

2011 _win_equiv[key] = v[0] 

2012 

2013# Keep track of which windows need additional parameters 

2014_needs_param = set() 

2015for k, v in _win_equiv_raw.items(): 

2016 if v[1]: 

2017 _needs_param.update(k) 

2018 

2019 

2020def get_window(window, Nx, fftbins=True): 

2021 """ 

2022 Return a window of a given length and type. 

2023 

2024 Parameters 

2025 ---------- 

2026 window : string, float, or tuple 

2027 The type of window to create. See below for more details. 

2028 Nx : int 

2029 The number of samples in the window. 

2030 fftbins : bool, optional 

2031 If True (default), create a "periodic" window, ready to use with 

2032 `ifftshift` and be multiplied by the result of an FFT (see also 

2033 :func:`~scipy.fft.fftfreq`). 

2034 If False, create a "symmetric" window, for use in filter design. 

2035 

2036 Returns 

2037 ------- 

2038 get_window : ndarray 

2039 Returns a window of length `Nx` and type `window` 

2040 

2041 Notes 

2042 ----- 

2043 Window types: 

2044 

2045 - `~scipy.signal.windows.boxcar` 

2046 - `~scipy.signal.windows.triang` 

2047 - `~scipy.signal.windows.blackman` 

2048 - `~scipy.signal.windows.hamming` 

2049 - `~scipy.signal.windows.hann` 

2050 - `~scipy.signal.windows.bartlett` 

2051 - `~scipy.signal.windows.flattop` 

2052 - `~scipy.signal.windows.parzen` 

2053 - `~scipy.signal.windows.bohman` 

2054 - `~scipy.signal.windows.blackmanharris` 

2055 - `~scipy.signal.windows.nuttall` 

2056 - `~scipy.signal.windows.barthann` 

2057 - `~scipy.signal.windows.kaiser` (needs beta) 

2058 - `~scipy.signal.windows.gaussian` (needs standard deviation) 

2059 - `~scipy.signal.windows.general_gaussian` (needs power, width) 

2060 - `~scipy.signal.windows.slepian` (needs width) 

2061 - `~scipy.signal.windows.dpss` (needs normalized half-bandwidth) 

2062 - `~scipy.signal.windows.chebwin` (needs attenuation) 

2063 - `~scipy.signal.windows.exponential` (needs decay scale) 

2064 - `~scipy.signal.windows.tukey` (needs taper fraction) 

2065 

2066 If the window requires no parameters, then `window` can be a string. 

2067 

2068 If the window requires parameters, then `window` must be a tuple 

2069 with the first argument the string name of the window, and the next 

2070 arguments the needed parameters. 

2071 

2072 If `window` is a floating point number, it is interpreted as the beta 

2073 parameter of the `~scipy.signal.windows.kaiser` window. 

2074 

2075 Each of the window types listed above is also the name of 

2076 a function that can be called directly to create a window of 

2077 that type. 

2078 

2079 Examples 

2080 -------- 

2081 >>> from scipy import signal 

2082 >>> signal.get_window('triang', 7) 

2083 array([ 0.125, 0.375, 0.625, 0.875, 0.875, 0.625, 0.375]) 

2084 >>> signal.get_window(('kaiser', 4.0), 9) 

2085 array([ 0.08848053, 0.29425961, 0.56437221, 0.82160913, 0.97885093, 

2086 0.97885093, 0.82160913, 0.56437221, 0.29425961]) 

2087 >>> signal.get_window(4.0, 9) 

2088 array([ 0.08848053, 0.29425961, 0.56437221, 0.82160913, 0.97885093, 

2089 0.97885093, 0.82160913, 0.56437221, 0.29425961]) 

2090 

2091 """ 

2092 sym = not fftbins 

2093 try: 

2094 beta = float(window) 

2095 except (TypeError, ValueError): 

2096 args = () 

2097 if isinstance(window, tuple): 

2098 winstr = window[0] 

2099 if len(window) > 1: 

2100 args = window[1:] 

2101 elif isinstance(window, str): 

2102 if window in _needs_param: 

2103 raise ValueError("The '" + window + "' window needs one or " 

2104 "more parameters -- pass a tuple.") 

2105 else: 

2106 winstr = window 

2107 else: 

2108 raise ValueError("%s as window type is not supported." % 

2109 str(type(window))) 

2110 

2111 try: 

2112 winfunc = _win_equiv[winstr] 

2113 except KeyError: 

2114 raise ValueError("Unknown window type.") 

2115 

2116 params = (Nx,) + args + (sym,) 

2117 else: 

2118 winfunc = kaiser 

2119 params = (Nx, beta, sym) 

2120 

2121 return winfunc(*params)