\( \def\bold#1{\bf #1} \newcommand{\d}{\mathrm{d}} \) BTP: Manual and Source Code Documentation

Power Uphill

bike mass [kg]
body mass [kg]
altitude gain [m]
climb length [km]
gradient [%]
time [s]
speed [km/h]
power [W]
power/mass [W/kg]
climbrate [m/min]

average power on climb stage

BTP  3.0
Routing/ClimbAnalysis/PowerCalculation
poweranalysis.cpp
1 #include "poweranalysis.h"
2 #include <QApplication>
3 PowerAnalysis::~PowerAnalysis(){
4  for(int i = 0; i < 9; i++)
5  if(d[i] != NULL)
6  delete d[i];
7 }
8 
9 PowerAnalysis::PowerAnalysis(){
10  for(int i = 0; i < 9; i++)
11  d[i] = NULL;
12 }
13 PowerAnalysis::PowerAnalysis(PowerAnalysisSetting* s){
14  setWindowTitle("Power Analysis");
15  this->s = s;
16  init();
17  ip[0 ] = new Inputs("mass [kg]" ,0 ,200 ,&(s->m));
18  ip[1 ] = new Inputs("cr" ,0 ,1. ,&(s->cr));
19  ip[2 ] = new Inputs("temperatur [°C]" ,-40,50 ,&(s->T));
20  ip[3 ] = new Inputs("air pressure [hPa]" ,900,1100,&(s->p0));
21  ip[4 ] = new Inputs("wind strength [bft]",0 ,12 ,&(s->ws));
22  ip[5 ] = new Inputs("wind direction [°]" ,0 ,360 ,&(s->wd));
23  ip[6 ] = new Inputs("Pmax [W]" ,0 ,500 ,&(s->Pmax));
24  ip[7 ] = new Inputs("Pvd [km/h]" ,0 ,50 ,&(s->Pvd));
25  ip[8 ] = new Inputs("PT [km/h]" ,0 ,10 ,&(s->PT));
26  ip[9 ] = new Inputs("cwAmax" ,0.2,0.7 ,&(s->cwAmax));
27  ip[10] = new Inputs("cwAmin" ,0.0,0.7 ,&(s->cwAmin));
28  ip[11] = new Inputs("cwAvd [km/h]" ,0 ,50 ,&(s->cwAvd));
29  ip[12] = new Inputs("cwAT [km/h]" ,0 ,30 ,&(s->cwAT));
30  ip[13] = new Inputs("a break [m/s²]" ,0 ,10 ,&(s->abrake));
31  ip[14] = new Inputs("a radial [m/s²]" ,0 ,10 ,&(s->aradial));
32 
33  QGridLayout* L = new QGridLayout();
34  L->setContentsMargins(10,0,10,0);
35  L->addWidget(ip[0],0,0);
36  L->addWidget(ip[1],1,0);
37  L->addWidget(ip[2],2,0);
38  L->addWidget(ip[3],3,0);
39  L->addWidget(&Pt,0,1,4,2);
40 
41  fwcb.setText("fight wind");
42  connect(&fwcb,SIGNAL(clicked()),this,SLOT(toggle_fightwind()));
43  L->addWidget(&fwcb,4,0);
44  L->addWidget(ip[4],5,0);
45  L->addWidget(ip[5],6,0);
46  wl = new WindLabel(&(s->ws),&(s->wd));
47  L->addWidget(wl,4,1,3,1);
48  textbox.setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
49  L->addWidget(&textbox,4,2,3,1);
50 
51  L->addWidget(ip[6],7,0);
52  L->addWidget(ip[7],8,0);
53  L->addWidget(ip[8],9,0);
54  Pvl.setText("Power setting");
55  Pvl.show();
56  L->addWidget(&Pvl,10,0);
57  L->addWidget(&Pv,7,1,4,2);
58 
59  L->addWidget(ip[9 ],11,0);
60  L->addWidget(ip[10],12,0);
61  L->addWidget(ip[11],13,0);
62  L->addWidget(ip[12],14,0);
63  cwAvl.setText("cwA setting");
64  L->addWidget(&cwAvl,15,0);
65  L->addWidget(&cwAv,11,1,5,2);
66 
67  L->addWidget(ip[13],16,0);
68  L->addWidget(ip[14],17,0);
69  bdefault.setText("Default");
70  brecalc.setText("Recalc");
71  btoggletimestamp.setText("Ignore/Subordinate time stamp");
72  L->addWidget(&bdefault,18,0);
73  L->addWidget(&brecalc,18,1);
74  L->addWidget(&btoggletimestamp,18,2);
75  setLayout(L);
76  connect(&bdefault,SIGNAL(clicked()),this,SLOT(set_default_refresh()));
77  connect(&brecalc,SIGNAL(clicked()),this,SLOT(recalc()));
78  connect(&btoggletimestamp,SIGNAL(clicked()),this,SLOT(toggle_timestamp()));
79  connect(ip[6],SIGNAL(changed()),this,SLOT(draw_Pv()));
80  connect(ip[7],SIGNAL(changed()),this,SLOT(draw_Pv()));
81  connect(ip[8],SIGNAL(changed()),this,SLOT(draw_Pv()));
82  connect(&Pv,SIGNAL(mousex(double)),this,SLOT(update_Pvl(double)));
83  connect(&cwAv,SIGNAL(mousex(double)),this,SLOT(update_cwAl(double)));
84  connect(ip[9 ],SIGNAL(changed()),this,SLOT(draw_cwAv()));
85  connect(ip[10],SIGNAL(changed()),this,SLOT(draw_cwAv()));
86  connect(ip[11],SIGNAL(changed()),this,SLOT(draw_cwAv()));
87  connect(ip[12],SIGNAL(changed()),this,SLOT(draw_cwAv()));
88  connect(ip[4],SIGNAL(changed()),wl,SLOT(refresh()));
89  connect(ip[5],SIGNAL(changed()),wl,SLOT(refresh()));
90  connect(ip[4],SIGNAL(changed()),this,SLOT(bft_to_mpros()));
91  connect(wl,SIGNAL(clicked()),ip[4],SLOT(refresh()));
92  connect(wl,SIGNAL(clicked()),ip[5],SLOT(refresh()));
93  connect(wl,SIGNAL(clicked()),this,SLOT(bft_to_mpros()));
94  for(int i = 0; i < 15; i++)
95  connect(ip[i],SIGNAL(changed()),this,SLOT(show_slopespeed_table()));
96 
97  setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
98  BTP3setups(&pfs).init();
99  pfs.singlecolor = true;
100  pfs.fillcolor = QColor(255,0,0,140).rgba();
101  pfs.showreduceddata = false;
102  Pv.settings(&pfs);
103  Pt.settings(&pfs);
104  cwAv.settings(&pfs);
105  draw_Pv();
106  draw_cwAv();
107 }
108 void PowerAnalysis::init(){
109  bft_to_mpros();
110  plotdata[0] = new double[100];
111  plotdata[1] = new double[100];
112  for(int i = 0; i < 100; i++)
113  plotdata[0][i] = 60./100.*i;
114  count = 0;
115  for(int i = 0; i < 9; i++)
116  d[i] = NULL;
117 }
119  PA->abrake = 2;
120  PA->aradial = 5;
121  PA->cr = 0.006;
122  PA->cwAmax = 0.45;
123  PA->cwAmin = 0.25;
124  PA->cwAT = 10;
125  PA->cwAvd = 23/3.6;
126  PA->fightwind= 0;
127  PA->m = 85;
128  PA->p0 = 1013.25;
129  PA->Pmax = 320;
130  PA->PT = 1.94;
131  PA->Pvd = 30.0;
132  PA->T = 20;
133  PA->wd = 15;
134  PA->ws = 3;
135 }
136 Inputs::Inputs(QString labeltext,double min, double max, double* v){
137  this->v = v;
138  slider = new QSlider(Qt::Horizontal);
139  label = new QLabel(labeltext);
140  edit = new QLineEdit(QString("%1").arg(*v));
141  smin = min;
142  smax = max;
143  slider->setMinimum(0);
144  slider->setMaximum(1000);
145  if(*v >= min && *v <= max){
146  slider->setValue((*v-min)/(max-min));
147  }
148  slider->setValue(500);
149  QBoxLayout* L = new QBoxLayout(QBoxLayout::LeftToRight);
150  L->setContentsMargins(0,0,0,0);
151  L->addWidget(label,2);
152  L->addWidget(slider,2);
153  L->addWidget(edit,1);
154  setLayout(L);
155  connect(slider,SIGNAL(sliderReleased()),this,SLOT(slidertoedit()));
156  connect(edit,SIGNAL(textEdited(QString)),this,SLOT(checkedit(QString)));
157  connect(slider,SIGNAL(valueChanged(int)),this,SLOT(sliderpreview(int)));
158  connect(slider,SIGNAL(actionTriggered(int)),this,SLOT(slidertoedit()));
159  }
161  edit->setText(QString("%1").arg(smin+1.*slider->value()/1000.*(smax-smin)));
162  *v = edit->text().toDouble();
163  emit changed();
164 }
166  edit->setText(QString("%1").arg(smin+1.*i/1000.*(smax-smin)));
167 }
168 void Inputs::checkedit(QString newedit){
169  bool OK;
170  double buf = newedit.toDouble(&OK);
171  if(OK && buf > 0){
172  *v = buf;
173  emit changed();
174  }
175  else
176  edit->setText("type number > 0");
177 }
179  edit->setText(QString("%1").arg(*v));
180 }
181 WindLabel::WindLabel(double *ws, double *wd){
182  setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum);
183  this->wd = wd;
184  this->ws = ws;
185 }
186 void WindLabel::set_para(double *ws, double *wd){
187  this->wd = wd;
188  this->ws = ws;
189  update();
190 }
191 void WindLabel::paintEvent(QPaintEvent *){
192  QPainter p(this);
193  p.drawPixmap(0,0,pm);
194 }
195 void WindLabel::resizeEvent(QResizeEvent *){
196  refresh_pixmap();
197 }
198 void WindLabel::mouseReleaseEvent(QMouseEvent *event){
199  float r = qMin(width(),height())/2.-2;
200  QPointF mouse = event->pos();
201  QPointF center(width()/2,height()/2);
202  QPointF d = mouse-center;
203  *ws = sqrt(d.x()*d.x()+d.y()*d.y())/r*6;
204  if(*ws > 0)
205  *wd = atan2(d.x(),-d.y())/3.1415*180;
206  else
207  *wd = 0;
208  if(*wd < 0) *wd += 360;
209  emit clicked();
210  refresh();
211 }
212 void WindLabel::refresh(){
213  refresh_pixmap();
214  update();
215 }
216 void WindLabel::refresh_pixmap(){
217  pm = QPixmap(size());
218  pm.fill(QPalette().color(QPalette::Window));
219  QPainter p(&pm);
220  p.setRenderHint(QPainter::Antialiasing);
221  p.setPen(QPen(Qt::black,2));
222  float r = qMin(width(),height())/2.-2;
223  QPointF center(width()/2,height()/2);
224  p.drawEllipse(center,r,r);
225  p.drawEllipse(center,r/2,r/2);
226  p.drawEllipse(center,r/4,r/4);
227  QPointF tri[3];
228  float l = *ws/6.*r;
229  tri[0] = center + QPointF(l/1.*sin(*wd/180*3.1415),
230  -l/1.*cos(*wd/180*3.1415));
231  tri[1] = center + QPointF(l/3.*sin((*wd+150)/180*3.1415),
232  -l/3.*cos((*wd+150)/180*3.1415));
233  tri[2] = center + QPointF(l/3.*sin((*wd+210)/180*3.1415),
234  -l/3.*cos((*wd+210)/180*3.1415));
235  p.setBrush(QBrush(Qt::red));
236  p.drawPolygon(tri,3);
237 }
239  for(int i = 0; i < 100;i++){
240  plotdata[0][i] = 1*i/1.5;
241  plotdata[1][i] = P(plotdata[0][i]/3.6);
242  }
243  Pv.set_data(plotdata,100);
244 }
246  for(int i = 0; i < 100;i++){
247  plotdata[0][i] = 1*i/1.5;
248  plotdata[1][i] = cwA(plotdata[0][i]/3.6);
249  }
250  cwAv.set_data(plotdata,100);
251 }
253  set_default(s);
254  for(int i = 0; i < 15; i++)
255  ip[i]->refresh();
256  draw_Pv();
257  draw_cwAv();
258  wl->refresh();
259 }
261  Pvl.setText(QString("%1 km/h: P=%2 W").arg(v,0,'f',1)
262  .arg(P(v),0,'f',1));
263 }
265  cwAvl.setText(QString("%1 km/h: cwA=%2").arg(v,0,'f',1)
266  .arg(cwA(v),0,'f',3));
267 }
268 void PowerAnalysis::show_slopespeed_table(){
269  QString t;
270  for(double s = 0; s < 0.16; s += 0.01)
271  t.append(QString("%1 % %2 km/h %3 % %4 km/h\n")
272  .arg(s*100.,2,'f',0)
273  .arg(vmax( s,0)*3.6,5,'f',1)
274  .arg(s*-100.,3,'f',0)
275  .arg(vmax(-s,0)*3.6,5,'f',1));
276  textbox.setPlainText(t);
277 }
278 double PowerAnalysis::vmax(double slope, double direction){
279  double rho0 = rho(0);
280  double vl = 0, vm = 10, vr = 50;
281  double Pl = P(vl,slope,direction,rho0)-P(vl);
282  double Pm = P(vm,slope,direction,rho0)-P(vm);
283  double Pr = P(vr,slope,direction,rho0)-P(vr);
284  while(Pr <= 0){
285  vr = vr * 1.5;
286  Pr = P(vr,slope,direction,rho0)-P(vr);
287  }
288 
289  while(Pm < -0.3 || Pm > 0.3){
290  if(Pm > 0){
291  /*velocity has to be reduced*/
292  vr = vm;
293  Pr = Pm;
294  }
295  else{
296  /*velocity can be increased*/
297  vl = vm;
298  Pl = Pm;
299  }
300  vm = (-Pl*vr+Pr*vl)/(Pr-Pl);
301  Pm = P(vm,slope,direction,rho0)-P(vm);
302  }
303  return vm;
304 }
305 
306 inline double PowerAnalysis::rho(double h){
307  return 1./(273.15+T(h))*(s->p0*100*exp(-1.2931*9.81/101325*h))/287.058;
308 }
309 
310 inline double PowerAnalysis::T(double h){
311  return s->T + 0.75*(h/100.);
312 }
313 inline double PowerAnalysis::P(double v){
314  return fermi(v*3.6,s->Pmax,s->PT,s->Pvd);
315 }
316 double PowerAnalysis::veff(double v, double direction){
317  return v-vwind*cos(direction-s->wd/180*3.1415);
318 }
319 
320 inline double PowerAnalysis::P(double v,double slope, double direction,
321  double rho0){
322  double veff0 = veff(v,direction);
323  return cwA(veff0)*rho0*0.5*veff0*veff0*veff0
324  +((s->cr+slope*sqrt(1./(slope*slope+1)))*s->m*9.81)*v;
325 }
326 inline double PowerAnalysis::cwA(double v){
327  return s->cwAmin+fermi(v*3.6,s->cwAmax-s->cwAmin,s->cwAT,s->cwAvd);
328 }
330  vwind = 0.836*pow(s->ws,1.5)*0.72*0.5;
331  return vwind;
332 }
334  track_to_data(t);
335  timeexisting = false;
336  calc_power();
337 }
339  /* extract primary data*/
340  double s = t->get_length()*1000.;
341  count = ceil(s/5)+1;
342  ds = s/(count-1);
343  if(count > 0){
344  for(int i = 0; i < 9; i++){
345  if(d[i] != NULL)
346  delete d[i];
347  d[i] = new double[count];
348  }
349  }
350  for(int i = 0; i < count; i++){
351  d[0][i] = s*i/count;
352  t->extract_h(d[0][i]/1000.,&(d[1][i]));
353  t->extract_azimtut(d[0][i]/1000.,&(d[2][i]));
354  }
355  /* calc mean azimutal change data*/
356  for(int i = 2; i < count-2; i++){
357  double d1 = +d[2][i+2]-d[2][i-2];
358  double d2 = +d[2][i+1]-d[2][i-1];
359  if(d1 > M_PI) d1 -= 2*M_PI;
360  if(d1 <-M_PI) d1 += 2*M_PI;
361  if(d2 > M_PI) d2 -= 2*M_PI;
362  if(d2 <-M_PI) d2 += 2*M_PI;
363  d[3][i] =d1/4+d2/8;
364  }
365  if(count > 2){
366  d[3][1] = -d[3][0]/2.+d[3][2]/2.;
367  d[3][count-2] = -d[3][count-3]/2.+d[3][count-1]/2.;
368  }
369  if(count > 1){
370  d[3][0] = -d[3][0]+d[3][1];
371  d[3][count-1] = -d[3][count-2]+d[3][count-1];
372  }
373  /*calc bend radius frommean azimutal change*/
374  for(int i = 0; i < count; i++){
375  //d[2][i] = d[3][i]/M_PI*180;
376  if(qAbs(d[3][i])<1e-10)
377  d[3][i] = 1e100;
378  else
379  d[3][i] = qAbs(ds / 2. / sin(0.5*d[3][i]));
380  }
381 }
383  /*calc vmax*/
384  d[4][count-1] = sqrt(d[3][count-1]*s->aradial);
385  for(int i = count-2; i >= 0; i--)
386  d[4][i] = qMin(sqrt(d[4][i+1]*d[4][i+1] + 2*ds*s->abrake),
387  sqrt(d[3][i]*s->aradial));
388  /*calc v,P*/
389  d[5][0] = 1;
390  d[6][0] = 0;
391  d[7][0] = 0;
392  d[8][0] = 0;
393  double slope,rho0,st,E,v = 1,a,Pnom,Pis,dtt,dt,vnew;
394  Ebrake = Eout = 0;
395  double dE;
396  if(timeexisting){
397  for(int i = 0; i < count-1;i++){
398  slope = (d[1][i+1]-d[1][i])/ds;
399  rho0 = rho(d[1][i]);
400  vnew = (d[0][qMin(i+10,count-1)]-d[0][qMax(i-10,0)])
401  /(d[6][qMin(i+10,count-1)]-d[6][qMax(i-10,0)]);
402  Pis = P(vnew,slope,d[2][i],rho0);
403  a = (vnew-v)/(d[6][i+1]-d[6][i]);
404  Pnom = a*v*s->m + Pis;
405  v = vnew;
406  if(Pnom > 0)
407  dE = Pnom*(d[6][i+1]-d[6][i]);
408  else{
409  dE = 0;
410  Ebrake += Pnom*(d[6][i+1]-d[6][i]);
411  Pnom = 0;
412  }
413  Eout += dE;
414  d[5][i+1] = vnew;
415  d[7][i+1] = Pnom;
416  d[8][i+1] = d[8][i]+dE;
417  }
418  /* create power mean value*/
419  for(int i = 1; i < count-1;i++)
420  d[7][i] = (d[8][qMin(i+20,count-1)]-d[8][qMax(i-20,0)])
421  /(d[6][qMin(i+20,count-1)]-d[6][qMax(i-20,0)]);
422  }
423  else{
424  for(int i = 0; i < count-1;i++){
425  slope = (d[1][i+1]-d[1][i])/ds;
426  rho0 = rho(d[1][i]);
427  st = E = dE = dt = 0;
428  v = d[5][i];
429  if(s->fightwind) Pnom = P(veff(v,d[2][i]+M_PI));
430  else Pnom = P(v);
431  Pis = P(v,slope,d[2][i],rho0);
432  a = (Pnom-Pis)/s->m/v;
433  while(st + v + a/2. < ds){
434  st += v + a/2.;
435  v += a;
436  dE += Pnom;
437  dt++;
438  if(s->fightwind) Pnom = P(veff(v,d[2][i]));
439  else Pnom = P(v);
440  Pis = P(v,slope,d[2][i],rho0);
441  a = (Pnom-Pis)/s->m/v;
442  if(v+a < 0.1){
443  /* calculation should not crack due to lecking Pnom*/
444  a = v - 0.1;
445  Pnom = a*v*s->m + Pis;
446  }
447  }
448  dtt = (-v+sqrt(2*(ds-st)*a+v*v))/a;
449  dt += dtt;
450  v += a*dtt;
451  dE += Pnom*dtt;
452  if(v < d[4][i+1]){
453  /*v is not limited by bend vmax*/
454  Eout += dE;
455  d[5][i+1] = v;
456  d[6][i+1] = d[6][i]+dt;
457  d[7][i+1] = dE/dt;
458  d[8][i+1] = d[8][i]+dE;
459  }
460  else{
461  /*v is limited by bend vmax*/
462  dt = 2*ds/(d[4][i+1]+d[5][i]);
463  a = (d[4][i+1]-d[5][i])/dt;
464  v = d[5][i];
465  dE = 0;
466  double jmax = ceil(dt);
467  for(double j = 0; j < jmax; j++){
468  v = d[5][i] + (j+0.5)/jmax*(d[4][i+1]-d[5][i]);
469  Pis = P(v,slope,d[2][i],rho0);
470  Pnom = a*v*s->m + Pis;
471  if(Pnom > 0){
472  dE += Pnom *dt/jmax;
473  }
474  else
475  Ebrake += Pnom *dt/jmax;
476  }
477  Eout += dE;
478  d[5][i+1] = d[4][i+1];
479  d[6][i+1] = d[6][i]+dt;
480  d[7][i+1] = dE/dt;
481  d[8][i+1] = d[8][i]+dE;
482  }
483  }
484  }
485  //calculation is done, statistics
486  double maxP = 0;
487  for(int i = 0; i < count;i++)
488  if(d[7][i] > maxP)
489  maxP = d[7][i];
490  for(int i = 0; i < 100;i++){
491  plotdata[0][i] = maxP*i/100;
492  plotdata[1][i] = 0;
493  }
494  int index;
495  for(int i = 1; i < count;i++){
496  index = qMax(0,qMin(int(floor(d[7][i]/maxP*100)),99));
497  plotdata[1][index] += d[6][i]-d[6][i-1];
498  }
499  //QString er;
500  //for(int i = 0; i < 100; i++)
501  // er.append(QString("%1\t%2\n").arg(plotdata[1][i]).arg(plotdata[0][i]));
502  //QApplication::clipboard()->setText(er);
503  Pt.set_data(plotdata,100);
504  double Eflat = P(d[0][count-1]/d[6][count-1],0,s->wd+90,rho(0))
505  *d[6][count-1];
506  textbox.setPlainText(QString("<v> = %1\n<P> = %2 W\n%3% Eflat\n%4% Ebrake\n%5% Eclimb+wind")
507  .arg(d[0][count-1]/d[6][count-1]*3.6)
508  .arg(Eout/d[6][count-1])
509  .arg(Eflat/Eout*100,100,'f',0)
510  .arg(-Ebrake/Eout*100,100,'f',0)
511  .arg((Eout+Ebrake-Eflat)/Eout*100,100,'f',0));
512 }
513 void PowerAnalysis::calc_track(Track* t,double* timed,
514  double* time, int count){
515  track_to_data(t);
516  timeexisting = true;
517  double t0 = time[0];
518  int r=1;
519  for(int i = 0;i < this->count; i++){
520  while(d[0][i] > timed[r]*1000 && r < count)
521  r++;
522  if(d[0][i] <= timed[r]*1000 && timed[r] > timed[r-1]){
523  d[6][i] =( (d[0][i] -timed[r-1]*1000)*time[r]
524  +(timed[r]*1000- d[0][i])*time[r-1])
525  /(timed[r]*1000-timed[r-1]*1000)-t0;
526  if(i > 0 && d[6][i] == d[6][i-1])
527  timeexisting = false;
528  }
529  else
530  d[6][i] = d[6][qMax(0,i-1)]+1;
531  }
532  if(d[6])
533  calc_power();
534 }
536  if(count>0)
537  return d[0][count-1]/d[6][count-1]*3.6;
538  else
539  return 0.;
540 }
541 
543  if(count>0)
544  return Eout/d[6][count-1];
545  else
546  return 0.;
547 }
548 
549 double PowerAnalysis::get_t(double d){
550  int index = int(ceil(count*d*1000/this->d[0][count-1]));
551  if(index<count && index>=0)
552  return this->d[6][index];
553  else
554  return 0;
555 
556 }
557 
558 double PowerAnalysis::get_v(double d){
559  int index = int(ceil(count*d*1000/this->d[0][count-1]));
560  if(index<count && index>=0)
561  return this->d[5][index]*3.6;
562  else
563  return 0;
564 }
565 
566 double PowerAnalysis::get_P(double d){
567  int index = int(ceil(count*d*1000/this->d[0][count-1]));
568  if(index<count && index>=0)
569  return this->d[7][index];
570  else
571  return 0;
572 
573 }
574 double PowerAnalysis::get_v(double dmin, double dmax){
575  int index1 = int(ceil(count*dmin*1000/d[0][count-1]));
576  int index2 = int(ceil(count*dmax*1000/d[0][count-1]));
577  if(index1<count && index1>=0 && index2<count && index2>=0
578  && d[6][index2]>d[6][index1])
579  return (d[0][index2]-d[0][index1])
580  /(d[6][index2]-d[6][index1])*3.6;
581  else
582  return 0;
583 }
584 
585 double PowerAnalysis::get_P(double dmin, double dmax){
586  int index1 = int(ceil(count*dmin*1000/d[0][count-1]));
587  int index2 = int(ceil(count*dmax*1000/d[0][count-1]));
588  if(index1<count && index1>=0 && index2<count && index2>=0
589  && d[6][index2]>d[6][index1])
590  return (d[8][index2]-d[8][index1])
591  /(d[6][index2]-d[6][index1]);
592  else
593  return 0;
594 }
595 
597  if(count>0)
598  return 1;
599  else
600  return 0;
601 }
603  if(count > 0){
604  Pdata[0] = d[0];
605  Pdata[1] = d[7];
606  return Pdata;
607  }
608  else
609  return NULL;
610 }
611 
613  if(count > 0){
614  vdata[0] = d[0];
615  vdata[1] = d[5];
616  return vdata;
617  }
618  else
619  return NULL;
620 
621 }
622 
624  return count;
625 }
627  calc_power();
628  emit recalced();
629 }
631  if(fwcb.isChecked())
632  s->fightwind = 1;
633  else
634  s->fightwind = 0;
635 }
637  if(timeexisting){
638  textbox.setPlainText("Calculation will be based on user defined, velocity dependend power output.");
639  timeexisting = false;
640  }
641  else{
642  // check if a good time stamp exist
643  bool timeOK = true;
644  for(int i = 0; i < count; i++)
645  if(d[6][i] == d[6][i-1])
646  timeOK = false;
647  if(timeOK){
648  textbox.setPlainText("Calculation will be based on current time/velocity stamps.");
649  timeexisting = true;
650  }
651  else
652  textbox.setPlainText("Time/velocity stamps are not valid, stamps will be ignored.");
653  }
654 }
double get_P()
return average power
bool showreduceddata
average data over multiple screen pixels to sensfully show fill color
Definition: DataTyps.h:211
void track_to_data(Track *t)
extracs calculation data
double ** get_vdata()
returns data array pointer
double ** get_Pdata()
returns data array pointer
provide all user settings
Definition: btp3setups.h:70
void slidertoedit()
apply slider value to edit and v
double vwind
wind velocity
double T
Temperature at sea level [°C].
Definition: DataTyps.h:10
double * plotdata[2]
container to collect plotting data
plot2D Pv
user defined power output
double rho(double h)
physics: air pressure dependend from height (barometric formula)
void update_cwAl(double v)
update info label
int get_datacount()
returns data array length
void checkedit(QString newedit)
check if user input is a float
double abrake
maximum brake accelartion [m/s²]
Definition: DataTyps.h:16
double cwA(double v)
velocity depend cwA value, parametrised with fermi function
void update_Pvl(double v)
update info label
void set_default_refresh()
reset PowerAnalysisSetting s
setting for poweranalysis
Definition: DataTyps.h:6
double * v
define data range
Definition: poweranalysis.h:34
short extract_h(double d, double *h)
creates double for height refering distance point d
Definition: track.cpp:379
plot2D cwAv
user defined cwA value
double get_v()
return average velocity
void recalced()
informs about finished calculation
void sliderpreview(int i)
set edit text from slider value
combined input widget to serve text edit and slider at once
Definition: poweranalysis.h:18
void draw_Pv()
draw P(v) distriubtion
double vmax(double slope, double direction)
physics: calculate the resulting velocity from P(v) at specific slope
define wind strength and direction by clicking a wind rose picture
Definition: poweranalysis.h:39
official representation of Track in BTP3
Definition: track.h:14
double aradial
maximum radial accelaration [m/s²]
Definition: DataTyps.h:17
double get_length()
returns Track length [km]
Definition: track.cpp:320
double bft_to_mpros()
wind speed in m/s from beaufort
double * d[9]
double T(double h)
physics: temperature from height with 0.7 K/100m temperature decrease
void set_default(PowerAnalysisSetting *s)
apply default setting to the PowerAnalysisSetting s
void toggle_timestamp()
makes poweranalysis ignoring or subordinate time stamp
void refresh()
set edit text to v-value
double P(double v)
velocity depend output power, parametrised with fermi function
QLabel cwAvl
plot2d info area
WindLabel * wl
wind visualization
QCheckBox fwcb
fight wind checkbox
Inputs * ip[15]
user interface
double cwAT
Fermi CwA function parameter[,,km/h,].
Definition: DataTyps.h:13
Inputs(QString labeltext, double min, double max, double *v)
create widget with data range [min,max] and data reference v
void calc_power()
execute the calculation
double get_t(double d)
interpolate time in data
double cr
rolling resistance
Definition: DataTyps.h:9
void set_data(double **dataxy, int count)
setting one dataset and repaint plot
Definition: plot2D.cpp:475
void draw_cwAv()
draw cwA(v) distriubtion
bool timeexisting
is time data existing?
int count
data array length
double PT
Fermi Power function parameter [km/h,W,km/h].
Definition: DataTyps.h:12
double m
system weigth [kg]
Definition: DataTyps.h:8
double wd
Wind strenght ws [bft] and direction wd [°].
Definition: DataTyps.h:7
int isready()
returns whether data is loaded
PowerAnalysisSetting * s
assigned settings to be used
void calc_track(Track *t)
calc power from P(v) distribution
void settings(ProfilSettings *s)
asign settings to plot
Definition: plot2D.cpp:582
void toggle_fightwind()
switch wind handling in fightwind of PowerAnalysisSetting
double veff(double v, double direction)
physics: total air speed from movement speed v and wind
short extract_azimtut(double d, double *azimut)
extract way direction at distance point d
Definition: track.cpp:400
plot2D Pt
calculated power-time distriubtion
double p0
air pressure at sea level [hPa]
Definition: DataTyps.h:11