-------------------- -------------------- -------------------- -------

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//---------------------------------------------------------------------------
#include "headerstop.h"
#include <vector>
#include "Prognosys.h"
#include "Math\LSAlin.h"
#include "..\..\Container.Source\util\ltrace.h"
static const MachAlrm_Progn_cfg default_MachAlrm_Progn_cfg =
{.25, .8, .08, 3.0, .2, 6};
//! сколько ETCTIME'ов в секунде
static const ETCTIME ETCTIME2SECOND_ratio = 10000000;
//! один день
static const ETCTIME progn_etm_day = ETCTIME2SECOND_ratio*(__int64)3600*(__int64)24;
//! периоды по данным за которые надо строить прогнозы, от меньшего к большему
static const ETCTIME progn_periods[] = { progn_etm_day * 30, progn_etm_day * 122, progn_etm_day * 363};
//! число таких периодов
static const size_t progn_nperiods = sizeof(progn_periods)/sizeof(progn_periods[0]);
//! максимальное по модулю значение прогноза в секундах
//! (для предотвращения переполнения при конвертации double->ETCTIME)
static const double progn_max_prognosis = 3600.*24*365*10;
//! описание прогноза на один период
struct MachAlrm_Progn_single_res
{
bool Talarm_trusted; //! признак того, что прогнозное время попадает в 25% от предыстории
ETCTIME Talrm; //! прогнозное время срабатывания уставки относ. tnow
};
MachAlrm_Progn::MachAlrm_Progn()
: m_cfg(default_MachAlrm_Progn_cfg)
{
}
ETCTIME MachAlrm_Progn::get_history_len(void)
{
return(progn_periods[progn_nperiods - 1]); // самый большой
}
bool LinRegr2SingleRes( const LinRegresMod_res& lres, double guard_val,
double scale, size_t iperiod, double trust_len,
MachAlrm_Progn_single_res& res )
{
switch(lres.state)
{
case LinRegresMod_res::LR_CROSSES:
break;
case LinRegresMod_res::LR_NOCROSS:
res.Talarm_trusted = false;
res.Talrm = -1;
return(true);
default:
return(false);
}
// сейчас уже больше аварийной уставки
if(lres.a0 >= guard_val)
{
res.Talarm_trusted = true;
res.Talrm = 0;
return(true);
}
// снижается, а не возрастает
if(lres.a1 <= 0)
{
res.Talarm_trusted = false;
res.Talrm = -1;
return(true);
}
// уже пересекла
if(lres.cross_at < 0)
{
res.Talarm_trusted = true;
res.Talrm = 0;
return(true);
}
if(fabs(lres.cross_at * scale) > progn_max_prognosis)
{
res.Talarm_trusted = false;
if(lres.cross_at > 0)
res.Talrm = -1;
else
res.Talrm = -progn_max_prognosis*ETCTIME2SECOND_ratio;
}
else
{
res.Talrm = ( lres.cross_at * scale) * ETCTIME2SECOND_ratio;
res.Talarm_trusted = (lres.cross_at <= (progn_periods[iperiod]/ETCTIME2SECOND_ratio/scale)*trust_len);
}
return(true);
}
MachAlrm_Progn_res MachAlrm_Progn::combine(MachAlrm_Progn_single_res prgs[], size_t n, FILE *dbg_out)
{
MachAlrm_Progn_res res = {};
ETCTIME etm_min = -1, etm_min_trusted = -1;
for(size_t i = 0; i < n; i++)
{
if((etm_min == -1) || ((prgs[i].Talrm != -1) && (prgs[i].Talrm < etm_min)))
etm_min = prgs[i].Talrm;
if(prgs[i].Talarm_trusted && ((etm_min_trusted == -1) || ((prgs[i].Talrm != -1) && (prgs[i].Talrm < etm_min_trusted))))
etm_min_trusted = prgs[i].Talrm;
}
res.alrm_near = etm_min;
res.alrm_far = etm_min_trusted;
if((etm_min == -1) || (etm_min != etm_min_trusted))
for(size_t i = progn_nperiods; i > 0;)
{
i--;
if((etm_min == -1) || (((ETCTIME)(progn_periods[i]/ETCTIME2SECOND_ratio*m_cfg.Talrm_trust_interval))*ETCTIME2SECOND_ratio < etm_min))
{
res.alrm_near = ((ETCTIME)(progn_periods[i]/ETCTIME2SECOND_ratio*m_cfg.Talrm_trust_interval))*ETCTIME2SECOND_ratio;
break;
}
}
LTRACE(("combine result: %I64u, %I64u", etm_min, etm_min_trusted));
if(dbg_out)
fprintf(dbg_out, "combine result: %I64u, %I64u\n", etm_min, etm_min_trusted);
return(res);
}
bool MachAlrm_Progn::prognose(ETCTIME tnow, double Va, ETCTIME ts[], double vs[], size_t N, MachAlrm_Progn_res *res, FILE* dbg_out)
{
LTRACE(("MachAlrm_Progn::prognose(., %f, ., ., %u, .)", Va, (unsigned)N));
if(N<3)
{
LTRACE1("no prognosys - too few points");
return(false);
}
//ETCTIME interval = tnow - ts[N-1];
double scale_ds = get_history_len()/(double)ETCTIME2SECOND_ratio; // длина интервала в секундах
if(scale_ds < 1.0)
{
LTRACE1("no prognosys - too short interval");
if(dbg_out)
fprintf(dbg_out, "Prognoser: time interval too short\n");
return(false); // слишком короткий промежуток
}
std::vector<double> tms; // время (-1; 0)
for(size_t i = 0; i < N; ++i)
tms.push_back(-(((tnow - ts[i])/ETCTIME2SECOND_ratio)/scale_ds));
LinRegresMod_cfg LRM_cfg = { m_cfg.min_real_length, m_cfg.max_data_discarded,
m_cfg.max_data_deviation, m_cfg.max_model_deviation,
m_cfg.min_N };
std::vector<MachAlrm_Progn_single_res> prognoses;
size_t i = 1;
for(size_t cperiod = 0; cperiod < progn_nperiods; cperiod++)
{
while((i < N) && (tnow - ts[i]) <= progn_periods[cperiod])
i++;
{
LinRegresMod_res LRM_res;
LTRACE(("Calling LinRegresMod_Calc() on %u points", (unsigned)i));
if(dbg_out)
fprintf(dbg_out, "\nPrognoser: building prognose for %u days\n", (unsigned)(progn_periods[cperiod]/ETCTIME2SECOND_ratio/3600/24));
if(LinRegresMod_Calc(&(tms[0]), vs, i, Va, progn_periods[cperiod]/ETCTIME2SECOND_ratio/scale_ds, LRM_cfg, &LRM_res, dbg_out))
{
LTRACE(("Have prognose: %u, date %f, a1 = %f",
LRM_res.state,
(LRM_res.state == LinRegresMod_res::LR_CROSSES) ? LRM_res.cross_at : -7777.77,
(LRM_res.state == LinRegresMod_res::LR_CROSSES) ? LRM_res.a1 : -7777.77));
if(dbg_out)
fprintf(dbg_out, "Prognoser: have prognose: %u, date %f, a1 = %f\n",
LRM_res.state,
(LRM_res.state == LinRegresMod_res::LR_CROSSES) ? LRM_res.cross_at : -7777.77,
(LRM_res.state == LinRegresMod_res::LR_CROSSES) ? LRM_res.a1 : -7777.77 );
MachAlrm_Progn_single_res res = {};
if(LinRegr2SingleRes(LRM_res, Va, scale_ds, cperiod, m_cfg.Talrm_trust_interval, res))
prognoses.push_back(res);
}
}
}
if(!prognoses.empty())
{
*res = combine(&(prognoses[0]), prognoses.size(), dbg_out);
return(true);
}
else
{
if(dbg_out)
fprintf(dbg_out, "Prognoser: there were no valid prognoses\n");
return(false);
}
};