私は主張した出版物に困惑しました:バイケルダールであなたのFTPを1分で測定することは可能です。さらにグーグルは、Baronbiosys.comがこれを主張するXert-Appを開発したことを明らかにしました。
この方法では、洗練された手法とパターン認識を使用して、FTPを決定します。過去には、たとえば20分間のFTPプロトコルを使用してテストする必要があるか、何ヶ月ものデータを調べて現実的なFTP値を取得する必要がありますが、この方法では、その日またはその時点でFTPを決定できます。 CF Baronbiosys
Garmin(830)にXertアプリをインストールした後、無料の試用時間が消費されるまで、 FTPの推定値を非常にうまく行うまで経験しました。 Dcrainmakerはそれをレビューし、そのパフォーマンスと正確性について非常に前向きで、結論付けました。
ここでは、非常にユニークなリアルタイムでFTPフィードバックを取得しているという事実です。私は乗車に出かけ、これらの価値が策定しているのを見始めることができます。待ち時間はありません。私はそれを行う他のプラットフォームやアプリを知りません。 cf dcrainmaker
Arduino NRF52840 Expressボードで実行されている屋内トレーニングアプリケーションのC ++コードを開発することにしました。それは、より大きなプロジェクトの不可欠な部分であるAirflowになりました。以下は、その基礎の背後にある科学と数学の説明です。
Xertアプリは、いわゆる嫌気性作業能力( AWC )または機能的予備能力( FRC )の枯渇に基づいていることは明らかでした。シンプルに保つために、サイクリストがこれの与えられた量を持っていると仮定します有限の作業容量(エネルギーリザーブ)は、乗車の開始時に内部に保管されています。この量のエネルギーは、数学的な用語でw ' ( wプライムと発音)として知られており、エネルギーであり、その結果、ジュールで測定されます。あなたが低強度で乗っている間、 w 'は消費されていないため、その完全なレベルにとどまり、あなたは長い間この強度で乗馬を続けることができます。しかし、より強く押すと、このエネルギーの使用を開始します。このエネルギーリザーブの消費を開始する限界は、クリティカルパワー( CP )として知られています。ペダルをCPよりも強く押すと、 W 'は減少します。生成された電力(ワット)がCPよりも低くなるとすぐに、 W 'は「再生」し、エネルギーリザーブは再び増加します。 CP以下で十分に長く乗ると、 W 'は再び100%レベルに近づきます。ただし、 CPを超えて一生懸命働いていると、 W 'は完全に枯渇し、その瞬間に疲れ果てます(別名T lim )! W 'の変動は、Skiba博士アルゴリズム(2)で「 W'バランス」として表されます。アルゴリズムのもう1つのパラメーターは、電源がCPを下回っているときにW 'が再生している速度を定義するTAUです。
CPは、通常45〜60分間、長期間にわたって維持できる最高の運動強度として定義されます。機能的なしきい値( FTP )は、レクリエーションサイクリングでよりよく知られており、60分間維持できる最高の平均出力として定義されています(1)。定義の大きな類似性を考えると、非エリートサイクリングでは、 CP値とFTP値の間に有意差がないことを想定しています!
実装する必要があるアルゴリズムは、Dave Waterworth(3)による積分Skibaアルゴリズムの元のDr. Skibaアルゴリズム(2)と最適化(近似)です。 Aart Goossensは、Arduino設定でさまざまなアルゴリズムを理解して実装するのに大いに役立つGithub(4)のコードと説明情報を公開しました。以下の情報は、彼の元の作品から言い換えられ、読者にアルゴリズムの数学的背景に関する洞察を与えるために、彼の作品を参照してください:aart goosens @ github
積分Skibaアルゴリズムは、W 'バランスを計算するための最もよく知られているアルゴリズムであり、科学的に検証されています(5)。アルゴリズムの方程式は次のとおりです。 
W ' bal(t)は時刻tのw' balに等しく、 w 'はcp (臨界電力)を超える利用可能なエネルギーの量であり(臨界電力)、 w' balが計算される時間、 uは合計の繰り返し、 w ' exp(u) u(u) u(u)u seed cp u (expended)、 e euler number and eauler w' (emonced tau )a reconced a reconsed a cpを超えるエネルギーの量です。数字546、-0.01、および316は、Skibaの元の記事で実験的に決定されており、個人間で変化しません。 D CPは、 CPと電力がCPを下回っている間隔の平均パワーの違いです。 D CP動的に計算(平均時間tまで)またはトレーニング全体で1回計算して静的値として使用できます。 Skibaは、D CPに静的値を使用することをお勧めします。 P(t)は、時間tで生成される電力です。
数学者のデイブ・ウォーターワース(3)は、ゴールデン・チーターのコア開発者であるマーク・リバーエッジが、スキバアルゴリズムの最適化を開発するのを助けました(6)。この再定式化はスキバアルゴリズムに近似しているため、特に(タウ)がサンプル時間と比較して非常に小さい場合、極端な場合にのみ結果が少し変化します。 Skibaの方程式のW ' bal統合部分は、Waterworthによって書き直されています。 
ここで、 S(t)は開始後の時間tでの実行額であり、他の記号は以前の方程式に適合します。タウ( ʈw ' )およびw' exp(t)は、スキバによって提示された元の方程式で計算されます。積分Skibaアルゴリズムは、速いコンピューターであっても、再びTを繰り返す必要があるため、計算するのに非常に高価です。 Waterworthの最適化の大きな利点は、現在、 w 'バランスをリアルタイムで計算できることです。さらに、 w 'バランスが負になり、枯渇したときに、HIITトレーニングや激しいトレーニング中にその場での重要な力を決定したい場合、非常に役立ちます!

数学的には、パワー期間関係は双曲線関数として説明されています。曲線上の4つの異なるポイントは、 CPを超える対応する最大の持続可能な電力に到達し、疲労が発生した場合、時間のポイント( t lim )を表します。運動耐性が考慮されると、電力側面はCP (WATTS)として知られています。曲率定数はw ' (すなわち、 wプライム)として知られており、完了した作業単位で測定されます(ジュール)。 w 'を表す4つのグレーの領域の形が異なるが、サイズはほぼ等しいことに注意してください。行われた作業が時間に対してプロットされている場合、この双曲線のパワー期間関係は、線の勾配がCPに等しくなり、インターセプトがW 'に等しいように、時間に対してプロットされた場合、線形関係に変換できます。電力期間関係は運動耐性を説明しているが、それを説明していないことを強調する必要があります。それにもかかわらず、 CP以下および上記の運動に対する生理学的反応は、疲労プロセスに関する重要な洞察を提供する可能性があります。 CPはもともと、「無期限に」維持される可能性のある外部出力として定義されていました。ただし、この定義は理論的と見なされるべきです。なぜなら、無期限に演習を行うことはできないからです。現在、 CPは、運動耐性が予測可能に制限されている電力出力を分離していることが理解されています(運動電源> CP )。 CPを超えて実行される運動の不耐性( t lim )の実際の時間は定義されているため、方程式によって密接に予測されます。
t lim = w ′/(p-cp)
この方程式は、CPを超える不耐性の時間は、 CPに維持されている電力出力( P )がw 'のサイズに維持される関数であることを強調しています。 PがCPを大幅に上回っている場合、 W 'パラメーターで表される一定の作業量が迅速に利用され、 T LIMが短くなります。 PがCPに近づくと、 w 'はよりゆっくりと使用され、 t limはより長くなります。ここでの重要な考慮事項は、 w 'がCPを超えるすべてのPに対して一定であると想定されることです。したがって、この「 2つのパラメーター」のパラメーターまたは電力期間モデルは、絶対運動のパフォーマンスが単にCPの値(ワット)とw 'の値(ジュール)に依存することを意味します。 CPとW 'パラメーターの両方は、健康/病気、年齢、フィットネス、トレーニングの関数として個人の間でかなり異なる場合があります。
// ------------ W' Balance calculation -------------------
// Global variables related to Cycling Power and W-Prime
uint16_t TAWC_Mode = 1 ; // Track Anaerobic Capacity Depletion Mode == TRUE -> APPLY and SHOW
uint16_t CP60 = 160 ; // Your (estimate of) Critical Power, more or less the same as FTP
uint16_t eCP = CP60; // Algorithmic estimate of Critical Power during intense workout
uint16_t w_prime_usr = 7500 ; // Your (estimate of) W-prime or a base value
uint16_t ew_prime_mod = w_prime_usr; // First order estimate of W-prime modified during intense workout
uint16_t ew_prime_test = w_prime_usr; // 20-min-test algorithmic estimate (20 minute @ 5% above eCP) of W-prime for a given eCP!
long int w_prime_balance = 0 ; // Can be negative !!!
bool IsShowWprimeValuesDominant = false ; // Boolean that determines to show W Prime data on Oled or not
// ------------------------------------------------------- // ------------------------ W'Balance Functions -----------------------------------
uint16_t CalculateAveragePowerBelowCP ( uint16_t iPower, uint16_t iCP);
void CalculateAveragePowerAboveCP ( uint16_t iPower, uint16_t &iavPwr, unsigned long &iCpACp);
double tau_w_prime_balance ( uint16_t iPower, uint16_t iCP);
void w_prime_balance_waterworth ( uint16_t iPower, uint16_t iCP, uint16_t iw_prime);
void ConstrainW_PrimeValue ( uint16_t &iCP, uint16_t &iw_prime);
uint16_t GetCPfromTwoParameterAlgorithm ( uint16_t iav_Power, unsigned long iT_lim, uint16_t iw_prime);
uint16_t GetWPrimefromTwoParameterAlgorithm ( uint16_t iav_Power, double iT_lim, uint16_t iCP);
// ------------------------ W'Balance Functions ------------------------------------ uint16_t CalculateAveragePowerBelowCP ( uint16_t iPower, uint16_t iCP){
// calculate avg_power_below_cp real time using a running sum and counter
static unsigned long int CountPowerBelowCP = 0 ;
static unsigned long int SumPowerBelowCP = 0 ;
if (iPower < iCP) {
SumPowerBelowCP += ( unsigned long int )iPower;
CountPowerBelowCP++;
}
return uint16_t (SumPowerBelowCP/CountPowerBelowCP); // average power below CP
} // end calculate avg_power_below_cp
void CalculateAveragePowerAboveCP ( uint16_t iPower, uint16_t &iavPwr, unsigned long int &iCpACp){
// calculate avg_power_above_cp real time using a running sum and counter
// returning the values by C++ reference!
static unsigned long int SumPowerAboveCP = 0 ;
SumPowerAboveCP += ( unsigned long int )iPower;
iCpACp++;
iavPwr = uint16_t (SumPowerAboveCP/iCpACp); // average power above CP
} // end calculate avg_power_above_cp
double tau_w_prime_balance ( uint16_t iPower, uint16_t iCP){
uint16_t avg_power_below_cp = CalculateAveragePowerBelowCP (iPower, iCP);
double delta_cp = double (iCP - avg_power_below_cp);
return ( double ( 546.00 ) * exp (- 0.01 * delta_cp) + double ( 316.00 ));
} // end Tau W Prime Balance
void w_prime_balance_waterworth ( uint16_t iPower, uint16_t iCP, uint16_t iw_prime) {
// Most power meters measure power, torque a.o. in a high frequency (20-60 Hz) but
// transmit (BLE) datasets to a monitoring device in much lower frequency: 1-4 times per second.
int power_above_cp = 0 ; // Power > CP
static double T_lim = 0 ; // Time (duration) while Power is above CP, the summed value of every sample time value P > CP
double w_prime_expended = 0.0 ; // Expended energy in Joules
double ExpTerm1 = 0.0 , ExpTerm2 = 0.0 ;
static double TimeSpent = 0.0 ; // Total Time spent in the workout, the summed value of every sample time value
static double running_sum = 0.0 ;
static unsigned long int CountPowerAboveCP = 0 ; // Count the Power readings above CP
static uint16_t avPower = 0 ; // Average power above CP
const long int NextLevelStep = 1000 ; // Stepsize of the next level of w-prime modification --> 1000 Joules step
static long int NextUpdateLevel = 0 ; // The next level at which to update eCP, e_w_prime_mod and ew_prime_test
// Quarq Dfour Zero Spider power meter sends between 2 and 1.2 power readings per second, dependent of POWER level !!!
// We assume that the sample frequency (number of samples per second) is VARIABLE !!!
// Determine the individual sample time in seconds, it may/will vary during the workout !!!
static unsigned long PrevReadingTime = 0 ;
double SampleTime = double ( millis ()-PrevReadingTime)/ 1000 ; // Time or duration since the previous sample, convert from millis to seconds
PrevReadingTime = millis (); // Update for the next sample
double tau = tau_w_prime_balance (iPower, iCP); // Determine the value for tau
TimeSpent += SampleTime ; // The summed value of all sample time values during the workout
power_above_cp = (iPower - iCP);
# ifdef DEBUGAIR
Serial. printf ( " Time:%6.1f ST: %4.2f tau: %f " , TimeSpent, SampleTime , tau);
# endif
// w_prime is energy and measured in Joules = Watt*second
// Determine the expended energy above CP since the previous measurement (--> i.e. during sample time)
w_prime_expended = double ( max ( 0 , power_above_cp))*SampleTime; // Determine (Watts_above_CP) * (its duration in seconds) = expended energy in Joules!
// Calculate some terms of the equation
ExpTerm1 = exp (TimeSpent/tau); // Exponential term1
ExpTerm2 = exp (-TimeSpent/tau); // Exponential term2
# ifdef DEBUGAIR
Serial. printf ( " W prime expended: %3.0f exp-term1: %f exp-term2: %f " , w_prime_expended , ExpTerm1, ExpTerm2);
# endif
running_sum = running_sum + (w_prime_expended*ExpTerm1); // Determine the running sum
# ifdef DEBUGAIR
Serial. printf ( " Running Sum: %f " , running_sum);
# endif
w_prime_balance = ( long int )( ( double )iw_prime - (running_sum*ExpTerm2) ) ; // Determine w prime balance and cast from double to int
# ifdef DEBUGAIR
Serial. printf ( " w_prime_balance: %d " , w_prime_balance);
# endif
// --------------- extra --------------------------------------------------------------------------------------
// Workout starts at a certain W'= ##,### Joules and CP = ### watts, set by the user; the algorithm increases CP and W' stepwise
// to more realistic values every time when W'balance is depleted to a certain level; -> 2-Parameter Algorithm updates CP and W'
if (power_above_cp > 0 ) {
CalculateAveragePowerAboveCP (iPower, avPower, CountPowerAboveCP); // Average power above CP is to be calculated for future use
T_lim += SampleTime ; // Time to exhaustion: the accurate sum of every second spent above CP, calculated for future use
}
# ifdef DEBUGAIR
Serial. printf ( " [%d] n " , CountPowerAboveCP);
# endif
// When working above CP, the moment comes that we need to update eCP and ew_prime !!
if ( (w_prime_balance < NextUpdateLevel) && (w_prime_expended > 0 ) ) { // W' balance is further depleted --> test for an update moment
NextUpdateLevel -= NextLevelStep; // Move down another level of depletion, update eCP, ew_prime_mod and ew_prime_test
eCP = GetCPfromTwoParameterAlgorithm (avPower, T_lim, iw_prime); // Estimate a new eCP value
ew_prime_mod = w_prime_usr - NextUpdateLevel; // Adjust ew_prime_modified to the next level of depletion to be checked
ew_prime_test = GetWPrimefromTwoParameterAlgorithm ( uint16_t (eCP* 1.045 ), double ( 1200 ), eCP); // 20-Min-test estimate for W-Prime
# ifdef DEBUGAIR
Serial. printf ( " Update of eCP - ew_prime %5d - avPower: %3d - T-lim:%6.1f --> eCP: %3d " , ew_prime_mod, avPower, T_lim, eCP);
Serial. printf ( " --> Test estimate of W-Prime: %d n " , ew_prime_test );
# endif
}
// -----------------extra -------------------------------------------------------------------------------
} // end
// Check and Set starting value of w_prime to realistic numbers!!
void ConstrainW_PrimeValue ( uint16_t &iCP, uint16_t &iw_prime) {
if (iCP < 100 ) { iCP = 100 ; } // Update to lowest level that we allow for
// First determine the "minimal" value for W_Prime according to a 20-min-test estimate, given the iCP value!
uint16_t w_prime_estimate = GetWPrimefromTwoParameterAlgorithm ( uint16_t (iCP* 1.045 ), double ( 1200 ), iCP);
if (iw_prime < w_prime_estimate) { iw_prime = w_prime_estimate; } // Update iw_prime to a realistic level
return ;
} // end
uint16_t GetCPfromTwoParameterAlgorithm ( uint16_t iav_Power, double iT_lim, uint16_t iw_prime) {
uint16_t WprimeDivTlim = uint16_t ( double (iw_prime)/iT_lim ); // type cast for correct calculations
if (iav_Power > WprimeDivTlim){ // test for out of scope
return (iav_Power - WprimeDivTlim); // Solve 2-parameter algorithm to estimate CP
} else {
return eCP; // Something went wrong do'nt allow an update of CP
}
} // end
uint16_t GetWPrimefromTwoParameterAlgorithm ( uint16_t iav_Power, double iT_lim, uint16_t iCP) {
if (iav_Power > iCP){ // test for out of scope
return (iav_Power-iCP)*(( uint16_t )iT_lim); // Solve 2-parameter algorithm to estimate new W-Prime
} else {
return w_prime_usr; // Something went wrong don't allow an update of w_prime
}
} // end
このコードは、 Airflowと呼ばれるより大きなプロジェクトに統合されています。基礎CPおよびWプライムの設定または変更は、 Airflow Companionアプリの不可欠な部分です!エアフロースマートデバイスは、屋内サイクリングワークアウト、ウォームアップ、強度間隔、断続的な回復、およびクールダウンのすべての段階で、安定した熱バランスのために、冷却ファンの要求されたエアフロー速度を継続的に調整します。サイクリストには、路面上の干渉がなく、ステーショントレーナーのトレーニングの要求に完全に集中することができ、常に適切に冷却する理想的なエアストリームに直面しています。さらに、サイクリストは、トレーニングの強さが激しく、十分に長いときに、彼/彼女の重要な力の発達に関する(ボーナスとして)洞察を得ます!応用されたArduino NRF52480 Express CPUは非常に強力であるため、 CPとW Primeのリアルタイム計算は、熱バランス項を決定し、ファンを適切な吹き込み能力に設定するためのすべての計算を除いて達成できます。
サイクリスト(プロパティ: CP = 140ワットとWプライム= 7.2 kJ )は、図に示すように、期間と強度で激しいトレーニングを行っています。 Wプライムは、最初のインターバルブロックで数回枯渇します。 CPおよびW Primeの新しい値は、必要な場合にのみ、トレーニング時間中にアルゴリズムによって推定されます。ビデオを実行して、W Primeの100%の枯渇と、それらがリアルタイムで計算され、OLED画面で表示された推定値を確認します... 175および195ワットでパワーがCPを超えると、水平バーがどのように収縮するかに注目してください。バーはW 'バランスに比例しており、さらに「タンクに残っている」ものがパーセンテージとして表示されます!測定値は加速されたシーケンスで表示され、トレーニングの指定された期間に適合しません! 