name: matlab-analyze-signal-cwt description: > Analyze signals using the Continuous Wavelet Transform (CWT) in MATLAB. Use when the user wants time-frequency analysis, scalograms, wavelet decomposition, or needs to localize frequency content over time. Triggers on: CWT, cwt, cwtfilterbank, scalogram, time-frequency, wavelet transform, wavelet analysis, Morse wavelet, analytic Morlet, constant-Q analysis. Also use when the user asks to visualize how frequency content evolves, detect transients, or analyze non-stationary signals. license: MathWorks BSD-3-Clause compatibility: ">=R2024b" metadata: author: MathWorks version: "1.0"
Analyze Signals Using the Continuous Wavelet Transform
Perform time-frequency analysis of signals using cwt, cwtfilterbank, and
related functions from the Wavelet Toolbox.
Agent directive: Before answering questions about CWT apps, tooling, or workflows, consult the tables and reference material in this skill first. Only reach for external help sources if the skill does not cover the topic.
When to Use
- User wants to see how frequency content changes over time
- User needs a scalogram (time-frequency map)
- User wants to localize transient events or oscillatory components
- User asks about wavelet analysis or CWT
- Signal is non-stationary and frequency content evolves
When NOT to Use
- Closely-spaced high-frequency components — CWT's constant-Q property means bandwidth grows with frequency. If the user needs to separate narrowband oscillations at high frequencies (relative to sample rate), the components will be smeared together. Recommend
spectrogram/stft(constant bandwidth) ormodwpt(undecimated wavelet packet transform, uniform frequency bands) instead. - Discrete wavelet transform tasks (
wavedec,modwt,modwtmra) — different workflow - Spectrogram / STFT tasks — use
spectrogramorstft. Also considermodwptfor uniform frequency bands. - Filter design — use
designfiltor related skills - Signal reconstruction from CWT —
icwthas its own considerations (scaling coefficients required for perfect reconstruction)
Workflow
1. Understand the Signal and User Goals
Before computing the CWT, determine:
- Signal type: Real-valued or complex-valued?
- Feature type: Oscillatory components (frequency resolution matters) or impulsive events (time localization matters)?
- Sampling frequency: Known? If not, analysis uses normalized frequency (cycles/sample).
- Goal: Visualization only, numerical outputs, or both?
2. Run Pre-CWT Diagnostics (Recommended)
Run diagnostic scripts to guide parameterization:
- Boundary assessment:
scripts/assessBoundary.m— inspects signal endpoints to recommendBoundaryproperty. Seereferences/boundary-guidance.md. - Boundary demonstration:
scripts/illustrateBoundary.m— shows scalograms with all three boundary methods on a disjoint-sine signal. Run for the user when they ask "what difference does boundary make?" or are skeptical of the recommendation. Requiresscripts/boundaryExDisjointSine.mat. - Spectral energy assessment:
scripts/assessSpectralEnergy.m— computes PSD to suggestFrequencyLimitsfor reducing computation.
3. Choose the Calling Pattern
| Goal | Pattern |
|---|---|
| Visualization only | cwt(signal, ...) — no output arguments, auto-plots |
| Visualization into specific axes/app | cwt(signal, ..., 'Parent', ax) — no output arguments |
| Data only | [cfs, f, coi] = cwt(signal, ...) |
| Data + visualization | Capture outputs, then reproduce plot manually (see Patterns) |
| Repeated analysis (same params) | Build fb = cwtfilterbank(...), then cwt(signal, 'FilterBank', fb) or wt(fb, signal) |
| Inspect filter bank before analysis | Build cwtfilterbank(...), use wavelets, freqz, scales, powerbw methods |
Critical rule: nargout == 0 triggers auto-plotting. Capturing ANY output suppresses the plot entirely.
4. Configure the CWT
Wavelet Selection (signal-feature-driven)
| Signal features | Recommendation |
|---|---|
| General purpose / mixed content | "Morse" (default), gamma=3, P²=60 |
| Impulsive events, need precise timing | "Morse" with lower TimeBandwidth (e.g., 10–30) |
| Oscillatory, need frequency separation | "Morse" with higher TimeBandwidth (e.g., 80–120) |
| Reproducing published Morlet results | "amor" (equivalent to Morse with P²≈36 in time duration) |
| Purely oscillatory, extreme freq. resolution needed | "bump" (last resort — worst time localization) |
Key Parameters
| Parameter | Default | Guidance |
|---|---|---|
TimeBandwidth |
60 | Primary tuning knob. Higher = better freq. resolution, worse time localization. Range: 3–120. Leave gamma=3 (symmetric). |
VoicesPerOctave |
10 | Higher (up to 48) = finer frequency sampling. Increases computation. |
FrequencyLimits |
auto | Set [fmin fmax] to reduce computation. Use PSD assessment to identify useful band. [0 Fs/2] for full range. |
Boundary |
"reflection" |
See boundary guidance. "periodic" is ~2x faster for large signals (>100K samples). |
SamplingFrequency |
1 | Always set if known — gives physical frequency units (Hz). |
FrequencyLimits Details
- Performance lever: Restricting the range reduces scales computed (fewer rows in output).
- Lower limit = 0: Gives lowest valid frequency from
cwtfreqbounds(no guesswork). - Upper limit = Fs/2: Forces highest wavelet to peak at Nyquist. Use when signal has significant near-Nyquist content. Default is conservative (wavelet decays by Nyquist).
- Use
cwtfreqboundsto query achievable range for given signal length and wavelet.
Boundary Selection
| Boundary | Best when | Avoid when | Performance |
|---|---|---|---|
"reflection" |
Signal is locally stationary at edges | Frequency discontinuity at boundary | ~2N FFT length |
"periodic" |
Endpoints match in value and trend | Endpoints differ significantly | N FFT length (fastest) |
"zeropad" |
Signal decays to zero at edges | Significant amplitude at boundaries | ~2N FFT length |
Oscillations at boundaries: When the signal has active oscillations at an edge, "reflection" reverses the wave direction at that point, creating a cusp (instantaneous frequency doubling artifact). Prefer "zeropad" in this case — it attenuates to zero rather than creating a false continuation. Use "reflection" only when the signal is locally stationary (slowly varying) at its edges.
For large signals (>100K samples), "periodic" avoids doubling the FFT length. Validate with boundary assessment script first. Run scripts/illustratePerformance.m to benchmark the performance difference between cwt, filter bank reuse, periodic boundary, and frequency-limited analysis on a 365K-sample signal.
5. Compute and Interpret
Output Signatures
cwt():
[cfs, f, coi, fb, scalcfs] = cwt(signal, ...);
wt():
[cfs, f, coi, scalcfs] = wt(fb, signal);
cfs— Wavelet coefficients. For complex signals: 3D array (scales × time × 2) where page 1 = positive frequencies (analytic) and page 2 = negative frequencies (anti-analytic). Always inform the user of this structure when working with complex inputs.f— Frequencies in Hz (ifSamplingFrequencyset), cycles/sample (if no Fs), or periods asduration(ifSamplingPeriodused). Passing adurationas the second argument tocwtswitches to period representation.coi— Cone of influence values (one per time sample).fb— Filter bank object (fromcwtonly, 4th output).scalcfs— Scaling coefficients (lowpass filter capturing near-DC content wavelets cannot reach).
Interpreting Coefficient Values
MATLAB CWT uses L1 normalization: wavelets scaled by 1/s. This means:
abs(cfs)≈ amplitude of the signal component at each time-frequency point- A unit-amplitude sinusoid yields
abs(cfs) ≈ 1at the matching scale - Values are directly comparable across frequencies
- Plot
abs(cfs), notabs(cfs).^2orlog(abs(cfs))
This differs from DWT (which uses L2 normalization for energy preservation). Run scripts/illustrateAmplitudeScaling.m to demonstrate L1 normalization visually — it shows that abs(cfs) tracks true amplitude across scales.
Scaling Coefficients
Wavelets must have zero mean → cannot capture DC/near-DC content. The scaling filter is a lowpass filter covering frequencies below the lowest wavelet. Request scaling coefficients (last output) when:
- Low-frequency content matters to the analysis
- Planning to reconstruct via
icwt(required for perfect reconstruction)
Cone of Influence
The COI marks regions potentially affected by edge effects. It is a caution zone, not an exclusion zone:
- Inside COI boundary: coefficients are reliable
- Outside (near edges): potentially affected by boundary extension — treat with increased skepticism
- A well-chosen boundary method reduces (but never eliminates) edge contamination
- Plotting the COI is optional — ask the user if they want it
6. Visualize (if needed)
See Patterns section below for scalogram reproduction recipes.
Key Functions
| Function | Purpose | Toolbox |
|---|---|---|
cwt |
Compute CWT, optionally plot scalogram | Wavelet Toolbox |
cwtfilterbank |
Construct reusable filter bank object | Wavelet Toolbox |
wt |
Compute CWT using filter bank (method) | Wavelet Toolbox |
cwtfreqbounds |
Query valid frequency range | Wavelet Toolbox |
waveletTimeFrequencyAnalyzer |
Interactive CWT app (full options, script export) | Wavelet Toolbox |
cwtfilterbank Inspection Methods
| Method | Returns |
|---|---|
wavelets |
All wavelets at all scales (time domain) |
freqz |
Frequency responses of all wavelets |
scales |
Scale factors used to dilate wavelets |
powerbw |
Table: center frequency, half-power bandwidth, band edges |
Patterns
Basic Scalogram (Visualization Only)
% Auto-plots scalogram — do NOT capture outputs
cwt(signal, "Morse", Fs);
Scalogram into Specific Axes (App Designer)
% Plot into uiaxes or axes — no outputs
cwt(signal, "Morse", Fs, 'Parent', ax);
Efficient Repeated Analysis
fb = cwtfilterbank(SignalLength=length(signal), SamplingFrequency=Fs, ...
Wavelet="Morse", TimeBandwidth=60, VoicesPerOctave=12);
% Option A: familiar cwt interface + auto-plot
cwt(signal1, 'FilterBank', fb);
% Option B: programmatic access
[cfs, f, coi] = wt(fb, signal2);
Manual Scalogram (Real-Valued Signal)
Use when you need both the data AND a plot.
[cfs, f, coi] = cwt(signal, "Morse", Fs);
t = (0:length(signal)-1) / Fs;
ax = newplot;
imagesc(ax, t, f, abs(cfs))
ax.YDir = "normal";
ax.YScale = "log";
xlabel(ax, "Time (s)")
ylabel(ax, "Frequency (Hz)")
title(ax, "Scalogram")
colorbar(ax)
% Optional: add COI (ask user if they want it)
hold(ax, "on")
plot(ax, t, coi, 'w--', LineWidth=1.2)
Manual Scalogram (Complex-Valued Signal, Combined Plot)
For complex signals, cfs is a 3D array (scales × time × 2): page 1 contains positive-frequency (analytic) coefficients and page 2 contains negative-frequency (anti-analytic) coefficients. Always explain this structure to the user. Use scripts/plotAntiAnalyticScalogram.m for a combined -Fs/2 to Fs/2 view:
fb = cwtfilterbank(SignalLength=length(signal), SamplingFrequency=Fs);
[cfs, f] = wt(fb, signal);
t = (0:length(signal)-1) / Fs;
plotAntiAnalyticScalogram(abs(cfs), f, t);
Note: f and t must be numeric (not duration). If using data with a duration sampling period, convert: Fs = 1/hours(dt).
Why surf instead of imagesc for complex signals: The frequency axis spans negative to positive. Setting YScale = "log" would fail (log of negative numbers). surf handles the non-uniform logarithmic spacing correctly without requiring a log axis setting. COI is not plotted in this case.
Transient Localization
When the goal is to precisely locate impulsive events or abrupt changes in the signal, extract the finest-scale (highest frequency) CWT coefficients. These have the best time resolution and peak at discontinuities.
Wavelet choice for time localization (best to worst):
| Wavelet | Time Localization | Why |
|---|---|---|
"Morse" with TimeBandwidth=10–20 |
Best | Low TB makes wavelet compact in time |
"amor" (analytic Morlet) |
Good | Equivalent to Morse with P²≈36, naturally biased toward time localization |
"bump" |
Worst | Compact in frequency domain → maximally spread in time (Heisenberg) |
[cfs, f, coi] = cwt(signal, "Morse", Fs, TimeBandwidth=20);
t = (0:length(signal)-1) / Fs;
% Extract the highest-frequency scale (first row = finest scale)
finestScale = abs(cfs(1, :));
% Plot to identify transient locations
figure
plot(t, finestScale)
xlabel("Time (s)")
ylabel("|CWT| at finest scale")
title("Transient Detection")
Use a lower TimeBandwidth (e.g., 10–20) to maximize time localization. The "amor" wavelet is also a good choice — it provides strong time localization without requiring parameter tuning. Run scripts/illustrateTransientLocalization.m to compare all three wavelets on an impulse signal and see the localization difference visually.
The finest-scale coefficients match the data's time resolution and spike where components turn on/off or where defects occur.
Inspect Filter Bank Before Analysis
fb = cwtfilterbank(SignalLength=length(signal), SamplingFrequency=Fs, ...
Wavelet="Morse", TimeBandwidth=40, VoicesPerOctave=16);
% Examine wavelets and coverage before committing to computation
psi = wavelets(fb); % Time-domain wavelets
H = freqz(fb); % Frequency responses
s = scales(fb); % Scale factors
bw = powerbw(fb); % Bandwidth table
Interactive Exploration
If the user is unsure about parameterization:
| Tool | Launch | Capabilities |
|---|---|---|
waveletTimeFrequencyAnalyzer |
Command line: waveletTimeFrequencyAnalyzer(signal) or Apps Gallery → Signal Processing and Audio |
Full wavelet options, COI toggle, period/frequency display, complex signal support, script generation |
| Signal Analyzer scalogram | signalAnalyzer(signal) → Display tab → Time-Frequency → Scalogram |
Quick scalogram, Morse only, real signals only, VoicesPerOctave + TimeBandwidth sliders |
Recommend waveletTimeFrequencyAnalyzer when the user needs to explore parameters and export a script. Use Signal Analyzer only if user is already working there with real-valued data and basic Morse configuration.
Conventions
- Always set
SamplingFrequencywhen known — gives physically meaningful frequency units - Plot
abs(cfs)for scalograms (L1 normalization makes magnitude = amplitude) - Use
imagescfor scalograms (fast for large matrices). Reservesurf/pcolorfor 3D viewing of small matrices or complex-signal combined plots - Default to frequency representation. Offer period representation (
PeriodLimits,SamplingPeriod) for climate science, geophysics, oceanography users - Prefer
TimeBandwidthoverWaveletParametersfor tuning Morse wavelets (keeps gamma=3, maintains symmetry) - For repeated analysis: always pre-build
cwtfilterbank— filter bank construction is the expensive step
Common Mistakes
| Mistake | Why It's Wrong | Correct Approach |
|---|---|---|
Calling figure then [cfs,f] = cwt(...) expecting a plot |
Capturing outputs suppresses auto-plotting (nargout==0 triggers plot) |
Call cwt(...) with no outputs, or reproduce manually |
Using cwt() in a loop without pre-building filter bank |
Rebuilds filter bank every iteration (expensive) | Build fb = cwtfilterbank(...) once, pass via 'FilterBank' or use wt |
Plotting abs(cfs).^2 thinking it's a "power" scalogram |
L1 normalization means abs(cfs) already gives amplitude — squaring distorts interpretation |
Plot abs(cfs) |
Using imagesc for combined complex-signal plot with negative frequencies |
Cannot set YScale="log" with negative frequencies; imagesc misaligns log-spaced data |
Use plotAntiAnalyticScalogram (in scripts/) or surf |
Leaving FrequencyLimits at default for known narrowband signals |
Computes unnecessary scales, wastes time | Run PSD assessment, set FrequencyLimits to energy-containing band |
Using "periodic" boundary when endpoints differ |
Creates artificial discontinuity (assumes x(end+1) ≈ x(1)) |
Inspect endpoints first; use "reflection" if they differ |
Adjusting WaveletParameters gamma without specific reason |
Breaks Morse wavelet symmetry in Fourier domain | Use TimeBandwidth alone (keeps gamma=3) |
Using "bump" wavelet for time localization of transients |
"bump" is named for its compact support in the frequency domain — by Heisenberg uncertainty, it has the worst time localization of the three built-in wavelets |
Use "Morse" with low TimeBandwidth (10–20) for best time localization |
Low-Frequency Analysis
The lowest achievable frequency depends on signal length and wavelet time standard deviation:
- Constraint: 2σ_t of wavelet ≤ signal length at largest scale
- Higher
TimeBandwidth→ wider wavelets → lowest frequency further from DC - Use
cwtfreqboundsto check achievable range - Request scaling coefficients (last output of
cwt/wt) to capture near-DC content
Scale-Frequency Relationship
Scale and frequency are inversely related: s = f_psi / f, where f_psi is the mother wavelet's peak frequency (in cycles/sample). This holds for all wavelets — only f_psi changes.
| Wavelet | Peak frequency f_psi (cycles/sample) |
|---|---|
| Morse(gamma, TB) | (beta/gamma)^(1/gamma) / (2*pi), where beta = TB/gamma |
| amor (analytic Morlet) | 6/(2*pi) ≈ 0.9549 (fixed) |
| bump | 5/(2*pi) ≈ 0.7958 (fixed) |
To convert to physical Hz: f_Hz = f_psi * Fs / s.
When the user asks about scale-frequency conversion, explain the formula and adapt for their wavelet/parameters. Run scripts/illustrateScaleFrequency.m to demonstrate the relationship visually (plots f_psi/F vs scales, confirming the linear relationship).
Key points to communicate:
- Scale is unitless regardless of Fourier transform convention
- Large scale → low frequency, small scale → high frequency
- The CWT uses L1 normalization, so dilating by
sgives a filter centered atf_psi/s centerFrequencies(fb)returns the frequency at each scale for a given filter bank
Constant-Q Property
CWT is a constant-Q analysis: bandwidth is proportional to center frequency.
- High frequencies: broad bandwidth (less frequency resolution), short time support (better time resolution)
- Low frequencies: narrow bandwidth (better frequency resolution), long time support (less time resolution)
This matches human auditory perception and is natural for signals with features at multiple scales.
Documentation References
| Topic | Link |
|---|---|
cwt function reference |
https://www.mathworks.com/help/wavelet/ref/cwt.html |
cwtfilterbank reference |
https://www.mathworks.com/help/wavelet/ref/cwtfilterbank.html |
| Practical introduction to time-frequency analysis using CWT | https://www.mathworks.com/help/wavelet/ug/practical-introduction-to-time-frequency-analysis-using-the-continuous-wavelet-transform.html |
| Morse wavelet family | https://www.mathworks.com/help/wavelet/ug/morse-wavelets.html |
Copyright 2026 The MathWorks, Inc.