ClassicalShannonWavelet.java
package com.morphiqlabs.wavelet.cwt.finance;
import com.morphiqlabs.wavelet.api.ContinuousWavelet;
import com.morphiqlabs.wavelet.exception.InvalidArgumentException;
/**
* Classical Shannon wavelet - the standard formulation.
*
* <p>This implements the classical Shannon wavelet as defined in wavelet literature:
* ψ(t) = 2*sinc(2t) - sinc(t)
* where sinc(x) = sin(πx)/(πx)</p>
*
* <p>This wavelet has perfect frequency localization with support in [π/2, π]
* in the frequency domain.</p>
*
* <p>For financial applications:</p>
* <ul>
* <li>Use when you need perfect frequency separation (e.g., isolating trading cycles)</li>
* <li>Best for analyzing stationary periodic patterns</li>
* <li>May produce ringing artifacts (Gibbs phenomenon) around sharp transitions</li>
* <li>Not recommended for transient event detection</li>
* </ul>
*
* <p>Compare with Shannon-Gabor wavelet which provides better time localization
* at the cost of some frequency resolution.</p>
*
* @see ShannonGaborWavelet
*/
public final class ClassicalShannonWavelet implements ContinuousWavelet {
private static final String NAME = "shan";
@Override
public String name() {
return NAME;
}
@Override
public double psi(double t) {
// Shannon wavelet: ψ(t) = 2*sinc(2t) - sinc(t)
return 2.0 * sinc(2.0 * t) - sinc(t);
}
@Override
public double centerFrequency() {
// Center frequency is at 3π/4 in angular frequency
// In normalized frequency: 3/8 = 0.375
return 0.75 * Math.PI / (2.0 * Math.PI);
}
@Override
public double bandwidth() {
// Bandwidth is π/2 in angular frequency
// In normalized frequency: 1/4 = 0.25
return 0.5 * Math.PI / (2.0 * Math.PI);
}
@Override
public boolean isComplex() {
return false;
}
@Override
public double[] discretize(int length) {
if (length <= 0) {
throw new InvalidArgumentException("Length must be positive");
}
double[] samples = new double[length];
int center = length / 2;
// Shannon wavelet has slow decay, use large support
double support = 20.0;
for (int i = 0; i < length; i++) {
double t = (i - center) * 2.0 * support / length;
samples[i] = psi(t);
}
return samples;
}
/**
* Sinc function: sin(πx)/(πx)
*/
private double sinc(double x) {
if (Math.abs(x) < 1e-10) {
return 1.0;
}
double px = Math.PI * x;
return Math.sin(px) / px;
}
}