moonsignalkit

Streaming telemetry statistics and change detection for MoonBit.

signal
timeseries
streaming
telemetry
cusum
anomaly-detection
moon add cn-wn/moonsignalkit@0.3.0
Download zip
Author
Version
0.3.0
License
Apache-2.0
Last updated
last month
Downloads
17
README

#MoonSignalKit

MoonSignalKit supplies portable time-series and streaming telemetry primitives for MoonBit: batch summaries, bounded rolling quantiles, filters, CSV interchange, online moments, timestamp monitoring, and two-sided CUSUM.

#Add to a project

moon add cn-wn/moonsignalkit

///|
test {
let monitor = TimestampMonitor::new(10)
let _first = monitor.observe(Sample::new(100, 1.0))
let observation = monitor.observe(Sample::new(115, 1.0))
assert_true(observation.is_gap)
}

The package has no filesystem, network, browser, or FFI dependency, so its API is shared by Native, JavaScript, Wasm, and Wasm-GC targets. For full examples, quality gates, scope, and related work, see the repository README.

#
ChangeDirection

pub(all) enum ChangeDirection {
Rising
Falling
} derive(Eq,
Debug
)

#
ChangePoint

pub(all) struct ChangePoint {
sample : Sample
direction : ChangeDirection
magnitude : Double
observation : Int
} derive(
Debug
)

A sustained level shift reported by CusumDetector.

#
ChangePoint::to_json

fn ChangePoint::to_json(self : ChangePoint) -> String

#
CsvError

pub(all) enum CsvError {
EmptyInput
MissingColumns(Int)
InvalidTime(Int)
InvalidValue(Int)
} derive(Eq,
Debug
)

Errors reported by the intentionally small, dependency-free telemetry CSV reader.

The format is two columns: time,value. Quoted fields and locale-specific numeric formats are intentionally out of scope for a portable core library.

#
CusumDetector

pub(all) struct CusumDetector {
target : Double
drift : Double
threshold : Double
positive_sum : Double
negative_sum : Double
observations : Int
} derive(
Debug
)

Stateful two-sided CUSUM detector for streaming telemetry.

target is the expected process level, drift suppresses ordinary noise, and threshold controls how much cumulative evidence triggers an event.

#
CusumDetector::new

fn CusumDetector::new(target : Double, drift : Double, threshold : Double) -> CusumDetector

#
CusumDetector::push

fn CusumDetector::push(self : CusumDetector, sample : Sample) -> ChangePoint?

Processes one sample in O(1) time and returns an event only on a level shift.

#
CusumDetector::reset_evidence

fn CusumDetector::reset_evidence(self : CusumDetector) -> Unit

Clears accumulated evidence while preserving configuration and count.

#
EwmaFilter

pub(all) struct EwmaFilter {
alpha : Double
has_value : Bool
value : Double
} derive(
Debug
)

O(1)-memory exponentially weighted moving-average filter.

#
EwmaFilter::new

fn EwmaFilter::new(alpha_per_mille : Int) -> EwmaFilter

#
EwmaFilter::push

fn EwmaFilter::push(self : EwmaFilter, sample : Sample) -> Sample

#
EwmaFilter::reset

fn EwmaFilter::reset(self : EwmaFilter) -> Unit

#
EwmaFilter::value

fn EwmaFilter::value(self : EwmaFilter) -> Double?

#
MedianFilter

pub(all) struct MedianFilter {
window : RollingWindow
} derive(
Debug
)

A bounded median filter for suppressing isolated telemetry spikes.

#
MedianFilter::new

fn MedianFilter::new(window : Int) -> MedianFilter

#
MedianFilter::push

fn MedianFilter::push(self : MedianFilter, sample : Sample) -> Sample

#
MedianFilter::reset

fn MedianFilter::reset(self : MedianFilter) -> Unit

#
OnlineMoments

pub(all) struct OnlineMoments {
count : Int
mean : Double
m2 : Double
min : Double
max : Double
} derive(
Debug
)

Numerically stable online statistics using Welford's algorithm.

Each sample is processed in O(1) time and O(1) memory, so the accumulator can be used for unbounded telemetry streams without retaining raw samples.

#
OnlineMoments::new

#
OnlineMoments::push

fn OnlineMoments::push(self : OnlineMoments, value : Double) -> Unit

Adds one observation using a stable one-pass update.

#
OnlineMoments::std_dev

fn OnlineMoments::std_dev(self : OnlineMoments) -> Double

#
OnlineMoments::summary

fn OnlineMoments::summary(self : OnlineMoments) -> Summary

Takes an immutable summary without resetting the accumulator.

#
OnlineMoments::variance

fn OnlineMoments::variance(self : OnlineMoments) -> Double

#
RollingWindow

pub(all) struct RollingWindow {
capacity : Int
values : Array[Sample]
size : Int
next : Int
} derive(
Debug
)

A bounded chronological telemetry window.

Appending a sample is O(1). Summaries and quantiles deliberately inspect the bounded window, so their cost is O(window_size) and does not grow with the lifetime of a stream.

#
RollingWindow::capacity

fn RollingWindow::capacity(self : RollingWindow) -> Int

#
RollingWindow::is_ready

fn RollingWindow::is_ready(self : RollingWindow) -> Bool

#
RollingWindow::length

fn RollingWindow::length(self : RollingWindow) -> Int

#
RollingWindow::median

fn RollingWindow::median(self : RollingWindow) -> Double

#
RollingWindow::new

fn RollingWindow::new(capacity : Int) -> RollingWindow

#
RollingWindow::push

fn RollingWindow::push(self : RollingWindow, sample : Sample) -> Unit

Adds one sample, evicting the oldest sample after the capacity is reached.

#
RollingWindow::quantile

fn RollingWindow::quantile(self : RollingWindow, permille : Int) -> Double

Returns an exact nearest-rank quantile over the retained values.

permille is clamped to the inclusive range 0..1000, making 500 the median.

#
RollingWindow::reset

fn RollingWindow::reset(self : RollingWindow) -> Unit

#
RollingWindow::samples

fn RollingWindow::samples(self : RollingWindow) -> Array[Sample]

Returns retained samples from oldest to newest.

#
RollingWindow::summary

fn RollingWindow::summary(self : RollingWindow) -> Summary

Computes a numerically stable summary over the current bounded window.

#
Sample

pub(all) struct Sample {
time : Int
value : Double
} derive(
Debug
)

#
Sample::new

fn Sample::new(time : Int, value : Double) -> Sample

#
Series

pub(all) struct Series {
name : String
samples : Array[Sample]
} derive(
Debug
)

#
Series::difference

fn Series::difference(self : Series, name? : String) -> Series

#
Series::exponential_smoothing

fn Series::exponential_smoothing(self : Series, alpha_per_mille : Int, name? : String) -> Series

#
Series::from_csv

fn Series::from_csv(name : String, csv : String, has_header? : Bool) -> Result[Series, CsvError]

Imports a two-column time,value CSV document.

Empty lines are ignored. The first non-empty row is treated as a header when has_header is true, which is the default and matches Series::to_csv.

#
Series::is_empty

fn Series::is_empty(self : Series) -> Bool

#
Series::length

fn Series::length(self : Series) -> Int

#
Series::max_value

fn Series::max_value(self : Series) -> Double

#
Series::mean

fn Series::mean(self : Series) -> Double

#
Series::min_value

fn Series::min_value(self : Series) -> Double

#
Series::moving_average

fn Series::moving_average(self : Series, window : Int, name? : String) -> Series

#
Series::new

fn Series::new(name : String, samples : Array[Sample]) -> Series

#
Series::normalize_minmax

fn Series::normalize_minmax(self : Series, name? : String) -> Series

#
Series::outliers

fn Series::outliers(self : Series, z_threshold : Double) -> Array[Sample]

#
Series::peak_count

fn Series::peak_count(self : Series, threshold : Double) -> Int

#
Series::peaks

fn Series::peaks(self : Series, threshold : Double) -> Array[Sample]

#
Series::range

fn Series::range(self : Series) -> Double

#
Series::rate_of_change

fn Series::rate_of_change(self : Series, name? : String) -> Series

#
Series::sum

fn Series::sum(self : Series) -> Double

#
Series::summary

fn Series::summary(self : Series) -> Summary

#
Series::summary_json

fn Series::summary_json(self : Series) -> String

#
Series::to_csv

fn Series::to_csv(self : Series) -> String

Exports a series as portable UTF-8 CSV with a time,value header.

#
Series::variance

fn Series::variance(self : Series) -> Double

#
Summary

pub(all) struct Summary {
count : Int
min : Double
max : Double
mean : Double
range : Double
variance : Double
std_dev : Double
} derive(
Debug
)

#
Summary::to_json

fn Summary::to_json(self : Summary) -> String

#
TimestampMonitor

pub(all) struct TimestampMonitor {
max_gap : Int
last_time : Int?
} derive(
Debug
)

Detects late samples and excessive timestamp gaps without retaining a stream. The latest in-order timestamp is never moved backwards, making observations deterministic for out-of-order telemetry.

#
TimestampMonitor::new

fn TimestampMonitor::new(max_gap : Int) -> TimestampMonitor

#
TimestampMonitor::observe

#
TimestampMonitor::reset

fn TimestampMonitor::reset(self : TimestampMonitor) -> Unit

#
TimingObservation

pub(all) struct TimingObservation {
previous_time : Int?
time : Int
delta : Int
is_late : Bool
is_gap : Bool
} derive(
Debug
)

Timing quality observed while accepting one telemetry sample.

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io