Bikeradar에서 1 분 안에 FTP를 측정 할 수 있습니다. 추가 인터넷 검색은 Baronbiosys.com이이를 주장하는 Xert-App을 개발했다고 밝혔다.
이 방법은 정교한 기술과 패턴 인식을 사용하여 FTP를 결정합니다. 과거에는 예를 들어 20 분 FTP 프로토콜을 사용하여 테스트하거나 현실적인 FTP 값을 얻기 위해 몇 개월 분량의 데이터를 검사해야했지만이 방법을 사용하면 그 날이나 그 순간에도 FTP를 결정할 수 있습니다. CF Baronbiosys
Garmin (830)에 Xert 앱을 설치 한 후, 나는 무료 시험 시간이 소비 될 때까지 FTP 의 추정치를 매우 잘 수행 한 경험을 쌓았습니다. Dcrainmaker는이를 검토했으며 성능과 정확성에 대해 상당히 긍정적이며 다음과 같습니다.
여기서는 FTP 피드백을 실시간으로 받고 있다는 사실입니다. 나는 타기 위해 나가서 열심히 노력할 때 이러한 가치가 공식화되는 것을보기 시작할 수 있습니다. 대기 시간 또는 몇 분 후에. 나는 그렇게하는 다른 플랫폼이나 앱을 알지 못합니다. CF DCRAINMAKER
Arduino NRF52840 Express 보드에서 실행중인 실내 교육 응용 프로그램을위한 C ++ 코드를 개발하기로 결정했으며 Xert 앱 (Garmin Connect의 경우)의 기능에 가능한 한 가깝습니다. 더 큰 프로젝트의 필수 부분 인 공기 흐름이되었습니다. 다음은 기초의 과학과 수학에 대한 설명입니다.
Xert 앱은 소위 혐기성 작업 용량 ( AWC ) 또는 기능 예비 용량 ( FRC )의 고갈에 기반을두고 있음이 분명했습니다. 간단하게 유지하기 위해 자전거 타는 사람이 주어진 양을 가지고 있다고 가정합니다. 유한 작업 능력 (에너지 보호 구역)는 타기 시작시 내부적으로 저장됩니다. 이 에너지의 양은 수학적 용어로 w ' (pronalounce w prime )로 알려져 있으며, 에너지이며 결과적으로 줄무늬로 측정됩니다. 낮은 강도로 타는 동안 W '는 소비되지 않았기 때문에 전체 레벨에 남아 있으며 오랫동안이 강도를 계속 타는 데 계속 승차 할 수 있습니다. 그러나 더 세게 밀면이 에너지를 사용하기 시작합니다. 이 에너지 보호 구역을 소비하기 시작하는 한도는 Critical Power ( CP )라고합니다. CP 보다 페달을 더 세게 밀면 W '가 줄어 듭니다. 생산 된 전력 (와트) 이 CP 보다 낮아 지 자마자 W '는 "재생"되며 에너지 보호 구역이 다시 증가합니다. CP 아래에서 충분히 오래 타면 W '는 100% 레벨에 다시 접근합니다. 그러나 CP 위에서 열심히 일할 때 W '는 완전히 고갈되고 바로 그 순간에 소진 될 것입니다 (일명 T Lim )! W ' 의 변형은 Dr. Skiba 알고리즘 (2)에서 " W'균형 "으로 표현됩니다. 알고리즘의 또 다른 매개 변수는 전원이 CP 보다 낮을 때 W ' 가 재생되는 속도를 정의하는 타우 입니다.
CP 는 일반적으로 45 ~ 60 분 동안 장기간 동안 유지 될 수있는 최고 운동 강도로 정의됩니다. 기능적 임계 값 전력 ( FTP )은 레크리에이션 사이클링에서 더 잘 알려져 있으며 60 분 동안 유지할 수있는 가장 높은 평균 전력 출력으로 정의되었습니다 (1). 정의의 큰 유사성을 감안할 때, 우리는 비 엘리트 순환을 CP 와 FTP 값 사이에 유의 한 차이가 없다고 가정합니다!
구현해야 할 알고리즘은 Dave Waterworth (3)의 Integral Skiba 알고리즘의 원래 Dr. Skiba 알고리즘 (2) 및 최적화 (근사)입니다. Aart Goossens는 Arduino 설정에서 다양한 알고리즘을 이해하고 구현하는 데 큰 도움이되는 Github (4)에 대한 코드 (Python) 및 설명 정보를 게시했습니다. 다음 정보는 독자에게 알고리즘의 수학적 배경에 대한 통찰력을 제공하기 위해 그의 원래 작품에서 논의되어 있습니다. aart goosens @ github에서 그의 작품을 참조하십시오.
적분 Skiba 알고리즘은 W '밸런스를 계산하는 가장 잘 알려진 알고리즘이며 과학적으로 검증되었습니다 (5). 알고리즘의 방정식은 다음과 같습니다. 
W ' BAL ( t ) 은 시간 t 에서 W'BAL 과 같다 숫자 546, -0.01 및 316은 Skiba의 원래 기사에서 실험적으로 결정되며 개인간에 변경되지 않습니다. D CP는 CP 와 전력이 CP 보다 낮은 간격의 평균 전력의 차이입니다. D CP 동적으로 계산하거나 (시간 t 까지의 평균) 전체 운동에 대해 한 번 계산하고 정적 값으로 사용될 수 있습니다. Skiba는 d cp 에 정적 값을 사용하는 것이 좋습니다 . p (t) 는 시간 t 에 생성 된 전력이다.
수학자 Dave Waterworth (3)는 Mark Liversedge 인 Golden Cheetah의 핵심 개발자가 Skiba 알고리즘의 최적화를 개발하는 데 도움을주었습니다 (6). 이 개혁은 Skiba 알고리즘과 비슷하므로 결과는 극단적 인 경우에만 약간 달라질 수 있습니다. 특히 ( TAU )가 샘플 시간에 비해 매우 작을 때. Skiba 방정식의 W ' Bal 적분 부분은 Waterworth에 의해 다시 작성됩니다. 
여기서 s (t)는 시작 후 시간 t 에서 실행 합계 인 경우, 다른 기호는 이전 방정식을 준수합니다. 타우 ( ' w' )와 w ' exp (t)는 Skiba가 제시 한 원래 방정식으로 계산됩니다. 적분 Skiba 알고리즘은 빠른 컴퓨터에서도 계산하는 데 상당히 비싸다. Waterworth 최적화의 가장 큰 장점은 이제 W '균형을 실시간으로 계산할 수 있다는 것입니다. 또한 HIIT 운동 중 또는 W '밸런스가 부정적이고 고갈되었을 때 격렬한 운동 중에 치명적인 힘을 결정하고 싶을 때 매우 도움이됩니다!

수학적으로 전력 기간 관계는 쌍곡선 기능으로 묘사됩니다. 곡선의 4 가지 다른 점은 CP 위의 해당 최대 지속 가능한 전력에 도달하고 소진이 발생할 때 지점 ( t lim )을 나타냅니다. 운동 내성이 고려되면 전력-아스형 테트를 CP (Watts)라고합니다. 곡률 상수는 w ' (즉, 프라임 )로 알려져 있으며, 작업 단위 (줄음)로 측정됩니다. W '를 나타내는 4 개의 회색 영역은 형태가 다르지만 크기는 거의 같다는 점에 주목하십시오. 이 쌍곡선 전력 기간 관계는 작업을 수행하는 작업이 시간에 대해 표시되면 선의 경사가 CP 와 같고 인터셉트는 W ' 와 같도록 선형 관계로 변환 될 수 있습니다. 전력 기간 관계는 운동 관용을 설명하지만 설명하지 않는다는 점을 강조해야합니다. 그럼에도 불구하고, 아래 및 CP 에서 수행 된 운동에 대한 생리 학적 반응은 피로 과정에 대한 중요한 통찰력을 제공 할 수 있습니다. CP는 원래 "무기한"지속될 수있는 외부 전력 출력 또는 피로없이 오랫동안 오랫동안 정의되었습니다. 그러나이 정의는 무기한 운동을 할 수 없기 때문에 이론적으로 간주되어야합니다. 이제 CP는 운동 공차가 예측 가능하게 제한되는 전력 출력을 분리한다는 것이 이해됩니다 (운동 전력> CP ). CP 위에서 수행 된 운동에 대한 실제 편협 ( t lim ) 시간은 방정식에 의해 정의되어 밀접하게 예측됩니다.
t lim = w '/(p-cp)
이 방정식은 CP 이상의 편협에 대한 시간이 전력 출력 ( P )의 근접성과 CP 에 유지되는 기능의 함수이며 W ' 의 크기임을 강조합니다. P가 CP 보다 상당히 상당한 경우, W ' 매개 변수로 표시되는 일정한 양의 작업이 빠르게 활용되고 t lim은 짧습니다. CP 에 더 가까워지면 W '는 더 느리게'사용 '되고 T Lim은 더 길어질 것입니다. 여기서 중요한 고려 사항은 W '가 CP 보다 모든 P 에 대해 일정하다고 가정된다는 것입니다. 따라서이 ' 두 매개 변수 '전원 시간 또는 전력 기간 모델은 절대 운동 성능이 단순히 CP (와트)의 값과 w ' (joules)의 값에 달려 있음을 의미합니다. 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
이 코드는 공기 흐름 이라는 더 큰 프로젝트에 통합되었습니다. 기저 CP 및 W 프라임을 설정하거나 변경하는 것은 공기 흐름 동반자 앱의 필수 부분입니다! 공기 흐름 스마트 장치는 실내 사이클링 운동, 워밍업, 강도 간격, 간헐적 회복 및 재사용 대기 시간의 모든 단계에서 안정적인 열 균형을 위해 냉각 팬의 요청 된 공기 흐름 속도를 지속적으로 조정합니다. 자전거 타는 사람은 현장 간섭이 없으며 Stationay 트레이너 운동의 요구에 완전히 집중할 수 있으며, 항상 적절하게 그를 식힐 수있는 이상적인 비행장에 직면합니다. 또한 자전거 타는 사람은 훈련 강도가 강렬하고 길어질 때 자신의 비판적 힘을 개발할 때 (보너스로) 통찰력을 얻습니다! 적용된 Arduino NRF52480 Express CPU는 너무 강력하여 CP 및 W 프라임 의 실시간 계산은 열 균형 항을 결정하고 팬을 적절한 블로킹 용량으로 설정하기위한 모든 계산을 제외하고 달성 될 수 있습니다.
사이클리스트 (속성 : CP = 140 와트 및 W 프라임 = 7.2 kJ )는 그림과 같이 지속 시간과 강도로 강렬한 운동을하고 있습니다. W 프라임은 첫 번째 간격 블록 동안 여러 번 고갈됩니다. CP 및 W 프라임 의 새로운 값은 적절한 경우에만 운동 시간 동안 알고리즘에 의해 추정됩니다. 비디오를 실행하여 W Prime의 100% 고갈과 OLED 화면에 계산 된 예상 값을 볼 수 있습니다. 전원이 175 및 195 와트에서 CP를 초과 할 때 수평 막대가 어떻게 줄어든지 확인하십시오. 막대는 w '균형 에 비례하며 "탱크에 남은 것"은 백분율로 표시됩니다! 읽기는 가속 순서로 표시되며 운동의 표시 시간 지속 시간을 준수하지 않습니다! 