question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

BUG: scipy.fft.dct type I with norm = "ortho" leads to wrong powers in modes

See original GitHub issue

Describe your issue.

Applying the type I DCT yields to confusing/wrong results. If norm = “backward”, the individual modes k=0pi, 1pi, … contain the right amount of energy according to the input signal. However, using norm = “ortho”, the power in the individual modes of the transform does not correspond any more to the original signal (see code snippet 1). This is a critical bug.

I traced the issue down to the normalisation. The misbehaviour is caused by the modification of the input signal (see documentation of SciPy DCT (x[0], x[N-1])) before performing the transform. Thus, the DCT result does not correspond any more to the original signal.

I am aware that one might argue that this bug exists only to make Parseval’s theorem hold directly from the input signal and the DCT. However, this is definitely secondary as then the actual DCT result is malicious.

I suggest that the DCT type I result should contain the power in modes of the original input signal, and not of the modified one. The scaling of y[k] (see documentation of SciPy DCT) can still be applied in case of norm = “ortho”. After this fix, the documentation should mention that Parseval’s theorem only holds if one scales/weights the input signal as indicated by the scaling of x[0], x[N-1] in the current documentation.

The problem and its solution is also discussed in a StackOverflow question: https://stackoverflow.com/questions/69946957/scipy-discrete-cosine-transform-dct-power-in-non-existing-frequencies

Reproducing Code Example

### code snippet 1
import numpy as np
x = np.linspace(0, 1, 8, endpoint = True)
f = np.cos(1 * np.pi * x)

import scipy.fft
f_DCT = scipy.fft.dct(f, type = 1, norm = "ortho")
# f_DCT:
# array([ 3.35699888e-16,  2.09223516e+00, -1.48359792e-17,  2.21406462e-01,
#        -1.92867730e-16,  2.21406462e-01,  1.18687834e-16,  1.56558011e-01])
# One expects power only at k=1pi, but here there is power in many other modes too.

Error message

None

SciPy/NumPy/Python version information

1.6.2 1.20.2 sys.version_info(major=3, minor=8, micro=8, releaselevel=‘final’, serial=0)

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
turbulentphilcommented, Nov 17, 2021

That’s right, it’s typically given for Fourier transforms and especially considering the proper extension of the signal. Maybe it’s asked for too much to consider this special case of supporting the theorem even for “half” signals in this standard library.

My use case is the following: I want to analyse 3d flow data in a Cartesian domain which is periodic in horizontal directions only. I cannot simply add the flow domain in reverse order on top to make the domain fully periodic (and use then DFTs only), as this will change the kz=0 mode. Thus, DCTs and DSTs are necessary. To make sure that both descriptions (physical and “Fourier” space) coincide, I typically check Parseval’s theorem by means of the variance of the signal and the “Fourier” coefficients. When this holds, one is able to directly analyse quantities from physical space by the use of the coefficients with all its advantages (filtering scales).

0reactions
peterbell10commented, Nov 17, 2021

Strictly speaking I think Parseval’s theorem only applies to the fourier transform, so you would need to consider the even extension of the input signal. If you do that, then the normalization I gave is correct because some elements appear multiple times in the summation.

Perhaps it would make sense if you explained your use case?

Read more comments on GitHub >

github_iconTop Results From Across the Web

scipy.fft.dct — SciPy v1.9.3 Manual
For type in {1, 2, 3} , norm="ortho" breaks the direct correspondence with the direct Fourier transform. To recover it you must specify...
Read more >
Fourier Transforms (scipy.fft) — SciPy v1.9.3 Manual
Two parameters of the dct/idct function calls allow setting the DCT type and coefficient normalization. For a single dimension array x, dct(x, norm='ortho')...
Read more >
SciPy 1.8.0 Release Notes — SciPy v1.9.3 Manual
Our development attention will now shift to bug-fix releases on the 1.8.x branch, ... #15033: BUG: scipy.fft.dct type I with norm = “ortho”...
Read more >
SciPy 1.2.0 Release Notes — SciPy v1.9.3 Manual
Our development attention will now shift to bug-fix releases on the 1.2.x ... DCT-I, and DST-I orthonormalization are now supported in scipy.fftpack ....
Read more >
scipy.fft.fft — SciPy v1.9.3 Manual
Axis over which to compute the FFT. If not given, the last axis is used. norm{“backward”, “ortho”, “forward”}, optional. Normalization mode.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found