AdaptiveScaleSelector.java
package com.morphiqlabs.wavelet.cwt;
import com.morphiqlabs.wavelet.api.ContinuousWavelet;
/**
* Interface for adaptive scale selection strategies in Continuous Wavelet Transform.
*
* <p>Automatically determines optimal scale ranges and spacing based on:
* <ul>
* <li>Signal characteristics (length, frequency content, sampling rate)</li>
* <li>Wavelet properties (bandwidth, center frequency, support)</li>
* <li>Analysis requirements (resolution, computational constraints)</li>
* </ul>
*/
public interface AdaptiveScaleSelector {
/**
* Selects optimal scales for CWT analysis.
*
* @param signal the input signal to analyze
* @param wavelet the wavelet to use for analysis
* @param samplingRate the sampling rate of the signal (Hz)
* @return array of optimal scales
*/
double[] selectScales(double[] signal, ContinuousWavelet wavelet, double samplingRate);
/**
* Selects scales with additional configuration parameters.
*
* @param signal the input signal to analyze
* @param wavelet the wavelet to use for analysis
* @param config configuration for scale selection
* @return array of optimal scales
*/
double[] selectScales(double[] signal, ContinuousWavelet wavelet, ScaleSelectionConfig config);
/**
* Gets the frequency range that would be analyzed with the selected scales.
*
* @param scales the selected scales
* @param wavelet the wavelet used
* @param samplingRate the sampling rate
* @return frequency range [minFreq, maxFreq] in Hz
*/
default double[] getFrequencyRange(double[] scales, ContinuousWavelet wavelet, double samplingRate) {
if (scales.length == 0) {
return new double[]{0, 0};
}
double centerFreq = wavelet.centerFrequency();
double minFreq = centerFreq * samplingRate / scales[scales.length - 1];
double maxFreq = centerFreq * samplingRate / scales[0];
return new double[]{minFreq, maxFreq};
}
/**
* Estimates the number of scales needed for a given frequency range.
*
* @param minFreq minimum frequency (Hz)
* @param maxFreq maximum frequency (Hz)
* @param wavelet the wavelet to use
* @param samplingRate sampling rate (Hz)
* @param scalesPerOctave number of scales per octave
* @return estimated number of scales
*/
default int estimateScaleCount(double minFreq, double maxFreq, ContinuousWavelet wavelet,
double samplingRate, int scalesPerOctave) {
if (minFreq <= 0 || maxFreq <= minFreq) {
throw new IllegalArgumentException("Invalid frequency range");
}
double octaves = Math.log(maxFreq / minFreq) / Math.log(2);
return Math.max(1, (int) Math.ceil(octaves * scalesPerOctave));
}
/**
* Configuration class for adaptive scale selection.
*/
class ScaleSelectionConfig {
private final double samplingRate;
private final double minFrequency;
private final double maxFrequency;
private final int scalesPerOctave;
private final boolean useSignalAdaptation;
private final double frequencyResolution;
private final int maxScales;
private final ScaleSpacing spacing;
private ScaleSelectionConfig(Builder builder) {
this.samplingRate = builder.samplingRate;
this.minFrequency = builder.minFrequency;
this.maxFrequency = builder.maxFrequency;
this.scalesPerOctave = builder.scalesPerOctave;
this.useSignalAdaptation = builder.useSignalAdaptation;
this.frequencyResolution = builder.frequencyResolution;
this.maxScales = builder.maxScales;
this.spacing = builder.spacing;
}
// Getters
/**
* Gets the sampling rate.
* @return sampling rate in Hz
*/
public double getSamplingRate() { return samplingRate; }
/**
* Gets the minimum frequency.
* @return minimum frequency (Hz), or 0 if auto
*/
public double getMinFrequency() { return minFrequency; }
/**
* Gets the maximum frequency.
* @return maximum frequency (Hz), or 0 if auto
*/
public double getMaxFrequency() { return maxFrequency; }
/**
* Gets the number of scales per octave.
* @return number of scales per octave
*/
public int getScalesPerOctave() { return scalesPerOctave; }
/**
* Checks if signal adaptation is enabled.
* @return true if signal adaptation is enabled
*/
public boolean isUseSignalAdaptation() { return useSignalAdaptation; }
/**
* Gets the target frequency resolution.
* @return target frequency resolution (Hz), or 0 to auto-detect
*/
public double getFrequencyResolution() { return frequencyResolution; }
/**
* Gets the maximum number of scales.
* @return maximum number of scales
*/
public int getMaxScales() { return maxScales; }
/**
* Gets the scale spacing strategy.
* @return spacing strategy
*/
public ScaleSpacing getSpacing() { return spacing; }
/**
* Creates a builder for {@link ScaleSelectionConfig}.
* @param samplingRate sampling rate in Hz
* @return new builder instance
*/
public static Builder builder(double samplingRate) {
return new Builder(samplingRate);
}
/**
* Builder for {@link ScaleSelectionConfig}.
*/
public static class Builder {
private double samplingRate;
private double minFrequency = 0.0; // Auto-detect if 0
private double maxFrequency = 0.0; // Auto-detect if 0
private int scalesPerOctave = 10;
private boolean useSignalAdaptation = true;
private double frequencyResolution = 0.0; // Auto-detect if 0
private int maxScales = 200;
private ScaleSpacing spacing = ScaleSpacing.LOGARITHMIC;
/**
* Constructs a builder with the required sampling rate.
* @param samplingRate sampling rate in Hz
*/
private Builder(double samplingRate) {
this.samplingRate = samplingRate;
}
/**
* Sets the target frequency range; leave at 0 to auto-detect.
* @param minFreq minimum frequency (Hz)
* @param maxFreq maximum frequency (Hz)
* @return this builder
*/
public Builder frequencyRange(double minFreq, double maxFreq) {
this.minFrequency = minFreq;
this.maxFrequency = maxFreq;
return this;
}
/**
* Sets number of scales per octave.
* @param scales count per octave
* @return this builder
*/
public Builder scalesPerOctave(int scales) {
this.scalesPerOctave = scales;
return this;
}
/**
* Enables/disables signal-adaptive refinement.
* @param adapt true to adapt to signal properties
* @return this builder
*/
public Builder useSignalAdaptation(boolean adapt) {
this.useSignalAdaptation = adapt;
return this;
}
/**
* Sets desired frequency resolution; 0 to auto-detect.
* @param resolution frequency resolution (Hz)
* @return this builder
*/
public Builder frequencyResolution(double resolution) {
this.frequencyResolution = resolution;
return this;
}
/**
* Sets the maximum number of scales to produce.
* @param max maximum scale count
* @return this builder
*/
public Builder maxScales(int max) {
this.maxScales = max;
return this;
}
/**
* Selects spacing strategy (e.g., LOGARITHMIC or DYADIC).
* @param spacing spacing mode
* @return this builder
*/
public Builder spacing(ScaleSpacing spacing) {
this.spacing = spacing;
return this;
}
/**
* Builds configuration.
* @return new config instance
*/
public ScaleSelectionConfig build() {
return new ScaleSelectionConfig(this);
}
}
}
/**
* Different scale spacing strategies.
*/
enum ScaleSpacing {
/** Linear spacing between scales */
LINEAR,
/** Logarithmic spacing (constant ratio between scales) */
LOGARITHMIC,
/** Dyadic spacing (powers of 2) */
DYADIC,
/** Mel-scale spacing (perceptually uniform) */
MEL_SCALE,
/** Signal-adaptive spacing based on local frequency content */
ADAPTIVE
}
}