light_curve_feature/features/
linear_fit.rs

1use crate::evaluator::*;
2use crate::straight_line_fit::fit_straight_line;
3
4macro_const! {
5    const DOC: &str = r"
6Slope, its error and reduced $\chi^2$ of the light curve in the linear fit
7
8Least squares fit of the linear stochastic model with Gaussian noise described by observation
9errors $\{\delta_i\}$:
10$$
11m_i = c + \mathrm{slope} t_i + \delta_i \varepsilon_i
12$$
13where $c$ is a constant,
14$\{\varepsilon_i\}$ are standard distributed random variables.
15
16Feature values are $\mathrm{slope}$, $\sigma_\mathrm{slope}$ and
17$\frac{\sum{((m_i - c - \mathrm{slope} t_i) / \delta_i)^2}}{N - 2}$.
18
19- Depends on: **time**, **magnitude**, **magnitude error**
20- Minimum number of observations: **3**
21- Number of features: **3**
22";
23}
24
25#[doc = DOC!()]
26#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]
27pub struct LinearFit {}
28
29impl LinearFit {
30    pub fn new() -> Self {
31        Self {}
32    }
33
34    pub const fn doc() -> &'static str {
35        DOC
36    }
37}
38
39lazy_info!(
40    LINEAR_FIT_INFO,
41    LinearFit,
42    size: 3,
43    min_ts_length: 3,
44    t_required: true,
45    m_required: true,
46    w_required: true,
47    sorting_required: true,
48);
49
50impl FeatureNamesDescriptionsTrait for LinearFit {
51    fn get_names(&self) -> Vec<&str> {
52        vec![
53            "linear_fit_slope",
54            "linear_fit_slope_sigma",
55            "linear_fit_reduced_chi2",
56        ]
57    }
58
59    fn get_descriptions(&self) -> Vec<&str> {
60        vec![
61            "slope of linear fit",
62            "error of slope of linear fit",
63            "linear fit quality (reduced chi2)",
64        ]
65    }
66}
67
68impl<T> FeatureEvaluator<T> for LinearFit
69where
70    T: Float,
71{
72    fn eval(&self, ts: &mut TimeSeries<T>) -> Result<Vec<T>, EvaluatorError> {
73        self.check_ts_length(ts)?;
74        let result = fit_straight_line(ts, true);
75        Ok(vec![
76            result.slope,
77            T::sqrt(result.slope_sigma2),
78            result.reduced_chi2,
79        ])
80    }
81}
82
83#[cfg(test)]
84#[allow(clippy::unreadable_literal)]
85#[allow(clippy::excessive_precision)]
86mod tests {
87    use super::*;
88    use crate::tests::*;
89
90    check_feature!(LinearFit);
91
92    feature_test!(
93        linear_fit,
94        [LinearFit::default()],
95        [1.0544186045473263, 0.7963978113902943, 0.013781209302325587],
96        [0.0_f32, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
97        [
98            0.0_f32, 0.01, 0.04, 0.09, 0.16, 0.25, 0.36, 0.49, 0.64, 0.81, 1.0
99        ],
100        [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0],
101    );
102}