Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't accurately compute C_d for an arbitrary wavelet. #1

Open
aaren opened this issue Aug 15, 2013 · 11 comments
Open

Can't accurately compute C_d for an arbitrary wavelet. #1

aaren opened this issue Aug 15, 2013 · 11 comments
Assignees

Comments

@aaren
Copy link
Owner

aaren commented Aug 15, 2013

Example code:

from wavelets import WaveletAnalysis
wa = WaveletAnalysis()

# hard coded Morlet value
print wa.C_d
print wa.wavelet.C_d

# override hard coding
wa.wavelet.C_d = None
# Now C_d is explicitly computed
print wa.C_d

The explicitly computed version is giving me a value of (0.13708 + 0j), rather than the 0.776 that we expect for a Morlet with w0 = 6 (which is the default).

@ghost ghost assigned aaren Aug 16, 2013
@aaren
Copy link
Owner Author

aaren commented Aug 31, 2014

@nabobalis @Cadair see section 3.i of Torrence and Compo for the maths.
I've implemented the function in wavelets.WaveletAnalysis.compute_Cdelta here
but maybe I've got something wrong.

@nabobalis
Copy link

From what I can see either, the value in the paper is wrong or either Y_00 or W_D are returning the wrong values.

For the morlet, is the frequency_rep function calculating the fourier transform of the Morlet wavelet as is given http://en.wikipedia.org/wiki/Morlet_wavelet ?

@aaren
Copy link
Owner Author

aaren commented Aug 31, 2014

It is implemented as in Table 1 of TC98 (paper here if you need it. ) I'm not sure how this maps to the wikipedia version.

@nabobalis
Copy link

Yeah, it is the same as far as I can tell as the paper version. I can't find an issue with the code.

@aaren
Copy link
Owner Author

aaren commented Aug 31, 2014

Are we talking about the same thing? I'm comparing this code, i.e.

def frequency_rep(self, w, s=1.0):
        """Frequency representation of morlet.

        s - scale
        w - angular frequency
        """
        x = w * s
        # heaviside mock
        Hw = 0.5 * (np.sign(x) + 1)
        return np.pi ** -.25 * Hw * np.exp((-(x - self.w0) ** 2) / 2)

with the fourier transform on wikipedia:

wikipedia version

What I can't see is how the heaviside function is represented on wikipedia.

@nabobalis
Copy link

Yeah, I do mean that. The last part of the equation vanishes for sigma
greater than 5. So it does simplify.
I guess I shouldn't be going to wikipedia anyway.

Regardless, the code follows the paper. So I'm not sure what the problem is
at the moment.

On 31 August 2014 13:51, aaren [email protected] wrote:

Are we talking about the same thing? I'm comparing this code
https://github.com/aaren/wavelets/blob/master/wavelets/wavelets.py#L207,
i.e.

def frequency_rep(self, w, s=1.0):
"""Frequency representation of morlet.
s - scale w - angular frequency """
x = w * s
# heaviside mock
Hw = 0.5 * (np.sign(x) + 1)
return np.pi ** -.25 * Hw * np.exp((-(x - self.w0) ** 2) / 2)

with the fourier transform on wikipedia:

[image: wikipedia version]
https://camo.githubusercontent.com/98674993726b55c71cecd0dab15e2eb5131a4ebc/687474703a2f2f75706c6f61642e77696b696d656469612e6f72672f6d6174682f342f342f662f34346666363266356232343461396663653363353662396566653164313432302e706e67

What I can't see is how the heaviside function is represented on wikipedia.


Reply to this email directly or view it on GitHub
#1 (comment).

aaren added a commit that referenced this issue Feb 14, 2015
I was using the form for the wavelet given in table 1 of TC98 and not
the normalised form given in equation 6 (to give unit energy).

This goes some way to fixing github issue #1.
@aaren
Copy link
Owner Author

aaren commented Feb 14, 2015

I made a mistake in the code. I'm still not getting the exact same value as TC98, but at least it's a lot closer (getting 0.724 now).

@aaren
Copy link
Owner Author

aaren commented Feb 14, 2015

The actual computation of Cdelta is a double summation of the fourier wavelet over scale and frequency. This is sensitive to the values of N, dj and s0 (dt cancels out).

It looks like N just needs to be big enough (>1000), whereas dj and s0 can be a bit smaller than default.

s0 is the smallest scale. The default choice for s0 is to find where this corresponds to the equivalent fourier period being equal to 2*dt, which comes out as ~1.9. Setting s0=1 improves the Cdelta calculation a lot, giving us Cdelta = 0.778 (compared with 0.776 in TC98).

aaren added a commit that referenced this issue Feb 14, 2015
also set as property and remove ability to select value by call (can do
it by indexing now)

This affects the computation of Cdelta, which is now about 0.768 for the
Morlet, without having to set the values of s0 and dj lower. Setting
them lower doesn't change this much. See #1.
aaren added a commit that referenced this issue Feb 14, 2015
also set as property and remove ability to select value by call (can do
it by indexing now)

n.b. the frequencies returned by numpy are adimensional, on the interval
[-1/2, 1/2], so we multiply by 2 * pi.

This affects the computation of Cdelta, which now comes out as correct
when s0 = 1 (for the Morlet). See #1.
@aaren
Copy link
Owner Author

aaren commented Feb 15, 2015

08baf66 nearly fixes the issue, giving Cdelta = 0.776 with s0 = 1. However setting s0 to lower than the default (based on the equivalent fourier period) changes the wavelet variance (TC98 equation 14), meaning that variance (energy) is no longer conserved through the wavelet transform.

The wavelet variance is dependent on the value of s0 for two reasons:

  1. s0 sets the scaling for all of the scales
  2. s0 sets the uppermost scale sJ via J = log2(N dt / s0) / dj

The scales are defined as sj = s0 * 2 ^ (j * dj), j=0, 1, ..., J (TC98 eq 9-10).

We are told to choose s0 such that the equivalent fourier period is about 2 * dt.

aaren added a commit that referenced this issue Feb 28, 2016
also set as property and remove ability to select value by call (can do
it by indexing now)

n.b. the frequencies returned by numpy are adimensional, on the interval
[-1/2, 1/2], so we multiply by 2 * pi.

This affects the computation of Cdelta, which now comes out as correct
when s0 = 1 (for the Morlet). See #1.
aaren added a commit that referenced this issue Feb 28, 2016
also set as property and remove ability to select value by call (can do
it by indexing now)

n.b. the frequencies returned by numpy are adimensional, on the interval
[-1/2, 1/2], so we multiply by 2 * pi.

This affects the computation of Cdelta, which now comes out as correct
when s0 = 1 (for the Morlet). See #1.
ulikoehler pushed a commit to ulikoehler/wavelets that referenced this issue Feb 28, 2016
also set as property and remove ability to select value by call (can do
it by indexing now)

n.b. the frequencies returned by numpy are adimensional, on the interval
[-1/2, 1/2], so we multiply by 2 * pi.

This affects the computation of Cdelta, which now comes out as correct
when s0 = 1 (for the Morlet). See aaren#1.
@paulthebaker
Copy link

paulthebaker commented Mar 29, 2017

I started coding up my own implementation of an inverse continuous wavelet transform. While searching for my own solution to this same problem, I found your repo.

I think the number quoted in the T&C paper is "wrong".

The actual computation of Cdelta is a double summation of the fourier wavelet over scale and frequency. This is sensitive to the values of N, dj and s0 (dt cancels out).

As you say, in the real, live, finite sample size case Cdelta is dependent on N, dj, and s0. If you use T&C eq. (5) to set up your w_k's, dt will affect the numerical integration step size (in the sum), even though it explicitly cancels. To reproduce the T&C result you need to use the exact settings they used.

If you look in their fortran code, you'll see they set:

N = 504
dt = 1/4
dj = 1/4
s0 = 1/4
jtot = 44

These are not the same values stated in T&C section 3.f. They also comment:

Note: for accurate reconstruction and wavelet-derived variance do not pad with zeroes, set s0=dt (for Paul set s0=dt/4), and use a large "jtot" (even though the extra scales will be within the cone of influence).
For plotting purposes, it is only necessary to use s0=2dt (for Morlet) and "jtot" from Eqn(10) Torrence&Compo(1998).

It appears that in practice T&C are over computing for numerical stability.

Anyways, using their values, I can reproduce Cdelta = 0.77574... for the w0=6 Morlet. Following thier comment and setting s0 = 1/16 for the m=4 Paul wavelet, I get Cdelta = 1.1302.... Actually, I used jtot = 35, because my scale generator sets that. I assume that's the cause of my small difference with T&C's Table 2.

The main point is that T&C's quoted numbers are not general. I think it's best to compute Cdelta and any other empirically determined constants for a particular wavelet basis as needed and ignore the T&C values in their table 2.

@shixun22
Copy link

shixun22 commented Jun 3, 2017

Thanks for the nice code! Here I wish to share what I figured out about Cdelta after some struggling and frustration.

The TC98 Cdelta values are indeed resolution dependent. Idealised values of Cdelta can be computed with

def phi_lnk(lnk):
k = np.exp(lnk)
return self.wavelet.frequency(k).real

Cd = scipy.integrate.quad(phi_lnk, -10, 10)[0] / self.wavelet.time(0).real * (2.*np.pi)**0.5 / np.log(2.)

The ln(2) factor arises from the summation of the 2-based self.scales in the Cdelta computation, which has not been normalised in the Cdelta definition in TC98 or this code.

For complex wavelet functions whose Fourier transform is specified to be 0 for k<=0, such as Morlet, the resulting value needs to be further divided by 2.

The resulting Cdelta value for Morlet is 0.7784..., for Marr/Ricker is 3.6163..., both slightly larger from their TC98 value.

Hope this helps!

endolith pushed a commit to endolith/wavelets that referenced this issue Jul 25, 2020
Added missing scale_from_period functionality for Paul + DOG wavelets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants