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:
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.
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:
- Partition inputs into Fast (MaxPowerKW >= FastMinKW), GPS-less (Unknown), and the remaining located-slow pool.
- DBSCAN the slow pool with the haversine metric.
- Label the largest slow cluster Home; everything else slow — smaller clusters AND noise singletons — is Public.
- 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 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.