ComplexShannonWavelet.java
package com.morphiqlabs.wavelet.cwt;
import com.morphiqlabs.wavelet.api.ComplexContinuousWavelet;
/**
* Complex Shannon wavelet (CSHAN).
*
* <p>The complex Shannon wavelet is the analytic signal version of the Shannon wavelet,
* providing perfect frequency localization. It's characterized by a sinc function
* modulated by a complex exponential, making it ideal for frequency-selective analysis.</p>
*
* <p>Mathematical form: ψ(t) = (fb)^(-1/2) * sinc(fb*t) * exp(2πi*fc*t)</p>
*
* <p>Parameters:
* <ul>
* <li>fb: Bandwidth parameter (controls frequency resolution)</li>
* <li>fc: Center frequency (determines the wavelet's central frequency)</li>
* </ul>
*/
public final class ComplexShannonWavelet implements ComplexContinuousWavelet {
private final double fb; // Bandwidth parameter
private final double fc; // Center frequency
private final String name;
/**
* Creates a Complex Shannon wavelet with specified parameters.
*
* @param fb Bandwidth parameter (must be positive)
* @param fc Center frequency (must be positive)
* @throws IllegalArgumentException if fb or fc are not positive
*/
public ComplexShannonWavelet(double fb, double fc) {
if (fb <= 0 || fc <= 0) {
throw new IllegalArgumentException(
"Bandwidth and center frequency must be positive");
}
this.fb = fb;
this.fc = fc;
this.name = String.format("cshan%.1f-%.1f", fb, fc);
}
/**
* Creates a Complex Shannon wavelet with default parameters.
* Default: fb=1.0, fc=1.0
*/
public ComplexShannonWavelet() {
this(1.0, 1.0);
}
@Override
public String name() {
return name;
}
@Override
public double psi(double t) {
// Real part: Shannon wavelet
double sinc = computeSinc(fb * t);
return sinc * Math.cos(2 * Math.PI * fc * t) / Math.sqrt(fb);
}
@Override
public double psiImaginary(double t) {
// Imaginary part for analytic signal
double sinc = computeSinc(fb * t);
return sinc * Math.sin(2 * Math.PI * fc * t) / Math.sqrt(fb);
}
@Override
public double centerFrequency() {
return fc;
}
@Override
public double bandwidth() {
return fb;
}
@Override
public double[] discretize(int numCoeffs) {
double[] coeffs = new double[numCoeffs];
double tMax = 5.0 / fb; // Support region
double dt = 2 * tMax / (numCoeffs - 1);
for (int i = 0; i < numCoeffs; i++) {
double t = -tMax + i * dt;
coeffs[i] = psi(t);
}
// Normalize
double sum = 0;
for (double c : coeffs) {
sum += c * c;
}
if (sum > 0) {
double norm = 1.0 / Math.sqrt(sum);
for (int i = 0; i < numCoeffs; i++) {
coeffs[i] *= norm;
}
}
return coeffs;
}
/**
* Computes the sinc function: sin(πx)/(πx)
*/
private double computeSinc(double x) {
if (Math.abs(x) < 1e-10) {
return 1.0;
}
double piX = Math.PI * x;
return Math.sin(piX) / piX;
}
}