syncsim

package
v0.0.0-...-f5f1695 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package syncsim provides a discrete-event simulator for testing the phcsync controller.

Architecture

The simulator uses an event-driven architecture built on Go 1.23 iterators:

generatePulseEvents()    ─┐
generateMessageEvents()  ─┼─> mergeEvents() ──> for event := range events
generateTickEvents()     ─┘

Three event streams are generated independently and merged chronologically:

  • Pulse events: GPS PPS edges (rising, and trailing for dual-edge mode)
  • Message events: GPS time messages containing TAI time
  • Tick events: System ticks every 250ms (like real daemon)

Key Design Principles

1. Event generators are declarative - they describe WHAT events happen and WHEN, but NOT which events are delivered. The main loop decides delivery based on outages.

2. Pulse timestamps are ALWAYS read (even during outages) to track PHC drift during signal loss. The decision to deliver to the controller happens separately.

3. Ticks start immediately at t=0.25, modeling real system behavior. Early ticks are safe because the controller returns early when in ModeReset.

4. Mode tracking uses the observer pattern, which sees samples BEFORE mode transitions. This correctly attributes samples to the mode that processed them.

5. Single-edge and dual-edge modes are handled uniformly - the generator produces 1 or 2 pulse events per PPS, and the event loop processes them identically.

Index

Constants

View Source
const (
	NoPulse = gpsprot.NavSolution // use NavSolution value to indicate no sawtooth messages
)

Variables

This section is empty.

Functions

func Generate

func Generate(cfg Config, w io.Writer) error

Generate outputs timestamps as JSON Lines to w. It generates PHC and/or GPS timestamps based on which config sections are non-zero.

func InOutage

func InOutage(outages []OutageConfig, t float64) bool

InOutage returns true if time t falls within any outage period. outages must be pre-normalized (sorted, merged, no zero-duration).

func LoadConfig

func LoadConfig(path string, cfg *Config) error

LoadConfig loads configuration from a TOML file into cfg. The caller initializes cfg (zero-valued or with defaults), and TOML values are merged on top.

func WriteDefaultConfig

func WriteDefaultConfig(w io.Writer) error

WriteDefaultConfig writes the default configuration as TOML to w. The output includes comments derived from struct field comment tags.

Types

type AR1Config

type AR1Config struct {
	// Tau is the correlation time constant in seconds.
	Tau Seconds `toml:"tau" check:">=0,<=1000000" comment:"Correlation time constant (s)"`

	// Sigma is the steady-state RMS in nanoseconds.
	Sigma clocksim.Nanoseconds `toml:"sigma" check:">=0,<=10000" comment:"Steady-state RMS (ns)"`
}

AR1Config configures an AR(1) phase noise process.

func (AR1Config) AlphaNoise

func (c AR1Config) AlphaNoise() (alpha float64, noise clocksim.Nanoseconds)

AlphaNoise returns (alpha, noise_stddev) for use with AR1ColoredNoiseGPS. alpha is the autocorrelation coefficient, noise is the driving noise stddev in nanoseconds. Assumes 1-second sample interval.

func (AR1Config) IsZero

func (c AR1Config) IsZero() bool

type AR1FMConfig

type AR1FMConfig struct {
	// Tau is the correlation time constant in seconds.
	Tau Seconds `toml:"tau" check:">=0,<=1000000" comment:"Correlation time constant (s)"`

	// Sigma is the steady-state RMS of frequency bias in ppb.
	Sigma clocksim.PPB `toml:"sigma" check:">=0,<=10000" comment:"Steady-state RMS of frequency bias (ppb)"`
}

AR1FMConfig configures an AR(1) frequency modulation process.

type Config

type Config struct {
	Sim   SimConfig      `toml:"sim" comment:"Simulation parameters"`
	PHC   PHCConfig      `toml:"phc" comment:"PHC oscillator error model"`
	GPS   GPSConfig      `toml:"gps" comment:"GPS time pulse error model"`
	Sync  phcsync.Config `toml:"sync" comment:"PHC sync controller parameters"`
	Pulse PulseConfig    `toml:"pulse" comment:"Pulse delivery timing"`
	Msg   MsgConfig      `toml:"msg" comment:"GPS message delivery timing"`
	Fault FaultConfig    `toml:"fault" comment:"Fault injection parameters"`
}

Config holds simulation parameters

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with zero noise but sensible operational defaults. PHC and GPS have zero noise parameters (user specifies exactly what noise they want). Pulse and Msg have reasonable timing defaults. Fault has no faults configured.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks that all config fields are within valid ranges. Returns an error if any field fails validation.

type DriftConfig

type DriftConfig struct {
	// Tau is the characteristic timescale in seconds.
	Tau Seconds `toml:"tau" check:">=0,<=1000000" comment:"Characteristic timescale (s)"`

	// Sigma is the RMS phase deviation in nanoseconds.
	Sigma clocksim.Nanoseconds `toml:"sigma" check:">=0,<=10000" comment:"RMS phase deviation (ns)"`

	// Zeta is the damping ratio.
	Zeta float64 `toml:"zeta" check:">=0,<=10" comment:"Damping ratio"`
}

DriftConfig configures bounded drift (Carpenter-Lee 2nd-order Gauss-Markov).

func DefaultDriftConfig

func DefaultDriftConfig() DriftConfig

DefaultDriftConfig returns a DriftConfig with sensible zeta default.

func (DriftConfig) InternalParams

func (c DriftConfig) InternalParams() (omegaN, zeta, sigmaDrift float64)

InternalParams converts user-facing (tau, sigma, zeta) to internal (omega_n, zeta, sigma_drift). Uses discrete Lyapunov calibration so that Sigma matches the actual RMS of the 1 Hz discrete drift simulator output.

type Event

type Event struct {
	Time float64
	Type EventType
	Data any
}

Event represents a simulation event with a time

type EventType

type EventType int
const (
	EventPulse EventType = iota
	EventNavSolutionMsg
	EventTick
	EventPrePulseMsg
	EventPostPulseMsg
)

type ExcursionConfig

type ExcursionConfig struct {
	// StartTime is when the excursion begins in seconds.
	StartTime Seconds `toml:"startTime" check:">=0" comment:"When excursion begins (s)"`

	// Duration is the total excursion duration including ramps in seconds.
	Duration Seconds `toml:"duration" check:">=0" comment:"Total duration including ramps (s)"`

	// Amplitude is the peak phase shift in nanoseconds.
	Amplitude clocksim.Nanoseconds `toml:"amplitude" comment:"Peak phase shift (ns)"`

	// Rise configures the rising edge ramp.
	Rise RampConfig `toml:"rise" comment:"Rising edge ramp"`

	// Fall configures the falling edge ramp.
	Fall RampConfig `toml:"fall" comment:"Falling edge ramp"`
}

ExcursionConfig configures a temporary phase excursion with smooth ramps.

func DefaultExcursionConfig

func DefaultExcursionConfig() ExcursionConfig

DefaultExcursionConfig returns an ExcursionConfig with sensible defaults.

func (ExcursionConfig) IsZero

func (c ExcursionConfig) IsZero() bool

IsZero returns true if the excursion has no effect (zero amplitude).

type FaultConfig

type FaultConfig struct {
	Outage    []OutageConfig    `toml:"outage" comment:"Signal outage periods"`
	Outlier   []OutlierConfig   `toml:"outlier" comment:"Discrete phase outlier injection"`
	Excursion []ExcursionConfig `toml:"excursion" comment:"Temporary phase excursions"`
}

FaultConfig configures fault injection for testing controller resilience.

func DefaultFaultConfig

func DefaultFaultConfig() FaultConfig

DefaultFaultConfig returns a FaultConfig with no faults configured. Includes zero entries so users can see the expected TOML structure.

func (*FaultConfig) NormalizeOutages

func (c *FaultConfig) NormalizeOutages() []OutageConfig

NormalizeOutages returns a sorted, merged list of non-overlapping outages. Zero-duration outages are removed. The result can be used with InOutage().

type FreqSinusoid

type FreqSinusoid struct {
	// Period is the oscillation period in seconds.
	Period Seconds `toml:"period" check:">0,<=1000000" comment:"Oscillation period (s)"`

	// Amp is the frequency amplitude in parts-per-billion.
	Amp clocksim.PPB `toml:"amp" check:">=0,<=10000" comment:"Frequency amplitude (ppb)"`

	// PhaseInit is the initial phase as a fraction of cycle [0,1).
	PhaseInit float64 `toml:"phaseInit" check:">=0,<1" comment:"Initial phase [0,1)"`
}

FreqSinusoid configures a sinusoidal frequency modulation component. Contribution to frequency: Amp * sin(2π * (t/Period + PhaseInit))

func (FreqSinusoid) IsZero

func (s FreqSinusoid) IsZero() bool

type GPSConfig

type GPSConfig struct {
	// Jitter is white phase noise stddev in nanoseconds.
	// Typical: 0.1-5 ns survey-grade, 5-50 ns consumer-grade.
	Jitter clocksim.Nanoseconds `toml:"jitter" check:">=0,<=1000" comment:"White phase noise stddev (ns)"`

	// Sawtooth configures GPS receiver quantization sawtooth error.
	Sawtooth SawtoothConfig `toml:"sawtooth" comment:"GPS receiver quantization sawtooth error"`

	// AR1 is a list of AR(1) colored phase noise processes.
	AR1 []AR1Config `toml:"ar1" comment:"AR(1) colored phase noise processes"`

	// AR1FM is an AR(1) frequency modulation process (sigma in ppb).
	AR1FM AR1FMConfig `toml:"ar1FM" comment:"AR(1) frequency modulation process"`

	// RandomWalk is the random walk FM coefficient in ppb/√s.
	RandomWalk float64 `toml:"randomWalk" check:">=0,<=1000" comment:"Random walk FM coefficient (ppb/√s)"`

	// Drift configures bounded drift (2nd-order Gauss-Markov).
	Drift DriftConfig `toml:"drift" comment:"Bounded drift (2nd-order Gauss-Markov)"`

	// Resonator configures a damped oscillator on phase.
	Resonator ResonatorConfig `toml:"resonator" comment:"Damped oscillator on phase"`

	// Sinusoid is a list of sinusoidal phase modulation components.
	Sinusoid []PhaseSinusoid `toml:"sinusoid" comment:"Sinusoidal phase modulation components"`
}

GPSConfig configures the GPS PPS timing error model. All phase parameters are in nanoseconds.

func DefaultGPSConfig

func DefaultGPSConfig() GPSConfig

DefaultGPSConfig returns a GPSConfig with zero noise but sensible defaults. Users specifying sawtooth.amp will get working InternalClock values automatically. Drift and Resonator have sensible zeta defaults for when user specifies tau/sigma. Includes zero AR1 and Sinusoid entries so users can see the expected structure.

func (GPSConfig) CreateSimulator

func (c GPSConfig) CreateSimulator(startTime toml.LocalTime) clocksim.GPSSimulator

CreateSimulator returns a GPSSimulator combining all GPS error sources. Applies components in order: jitter, AR(1), AR(1) FM, random walk, drift, sinusoids. Does NOT include Shift, Outlier, or Sawtooth - those are added separately in Simulate(). Sawtooth is created separately with oscillator coupling. startTime is the wall-clock time for t=0, used with PeakAt to calculate sinusoid phase.

func (GPSConfig) IsZero

func (c GPSConfig) IsZero() bool

IsZero returns true if all GPS parameters are zero (no PPS error configured).

type MsgConfig

type MsgConfig struct {
	// Delay is the mean delay from the PPS pulse to when the GPS time message
	// is received. Real GPS receivers take 50-250ms to transmit after the pulse.
	Delay Seconds `toml:"delay" check:">=0,<1" comment:"Mean message delay after pulse (s)"`

	// Jitter is the standard deviation of the message arrival time.
	Jitter Seconds `toml:"jitter" check:">=0,<1" comment:"Message delay stddev (s)"`

	// SawtoothType specifies how sawtooth correction messages are delivered:
	//   - SawtoothPrePulse ("prepulse"): Correction arrives before the pulse (UBX-TIM-TP)
	//   - SawtoothPostPulse ("postpulse"): Correction arrives after the pulse (UBX-TIM-TOS)
	//   - SawtoothNone ("none"): No correction messages
	SawtoothType SawtoothType `toml:"sawtoothType" comment:"How sawtooth correction is delivered (prepulse/postpulse/none)"`

	// PrePulseTime is the time before the PPS edge when a PrePulse correction
	// message is delivered. Only used when SawtoothType is SawtoothPrePulse.
	PrePulseTime Seconds `toml:"prePulseTime" check:">=0,<1" comment:"Time before pulse for prepulse message (s)"`

	// PostPulseDelay is the delay after the PPS edge when a PostPulse correction
	// message is delivered. Only used when SawtoothType is SawtoothPostPulse.
	PostPulseDelay Seconds `toml:"postPulseDelay" check:">=0,<1" comment:"Delay after pulse for postpulse message (s)"`
}

MsgConfig configures GPS message delivery timing. GPS receivers send time messages (e.g., UBX-NAV-PVT) after each PPS pulse.

func DefaultMsgConfig

func DefaultMsgConfig() MsgConfig

DefaultMsgConfig returns default message timing parameters.

type NavSolutionMsgEventData struct {
	PPS float64
}

type OutageConfig

type OutageConfig struct {
	// StartTime is when the outage begins in seconds.
	StartTime Seconds `toml:"startTime" check:">=0" comment:"When outage begins (s)"`

	// Duration is the outage duration in seconds.
	Duration Seconds `toml:"duration" check:">=0" comment:"Outage duration (s)"`
}

OutageConfig configures a signal outage period.

type OutlierConfig

type OutlierConfig struct {
	// Time is the simulation time at which to inject an outlier.
	Time Seconds `toml:"time" check:">=0" comment:"When to inject outlier (s)"`

	// Offset is the magnitude of the phase offset to inject in nanoseconds.
	// Typical multipath outliers are 1000-10000 ns (1-10 µs).
	Offset clocksim.Nanoseconds `toml:"offset" comment:"Outlier offset magnitude (ns)"`
}

OutlierConfig configures a discrete phase outlier injection.

func (OutlierConfig) IsZero

func (c OutlierConfig) IsZero() bool

type PHCConfig

type PHCConfig struct {
	// FreqOffset is the constant frequency offset in ppb.
	// Typical values: ±1000-10000 ppb for factory-trimmed oscillators.
	FreqOffset clocksim.PPB `toml:"freqOffset" check:">=-1_000_000,<=1_000_000" comment:"Constant frequency offset (ppb)"`

	// Drift is the linear frequency drift rate in ppb per day.
	Drift float64 `toml:"drift" check:">=-1_000_000,<=1_000_000" comment:"Linear frequency drift (ppb/day)"`

	// WhiteNoise is the standard deviation of white frequency noise in ppb.
	// Typical values are 1-20 ppb for good crystals.
	WhiteNoise clocksim.PPB `toml:"whiteNoise" check:">=0,<=10000" comment:"White frequency noise stddev (ppb)"`

	// FlickerNoise is the standard deviation of flicker (1/f) frequency noise in ppb.
	// Typical values are 0.1-5 ppb for crystals.
	FlickerNoise clocksim.PPB `toml:"flickerNoise" check:">=0,<=10000" comment:"Flicker (1/f) frequency noise stddev (ppb)"`

	// RandomWalk is the random walk FM coefficient in ppb/√s.
	// Typical values are 0.01-1 ppb/√s.
	RandomWalk clocksim.PPB `toml:"randomWalk" check:">=0,<=10000" comment:"Random walk FM coefficient (ppb/√s)"`

	// Sinusoid is a list of sinusoidal frequency modulation components.
	Sinusoid []FreqSinusoid `toml:"sinusoid" comment:"Sinusoidal frequency modulation components"`
}

PHCConfig configures the PTP Hardware Clock oscillator error model. The PHC's instantaneous frequency is modeled as:

nominal_freq * (1 + freq_offset + drift*t + white + flicker + random_walk + sinusoids)

All frequency parameters are in parts-per-billion (ppb) relative to nominal.

func DefaultPHCConfig

func DefaultPHCConfig() PHCConfig

DefaultPHCConfig returns a PHCConfig with zero noise. Includes a zero sinusoid entry so users can see the expected structure.

func (PHCConfig) CreateSimulator

func (c PHCConfig) CreateSimulator() clocksim.OscSimulator

CreateSimulator returns an OscSimulator combining all PHC error sources. Applies components in order: offset, white noise, flicker noise, random walk, drift, sinusoids.

func (PHCConfig) IsZero

func (c PHCConfig) IsZero() bool

IsZero returns true if all PHC parameters are zero (no oscillator error configured).

type PhaseSinusoid

type PhaseSinusoid struct {
	// Period is the oscillation period in seconds.
	Period Seconds `toml:"period" check:">0,<=1000000" comment:"Oscillation period (s)"`

	// Amp is the phase amplitude in nanoseconds.
	Amp clocksim.Nanoseconds `toml:"amp" check:">=0,<=10000" comment:"Phase amplitude (ns)"`

	// PeakAt is the time of day when the sinusoid peaks.
	// Used with SimConfig.StartTime to calculate initial phase.
	// Defaults to 06:00:00, which gives phase 0 when StartTime is 00:00:00.
	PeakAt toml.LocalTime `toml:"peakAt" comment:"Time of day when sinusoid peaks (HH:MM:SS)"`
}

PhaseSinusoid configures a sinusoidal phase modulation component. Contribution to phase: Amp * sin(2π * (t/Period + PhaseInit()))

func (PhaseSinusoid) IsZero

func (s PhaseSinusoid) IsZero() bool

func (PhaseSinusoid) PhaseInit

func (s PhaseSinusoid) PhaseInit(startTimeSec float64) float64

PhaseInit returns the initial phase [0,1) for this sinusoid. Calculates phase so sinusoid peaks at PeakAt given startTimeSec.

type PostPulseMsgEventData

type PostPulseMsgEventData struct {
	PPS float64
}

type PrePulseMsgEventData

type PrePulseMsgEventData struct {
	PPS      float64
	Sawtooth float64
}

type PulseConfig

type PulseConfig struct {
	// MinDelay is the minimum delay from the true GPS second to when the
	// PPS pulse edge is delivered to the PHC timestamper. Real GPS receivers
	// have internal processing delays that prevent the pulse from arriving
	// exactly at the second boundary. The actual delay for each pulse is
	// uniformly distributed between MinDelay and MaxDelay.
	// Typical values are 5-50 microseconds (0.000005 to 0.00005).
	MinDelay Seconds `toml:"minDelay" check:">=0,<1" comment:"Min pulse delay from GPS second (s)"`

	// MaxDelay is the maximum delay from the true GPS second to when the
	// PPS pulse edge is delivered to the PHC timestamper. Must be >= MinDelay.
	MaxDelay Seconds `toml:"maxDelay" check:">=0,<1" comment:"Max pulse delay from GPS second (s)"`

	// Width is the pulse width for dual-edge timestamping mode.
	// When Width > 0, the simulator generates both rising and falling edges.
	// When Width = 0, only rising edges are generated (single-edge mode).
	// Typical GPS receivers use 100ms (0.1) pulse width.
	Width Seconds `toml:"width" check:">=0,<1" comment:"Pulse width (0=single-edge mode)"`
}

PulseConfig configures PPS pulse timing characteristics.

func DefaultPulseConfig

func DefaultPulseConfig() PulseConfig

DefaultPulseConfig returns default pulse timing parameters.

type PulseEventData

type PulseEventData struct {
	EdgeIdx int
	PPS     float64
}

type RampConfig

type RampConfig struct {
	// Duration is the ramp duration in seconds. 0 means instant transition.
	Duration Seconds `toml:"duration" check:">=0" comment:"Ramp duration (s)"`

	// Power controls the ramp shape. nil defaults to 2.0 (smooth S-curve).
	// power > 1 gives smooth acceleration/deceleration at endpoints.
	// power = 1 is linear.
	Power *float64 `toml:"power" check:">0,<=10" comment:"Shape power (>1 for smooth S-curve)"`
}

RampConfig configures a smooth ramp transition.

func (RampConfig) EffectivePower

func (c RampConfig) EffectivePower() float64

EffectivePower returns the power value, defaulting to 2.0 if nil.

type ResonatorConfig

type ResonatorConfig struct {
	// Period is the natural oscillation period in seconds.
	Period Seconds `toml:"period" check:">=0,<=1000000" comment:"Natural oscillation period (s)"`

	// Sigma is the RMS phase deviation in nanoseconds.
	Sigma clocksim.Nanoseconds `toml:"sigma" check:">=0,<=10000" comment:"RMS phase deviation (ns)"`

	// Zeta is the damping ratio.
	Zeta float64 `toml:"zeta" check:">=0,<=10" comment:"Damping ratio"`
}

ResonatorConfig configures a damped harmonic oscillator on phase. Implements a bounded phase process that oscillates around zero.

func DefaultResonatorConfig

func DefaultResonatorConfig() ResonatorConfig

DefaultResonatorConfig returns a ResonatorConfig with sensible zeta default.

func (ResonatorConfig) InternalParams

func (c ResonatorConfig) InternalParams() (omegaN, zeta, sigmaNoise float64)

InternalParams converts user-facing (period, sigma, zeta) to internal (omegaN, zeta, sigmaNoise).

type SawtoothConfig

type SawtoothConfig struct {
	// Amp is the sawtooth amplitude in nanoseconds (≈ 0.5e9/f_osc).
	Amp float64 `toml:"amp" check:">=0,<=1000" comment:"Sawtooth amplitude (ns, ≈ 0.5e9/f_osc)"`

	// PhaseInit is the initial phase [0,1), default 0.5.
	PhaseInit float64 `toml:"phaseInit" check:">=0,<1" comment:"Initial phase [0,1)"`

	// InternalClock models the GPS receiver's internal oscillator error.
	InternalClock FreqSinusoid `toml:"internalClock" comment:"GPS internal oscillator error model"`
}

SawtoothConfig configures GPS receiver quantization sawtooth error.

func DefaultSawtoothConfig

func DefaultSawtoothConfig() SawtoothConfig

DefaultSawtoothConfig returns a SawtoothConfig with zero amplitude but sensible defaults for PhaseInit and InternalClock. Users specifying sawtooth.amp will get working values.

type SawtoothType

type SawtoothType int

SawtoothType specifies how sawtooth correction messages are delivered.

const (
	SawtoothPrePulse  SawtoothType = iota // correction before pulse (UBX-TIM-TP)
	SawtoothPostPulse                     // correction after pulse (UBX-TIM-TOS)
	SawtoothNone                          // no correction messages
)

func (SawtoothType) MarshalText

func (s SawtoothType) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler for TOML serialization.

func (SawtoothType) String

func (s SawtoothType) String() string

func (SawtoothType) TimeRef

func (s SawtoothType) TimeRef() gpsprot.TimeRef

TimeRef converts SawtoothType to gpsprot.TimeRef for use with timemsg.Buffer.

func (*SawtoothType) UnmarshalText

func (s *SawtoothType) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler for TOML deserialization.

type Seconds

type Seconds = float64

Seconds is a true alias for float64, used for documentation in config structs. No conversion needed - clocksim uses float64 for seconds internally.

type SimConfig

type SimConfig struct {
	// Duration is the simulation duration in seconds.
	Duration Seconds `toml:"duration" check:">0" comment:"Simulation duration (s)"`

	// StartTime is the wall-clock time of day for simulation t=0.
	// Used with PhaseSinusoid.PeakAt to calculate initial phase.
	// Defaults to 00:00:00 (midnight).
	StartTime toml.LocalTime `toml:"startTime" comment:"Wall-clock time for t=0 (HH:MM:SS)"`
}

SimConfig configures simulation parameters.

func DefaultSimConfig

func DefaultSimConfig() SimConfig

DefaultSimConfig returns a SimConfig with a reasonable default duration.

type Stats

type Stats struct {
	statsobs.Stats                       // embedded - detailed tracking statistics from observer
	SampleCount     int                  // total samples fed to controller
	TrackingStdDev  float64              // stddev from true time in nanoseconds (simulation-only)
	TrackingMean    float64              // mean offset from true time in nanoseconds (simulation-only)
	TrackingAbsMax  time.Duration        // max absolute offset from true time (simulation-only)
	TrackingADev    float64              // Allan deviation of tracking offsets (simulation-only)
	ModeSamples     map[phcsync.Mode]int // samples per mode (non-zero only)
	ModeTransitions map[phcsync.Mode]int // transitions into each mode (non-zero only)
}

Stats holds simulation results

func Simulate

func Simulate(observers []obs.Observer, cfg Config, tsLog io.Writer, curTime *time.Time, lg *slog.Logger) (Stats, error)

Simulate runs a phcsync simulation with the given configuration. tsLog is an optional writer for PHC timestamp log (JSON Lines format). curTime is updated as the simulation progresses, allowing callers to use it for logging. It returns statistics about the simulation run.

func (Stats) String

func (s Stats) String() string

String formats Stats for human-readable output.

type TickEventData

type TickEventData struct {
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL