Main Content

Signal Imputation in Signal Analyzer Using Time-Series Foundation Model

Since R2026a

This example shows how to integrate a Chronos model [1] into a MATLAB® workflow to restore missing values in a corrupted signal. The example also shows how to use the Chronos model as a custom preprocessing function in Signal Analyzer and use Signal Analyzer to analyze the imputed signal.

Introduction

Foundation models like Chronos can handle a wide range of time-series forecasting tasks with minimal customization. You can apply the model to a new data set without training it on that data set and adapt it for tasks such as anomaly detection and imputation.

In this example, you implement the model in PyTorch®. The chronos_forecast.py file defines the interface functions to load Chronos models and perform forecasting. The helperFillMissingWithChronos function handles data exchange between MATLAB and Python®, using the Chronos forecasting model to perform signal imputation. The helperCustomFillGaps function integrates Chronos as a custom preprocessing step in Signal Analyzer.

Set Up Python Environment

Chronos is implemented in PyTorch, so you must configure a Python environment for MATLAB to call. To install a supported Python implementation, see Configure Your System to Use Python. To avoid library conflicts, use the External Languages side panel in MATLAB to create a Python virtual environment using the requirements_chronos.txt file. For details on the External Languages side panel, see Manage Python Environments Using External Languages Panel. For details on Python environment execution modes and debugging Python from MATLAB, see Python Coexecution.

Use the helperCheckPyenv function to verify that the current PythonEnvironment contains the libraries listed in the requirements_chronos.txt file. This example was tested using Python 3.11.2.

requirementsFile = "requirements_chronos.txt";
currentPyenv = helperCheckPyenv(requirementsFile,Verbose=true);
Checking Python environment
Parsing requirements_chronos.txt 
Checking required package 'chronos-forecasting'
Checking required package 'torch'
Required Python libraries are installed.

You can use the following process ID and name to attach a debugger to the Python interface and debug the example code.

fprintf("Process ID for '%s' is %s.\n", ...
  currentPyenv.ProcessName,currentPyenv.ProcessID)
Process ID for 'MATLABPyHost' is 2961556.

Chronos is available in multiple pretrained variants, such as chronos-t5-tiny, chronos-t5-small, and larger models. You can choose a variant depending on the complexity of your task and available resources. The actual pretrained model is not loaded into memory until you make the first prediction using that model name.

Call Chronos Forecasting Model from MATLAB

Clear the Python Chronos pipeline cache to force a fresh model and pipeline initialization.

py.chronos_forecast.clear_pipeline_cache(verbose=1);
[chronos] pipeline cache cleared

Generate a simple synthetic input signal to forecast. Set npred to 16 to predict the next 16 points given the input signal. Chronos is a probabilistic model, so each prediction is randomly generated. Set nsample to 3 to generate three different forecasts.

sigin = sin((1:64)*0.4);
npred = 16;
nsample = 3;

Call the Chronos forecasting function implemented in Python from within MATLAB.

sigoutnp = py.chronos_forecast.forecast(sigin, int64(16),int64(3),model_name="amazon/chronos-t5-tiny");
[chronos] initializing pipeline with ('amazon/chronos-t5-tiny', 'auto', torch.float32)

Convert the forecast output into a MATLAB double array. The size is 3-by-16, meaning three forecasts, each of length 16.

whos sigoutnp
  Name          Size            Bytes  Class               Attributes

  sigoutnp      1x1                 8  py.numpy.ndarray              
sigout = double(sigoutnp);
whos sigout
  Name        Size            Bytes  Class     Attributes

  sigout      3x16              384  double              

Visualize the results.

plot(1:64,sigin,64+1:64+16,sigout,"o")
legend(["Signal","Prediction" + (1:3)],Location="southoutside",Orientation="horizontal")
grid on
ylim([-1,1])

Fill Missing Values Using Chronos Model from MATLAB

Prepare Signal with Missing Data

Create a synthetic signal by adding a linear trend and small noise to a frequency-swept chirp, then simulate missing data with NaNs.

fs = 1000;
t = 0:1/fs:1.5-1/fs;
rng("default")
sigFull = chirp(t,10,0.5,30) + t + 0.3*rand(1,length(t));
sigMissing = sigFull;
sigMissing(600:850) = NaN;

Visualize the signal.

tiledlayout(2,1)
nexttile
plot(t,sigFull)
xlabel("Time (s)")
ylabel("Amplitude")
title("Original Signal")
grid on

nexttile
plot(t,sigMissing)
xlabel("Time (s)")
ylabel("Amplitude")
title("Signal with Missing Data")
grid on

Fill Missing Values in MATLAB Using Chronos

Use the provided helper function, helperFillMissingWithChronos, to call the Chronos model from MATLAB. For this simple case, use the lightweight chronos-t5-tiny variant.

Chronos is a probabilistic forecaster that not only provides a single imputed signal but also produces uncertainty bounds. The helperFillMissingWithChronos function returns not only a median prediction (filledChronos) but also lower and upper bounds (filledChronosLow and filledChronosHigh) that define a central 80% predictive interval, giving a sense of confidence around the reconstructed values inside the missing region.

Modify the function parameters to control how the function predicts missing values.

  • ContextLength — Control the number of previous time steps to use.

  • MaxHorizon — Determine how far ahead to predict.

  • Bidirectional — Enable the model to run both forward and backward passes, using past data to predict ahead and future data to predict backward, improving estimates within gaps.

  • AggregationMethod — Determine how forward and backward predictions are combined. For example, "half" fills the first half of each missing region using the forward pass and the second half using the backward pass.

  • ModelName — Select the Chronos model to use. The lightweight "amazon/chronos-t5-tiny" runs quickly, while "amazon/chronos-t5-small" or "amazon/chronos-t5-base" can improve accuracy on more complex data.

  • ExecutionEnvironment — Specify the hardware resource for running the model. Defaults to "auto", but can be set to "cpu" or "gpu" for explicit control.

  • Verbose — Control whether to display detailed progress information.

[filledChronos,filledChronosLow,filledChronosHigh] = helperFillMissingWithChronos( ...
    sigMissing, ...
    ContextLength=512, ...
    MaxHorizon=64, ...
    Bidirectional=true, ...
    AggregationMethod="half", ...
    ModelName="amazon/chronos-t5-tiny", ...
    ExecutionEnvironment ="auto",...
    Verbose=true);
[MATLAB] Clearing pipeline cache...
[chronos] pipeline cache cleared
[MATLAB] Starting Forward pass: 4 windows to forecast
[chronos] initializing pipeline with ('amazon/chronos-t5-tiny', 'auto', torch.float32)
[MATLAB] 1/4 Forward window | elapsed=0.8s ETA=2.5s
[MATLAB] 2/4 Forward window | elapsed=1.3s ETA=1.3s
[MATLAB] 3/4 Forward window | elapsed=1.8s ETA=0.6s
[MATLAB] 4/4 Forward window | elapsed=2.3s ETA=0.0s
[MATLAB] Starting Backward pass: 4 windows to forecast
[MATLAB] 1/4 Backward window | elapsed=0.5s ETA=1.5s
[MATLAB] 2/4 Backward window | elapsed=1.0s ETA=1.0s
[MATLAB] 3/4 Backward window | elapsed=1.5s ETA=0.5s
[MATLAB] 4/4 Backward window | elapsed=2.0s ETA=0.0s

Compare Results

Compare the original signal, the Chronos-imputed signal, and the result from an autoregressive gap-filling method.

filledAR = fillgaps(sigMissing);

fig = helperPlotImputationComparison(t, sigMissing, sigFull, ...
    filledAR, filledChronos, filledChronosLow, filledChronosHigh);

Both methods exhibit slight discontinuities at the edges of the imputed regions. The Chronos model better preserves the signal's frequency and amplitude characteristics across the gap, while the autoregressive model introduces more noticeable distortions.

A closer look at the Chronos model shows that the 80% confidence interval becomes wider near the center of the gap, indicating increased uncertainty. This behaviour makes sense because the model relies on observed data at both ends of the gap to inform its predictions. The farther a point is from any known data, the less information the model has available to work with, so its confidence naturally decreases. As a result, the uncertainty is highest near the middle of the missing region.

Further compare the time-frequency characteristics of different imputation methods using spectrograms.

figure(Position=[0 0 800 600]);
tiledlayout(3,1);
sigList = {sigFull,filledChronos,filledAR};
sigNames = {"Original", "Chronos Imputed", "AR Imputed"};
for ii = 1:3
    nexttile
    sig = sigList{ii};
    spectrogram(sig,128,96,"yaxis",MinThreshold=-30);
    set(gca,'ylim',[0,0.2])
    ylabel("Frequency")
    title(sigNames(ii))
end

As shown, the Chronos-imputed result preserves the overall frequency trend across the missing region and maintains spectral energy more effectively than the autoregressive model.

Use Chronos Model as Custom Preprocessing Function in Signal Analyzer

Launch Signal Analyzer to Inspect Corrupted Signal

Load the sample vibration signal from the Helidata data set, which contains simulated accelerometer data recorded in a helicopter cabin during the main motor’s run-up and coast-down. The file includes a variable, vib, that holds the vibration time series.

data = load("helidata");
signalGroundTruth = data.vib;

Set the random seed for reproducible gaps. Use helperAddRandomMissing to introduce 15% missing samples into vibsignal between 20% and 80% of its length, with each gap spanning 10–50 samples.

rng("default")
gapRange = [round(0.2*numel(signalGroundTruth)) round(0.8*numel(signalGroundTruth))];
[sigCorrupted, gapMask] = helperAddRandomMissing( ...
    signalGroundTruth, ...
    0.15, ...
    Range=gapRange, ...
    MinGapLen=10, ...
    MaxGapLen=50 ...
);

Open Signal Analyzer and display the corrupted signal.

signalAnalyzer(sigCorrupted)

Duplicate and Preprocess Signals

Follow the instructions in Preprocess Signals to add a custom preprocessing function, which internally calls the MATLAB wrapper function of your Python model.

Use the provided helperCustomFillGaps function as an example. It internally calls helperFillMissingWithChronos. Duplicate the corrupted signal in the Signals table to preserve a reference. Apply the custom fill-gaps function only to the copy. Press Accept All to commit the changes.

The Signal Analyzer app in preprocess mode displays the duplicated signal “sigCorrupted_Copy” as a time plot from 0 to 5000 samples (approximately −20 to 40 amplitude) with some missing points. The Signals table appears on the left, and the Function Parameters panel on the right is set to the custom function helperCustomFillGaps, which includes an Apply button. Toolbar actions include Accept All and Cancel.

Compare Original and Filled Signals

Accept all changes and compare the filled signal with the original ground truth signal.

The Signal Analyzer app in display mode shows two time plots for comparison. The upper plot displays the original corrupted signal “sigCorrupted,” and the lower plot shows the filled signal “sigCorrupted_Chronos,” both ranging from 0 to 5000 samples. The two signals appear visually similar, but the Chronos version has no missing points.

Further compare the spectrograms obtained from the Chronos model (imputed), the autoregressive model (imputed), and the ground truth signal, shown from left to right.

The Signal Analyzer app in spectrogram mode displays three sets of time plots and spectrograms for comparison. From left to right, the panels show the ground truth signal, the Chronos-imputed signal, and the autoregressive (AR)-imputed signal. Each panel includes a waveform plot over 0 to 5000 samples and a corresponding spectrogram below it showing normalized frequency versus time. The spectrograms for the Chronos and AR models closely resemble the ground truth pattern, indicating accurate signal reconstruction.

Conclusion

This example demonstrates how to integrate Python-based models into MATLAB workflows and Signal Analyzer, enabling advanced data preprocessing directly within MATLAB. By bringing Python capabilities into MATLAB, you can expand preprocessing options while continuing to leverage MATLAB interactive apps, visualization, and analysis tools in a seamless environment.

Reference

[1] Ansari, Abdul Fatir, Lorenzo Stella, Caner Turkmen, Zhang Xiyuan, Pedro Mercado, Huibin Shen, Oleksandr Shchur, et al. "Chronos: Learning the Language of Time Series." Transactions on Machine Learning Research, 2024. https://openreview.net/forum?id=gerNCVqqtR

Appendix — Helper Functions

helperPlotAnomalyResults This function plots imputation results comparing AR and Chronos methods.

function fig = helperPlotImputationComparison(t, sigMissing, sigFull, filledAR, filledChronos, filledChronosLow, filledChronosHigh)
% Plot imputation results comparing AR and Chronos methods
% This function is only intended to support this example. It may be changed
% or removed in a future release. 

    arguments
        t (:,1) {mustBeNumeric}
        sigMissing (:,1) {mustBeNumeric}
        sigFull (:,1) {mustBeNumeric}
        filledAR (:,1) {mustBeNumeric}
        filledChronos (:,1) {mustBeNumeric}
        filledChronosLow (:,1) {mustBeNumeric}
        filledChronosHigh (:,1) {mustBeNumeric}
    end

    % Compute masks
    m = isnan(sigMissing);
    o = ~m;

    % Create observed/imputed versions
    chronosObs = filledChronos;
    chronosImp = filledChronos;
    chronosObs(m) = NaN;
    chronosImp(o) = NaN;

    arObs = filledAR;
    arImp = filledAR;
    arObs(m) = NaN;
    arImp(o) = NaN;

    % Create figure
    fig = figure(Position=[0 0 800 800]);
    tiledlayout(4, 1, TileSpacing="compact")

    % Plot 1: Original Signal
    nexttile
    hold on
    plot(t, sigMissing, LineWidth=1.2, DisplayName="Observed")
    plot(t(m), sigFull(m), DisplayName="True (Gap)")
    hold off
    title("Original Signal")
    legend(Location="northwest")
    box on
    grid on

    % Plot 2: AR Imputed
    nexttile
    hold on
    plot(t, arObs, LineWidth=1.2, DisplayName="Observed")
    plot(t, arImp, DisplayName="AR (Imputed)")
    hold off
    title("AR Imputed")
    xlabel("Time (s)")
    legend(Location="northwest")
    grid on
    box on

    % Plot 3: Chronos Imputation with Uncertainty Band
    nexttile
    ax = gca;
    c = ax.ColorOrder(5,:);
    hold on
    plot(t, chronosObs, LineWidth=1.2, DisplayName="Observed")
    fill([t(:); flipud(t(:))], [filledChronosLow(:); flipud(filledChronosHigh(:))], c, ...
        FaceAlpha=0.8, EdgeColor="none", DisplayName="80% Confidence Band")
    plot(t, chronosImp, LineWidth=1.2, DisplayName="Chronos (Imputed)")
    hold off
    title("Chronos Imputation with Uncertainty Band")
    legend(Location="northwest")
    grid on
    box on

    % Plot 4: Chronos vs Ground Truth
    nexttile
    hold on
    plot(t, sigMissing, LineWidth=1.2, DisplayName="Observed")
    plot(t(m), sigFull(m), LineWidth=1.2, DisplayName="True (Gap)")
    plot(t, chronosImp, "--", LineWidth=1.2, DisplayName="Chronos (Imputed)")
    hold off
    title("Chronos Imputed vs Ground Truth")
    xlabel("Time (s)")
    legend(Location="northwest")
    grid on
    box on

    % Link axes
    linkaxes(findall(fig, Type="Axes"), "xy")

    % Adjust view after plotting
    xlim([0.4 1])
    ylim([-1.1 2.2])

end

See Also

Apps

Functions

Topics