analytics

package
v0.32.1 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package analytics hosts local, deterministic analyses over the user's driving and charging history. Nothing in this package calls an LLM or leaves the backend — these are pure-Go heuristics used to power UI affordances (Home vs. Public vs. Fast charging badges, anomaly flags, etc.).

Charging-location classification has two axes:

  1. Session peak power. Anything at or above FastMinKW is treated as DC fast charging (EA, Supercharger, RAN L3, etc.) and goes into a single "Fast" bucket regardless of where it happened. The threshold (default 50 kW) is the de-facto line between AC L2 and DCFC — no production L2 charger exceeds ~22 kW.

  2. Location, for everything *below* the Fast threshold. Those sessions are DBSCAN-clustered on (lat, lon); the single largest cluster becomes "Home" (your driveway / apartment L2), and every other slow session — other L1/L2 stops, random friend's-house plug-ins, singleton noise — is "Public".

DBSCAN is chosen over k-means for the location step because:

  • the number of clusters is unknown (we want to discover it);
  • one-off public charging sessions are genuine outliers and shouldn't warp a centroid the way k-means would;
  • ~200m is a natural epsilon for "same parking lot / driveway".

The distance metric is haversine on (lat, lon) so clusters behave the same at any latitude. We keep the implementation small and dependency-free rather than pulling in a geo library.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ChargePoint

type ChargePoint struct {
	ID             string
	Lat, Lon       float64
	EnergyAddedKWh float64
	// MaxPowerKW is the peak kW observed during the session. When >=
	// Params.FastMinKW the charge is bucketed as Fast regardless of
	// location. Zero means unknown — those sessions fall through to
	// location clustering.
	MaxPowerKW float64
}

ChargePoint is the minimal projection of a charge session needed to classify it. Store.Charge is denormalised into this shape at the API boundary so analytics stays decoupled from the SQL schema.

type Cluster

type Cluster struct {
	Label       ClusterLabel
	Centroid    LatLon // mean of member coordinates
	MemberIDs   []string
	Sessions    int
	EnergyKWh   float64
	RadiusMeter float64 // max member distance from centroid
}

Cluster is a group of charges sharing a category. For Home / Public it's a geographic cluster; for Fast it's a power-defined bucket whose "centroid" is the mean of its members' coordinates (useful for a map pin only if the fast stops happen to cluster geographically).

func ClusterCharges

func ClusterCharges(points []ChargePoint, p Params) []Cluster

ClusterCharges classifies charges into Home / Public / Fast / Unknown.

Flow:

  1. Partition inputs into Fast (MaxPowerKW >= FastMinKW), GPS-less (Unknown), and the remaining located-slow pool.
  2. DBSCAN the slow pool with the haversine metric.
  3. Label the largest slow cluster Home; everything else slow — smaller clusters AND noise singletons — is Public.
  4. Emit one aggregate Fast cluster (if any fast sessions exist) and one Unknown cluster (if any no-GPS sessions exist).

Returned slice is ordered largest-first by session count, with Unknown last.

type ClusterLabel

type ClusterLabel string

ClusterLabel is the human-readable category assigned after classification. Three outcomes are possible for GPS-tagged charges: Home (largest location cluster of slow sessions), Public (everything else slow and located), Fast (peak power >= threshold). Charges missing a GPS fix land in LabelUnknown.

const (
	LabelHome    ClusterLabel = "Home"
	LabelPublic  ClusterLabel = "Public"
	LabelFast    ClusterLabel = "Fast"
	LabelUnknown ClusterLabel = "" // used for charges with no GPS fix
)

type LatLon

type LatLon struct {
	Lat, Lon float64
}

LatLon is a simple coordinate pair.

type Params

type Params struct {
	// EpsilonMeters is the neighbourhood radius used by DBSCAN.
	EpsilonMeters float64
	// MinPoints is the minimum cluster size for DBSCAN. Points in a
	// neighbourhood smaller than this are marked as noise and show
	// up as singleton Public clusters.
	MinPoints int
	// FastMinKW is the peak-power threshold at which a session is
	// classified as Fast regardless of location. 50 kW cleanly
	// separates the fastest AC L2 hardware (~22 kW) from DCFC.
	FastMinKW float64
}

Params controls both steps of classification.

func DefaultParams

func DefaultParams() Params

DefaultParams is the tuning the UI uses by default.

Jump to

Keyboard shortcuts

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