Resample

Change a signal's sample rate, filtering as it goes so nothing folds back.

Resample py
input
out
Type name
signal:Resample
Plane
signal
Tags
transform
Language
python
Tier
in-process
Bundle
signal
Source
node-bundles/signal/resample.py
Availability
available

Slots

SlotDirectionType
inputinputARRAY
outoutputARRAY

Parameters

resample

NameTypeDefaultRangeDoc
sfreqfloat2501 … 100000The rate to answer at, in Hz.
axisint-1-8 … 7Which axis holds the samples. -1 is time.

common

NameTypeDefaultRangeDoc
autotriggerboolfalseRun on the node's own schedule, instead of waiting for an input frame. Turn this on for sources; leave it off for transforms driven by their input.
max_frequencyfloat00 … 100Rate cap for this node, read through `frequency_mode`. 0 means uncapped — the node runs as often as the scheduler and its inputs allow.
frequency_modestringupdates_per_secondupdates_per_second | seconds_per_updateHow to read `max_frequency`: as a rate in Hz (updates per second), or as a period in seconds between updates — convenient for very slow nodes.

Source

The current source of this node, as it stands in the goofi repository at node-bundles/signal/resample.py.

node-bundles/signal/resample.py
"""Resample — the same signal at a different sample rate.

Polyphase, so the filter that stops aliasing is part of the resampling rather than a step before
it. The frame carries the new rate out; labels on the resampled axis go, because the samples they
named are gone.
"""

import numpy as np
from scipy.signal import resample_poly
import goofi


class Resample(goofi.Node):
    """Change a signal's sample rate, filtering as it goes so nothing folds back."""

    TAGS = ["transform"]
    INPUTS = {"input": goofi.InputSlot(goofi.DataType.ARRAY, required=True)}
    OUTPUTS = {"out": goofi.DataType.ARRAY}
    PARAMS = {
        "resample": {
            "sfreq": goofi.FloatParam(250.0, 1.0, 100000.0, doc="The rate to answer at, in Hz."),
            "axis": goofi.IntParam(-1, -8, 7, doc="Which axis holds the samples. -1 is time."),
        }
    }

    def process(self, input):
        p = self.params.resample
        source = input.meta.get("sfreq")
        if not source:
            raise ValueError("this node needs a frame that carries its sample rate")
        axis = p.axis if p.axis >= 0 else p.axis + input.data.ndim
        ratio = np.gcd(int(round(p.sfreq)), int(round(source)))
        up, down = int(round(p.sfreq)) // ratio, int(round(source)) // ratio
        out = resample_poly(np.asarray(input.data, dtype=np.float64), up, down, axis=axis)
        axes = {k: v for k, v in input.meta.get("channels", {}).items() if k != f"dim{axis}"}
        return out.astype(np.float32), {**input.meta, "channels": axes, "sfreq": p.sfreq}

← All nodes

This reference describes goofi 3.1.0(537cd394), generated from a running instance on 2026-09-06.