Private
Public Access
1
0

better power zones

This commit is contained in:
Sander Roosendaal
2022-12-15 22:10:37 +01:00
parent 98f2ff2707
commit 47d8dd63d3
6 changed files with 134 additions and 103 deletions

View File

@@ -1259,7 +1259,6 @@ def getsmallrowdata_db(columns, ids=[], doclean=True, workstrokesonly=True, comp
df = pd.concat(data, axis=0) df = pd.concat(data, axis=0)
except ValueError: # pragma: no cover except ValueError: # pragma: no cover
return pd.DataFrame() return pd.DataFrame()
# df = dd.concat(data,axis=0)
else: else:
try: try:

View File

@@ -6283,7 +6283,15 @@ def thumbnails_set(r, id, favorites):
columns += ['time'] columns += ['time']
rowdata = dataprep.getsmallrowdata_db(columns, ids=[id], doclean=True) rowdata = dataprep.getsmallrowdata_db(columns, ids=[id], doclean=True)
rowdata.dropna(axis=1, how='all', inplace=True) try:
rowdata.dropna(axis=1, how='all', inplace=True)
except TypeError:
return [
{'script': "",
'div': "",
'notes': ""
}]
if rowdata.empty: if rowdata.empty:
try: try:
@@ -6303,12 +6311,6 @@ def thumbnails_set(r, id, favorites):
'notes': "" 'notes': ""
}] }]
# else:
# try:
# rowdata.sort_values(by='time',ascending=True,inplace=True)
# except KeyError:
# pass
lengte = len(rowdata) lengte = len(rowdata)
maxlength = 50 maxlength = 50
if lengte > maxlength: if lengte > maxlength:

View File

@@ -964,6 +964,7 @@ class Rower(models.Model):
# Power Zone Data # Power Zone Data
ftp = models.IntegerField( ftp = models.IntegerField(
default=226, verbose_name="Functional Threshold Power") default=226, verbose_name="Functional Threshold Power")
cogganzones = models.BooleanField(verbose_name='Use Default Power Zones',default=True)
p0 = models.FloatField(default=1.0, verbose_name="CP p1") p0 = models.FloatField(default=1.0, verbose_name="CP p1")
p1 = models.FloatField(default=1.0, verbose_name="CP p2") p1 = models.FloatField(default=1.0, verbose_name="CP p2")
@@ -997,11 +998,11 @@ class Rower(models.Model):
pw_an = models.IntegerField(default=273, verbose_name="AN Power") pw_an = models.IntegerField(default=273, verbose_name="AN Power")
powerzones = PowerZonesField(default=['Rest', powerzones = PowerZonesField(default=['Rest',
'Pwr UT2', 'Active Recovery',
'Pwr UT1', 'Endurance',
'Pwr AT', 'Tempo',
'Pwr TR', 'Threshold',
'Pwr AN']) 'Anaerobic'])
hrzones = PowerZonesField(default=['Rest', hrzones = PowerZonesField(default=['Rest',
'UT2', 'UT2',
@@ -4224,7 +4225,7 @@ class RowerExportForm(ModelForm):
class RowerPowerForm(ModelForm): class RowerPowerForm(ModelForm):
class Meta: class Meta:
model = Rower model = Rower
fields = ['hrftp', 'ftp', 'otwslack'] fields = ['hrftp', 'ftp', 'otwslack','cogganzones']
class RowerCPForm(ModelForm): class RowerCPForm(ModelForm):

View File

@@ -10,6 +10,103 @@
<p><a href="http://analytics.rowsandall.com/2017/11/02/rowsandall-settings-page-tutorial/">Need help? Click to read the tutorial</a></p> <p><a href="http://analytics.rowsandall.com/2017/11/02/rowsandall-settings-page-tutorial/">Need help? Click to read the tutorial</a></p>
<ul class="main-content"> <ul class="main-content">
<li class="grid_2">
<form enctype="multipart/form-data" action="" method="post">
<h2>Functional Threshold Power and OTW Slack</h2>
<p>Use this form to quickly change your zones based on the power
of a recent full out 60 minutes effort on the ergometer. It
will update all zones defined.</p>
<p>The OTW Power Slack is the percentage drop of your On-the-water
rowing power vs the erg power. Typical values are around
15%. This will lower the power zones for your OTW workouts.</p>
<p>If you use default power zones, we will use the namees and
values as defined by
<a href="https://www.trainingpeaks.com/blog/power-training-levels/" target="_">Coggan</a>.</p>
<table>
{{ powerform.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Update">
</form>
</li>
<li class="grid_2">
<h2>Power Zones</h2>
<p>Use this form if you want to rename and redefine your power
zones independent of the value of FTP. We recommend, however, that
you leave these values as they are and only change the FTP and OTW
slack values.</p>
<form enctype="multipart/form-data" action="" method="post">
{% if powerzonesform.errors %}
<p style="color: red;">
Please correct the error{{ powerzonesform.errors|pluralize }} below.
{{ powerzonesform.non_field_errors }}
</p>
{% endif %}
<table>
<thead>
<tr>
<th>ID&nbsp;</th><th>Zone Name</th><th>Lower Boundary (Watt)&nbsp;</th><th>Lower Boundary (Watt)</th>
</tr>
<tr>
<th></th><th></th><th>Indoor</th><th>OTW</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td><td>{{ powerzonesform.ut3name }}</td>
<td></td>
</tr>
<tr>
<td>2</td><td>{{ powerzonesform.ut2name }}</td>
<td>{{ powerzonesform.pw_ut2 }}</td>
<td>{{ user.rower.pw_ut2|otwslack:user }}</td>
</tr>
<tr>
<td>3</td><td>{{ powerzonesform.ut1name }}</td>
<td>{{ powerzonesform.pw_ut1 }}</td>
<td>{{ user.rower.pw_ut1|otwslack:user }}</td>
</tr>
<tr>
<td>4</td><td>{{ powerzonesform.atname }}</td>
<td>{{ powerzonesform.pw_at }}</td>
<td>{{ user.rower.pw_at|otwslack:user }}</td>
</tr>
<tr>
<td>5</td><td>{{ powerzonesform.trname }}</td>
<td>{{ powerzonesform.pw_tr }}</td>
<td>{{ user.rower.pw_tr|otwslack:user }}</td>
</tr>
<tr>
<td>6</td><td>{{ powerzonesform.anname }}</td>
<td>{{ powerzonesform.pw_an }}</td>
<td>{{ user.rower.pw_an|otwslack:user }}</td>
</tr>
</tbody>
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input type="submit" value="Update Power Zones">
</div>
</form>
</li>
<li class="grid_2">
<form enctype="multipart/form-data" action="" method="post">
<h2>Fitness and Performance Manager Settings</h2>
<p>Use this form to change the parameters affecting your performance management.</p>
<p>A shorter range for the CP calculations
will give you notifications of fitness improvements more often,
but will also quickly forget those breakthrough workouts. Shorter decay
time constants for the performance manager will model a quicker building up
of fitness and a faster recovery. Recommended values are 42 days (fitness)
and 7 days (fatigue).</p>
<table>
{{ cpform.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Update">
</form>
</li>
<li class="grid_2"> <li class="grid_2">
<p> <p>
<h2>Heart Rate Zones</h2> <h2>Heart Rate Zones</h2>
@@ -22,7 +119,7 @@
</p> </p>
{% endif %} {% endif %}
<table> <table>
<thead> <thead>
<tr> <tr>
<th>ID</th><th>Zone Name</th><th>Lower Boundary (BPM)</th> <th>ID</th><th>Zone Name</th><th>Lower Boundary (BPM)</th>
</tr> </tr>
@@ -52,7 +149,7 @@
<td>6</td><td>{{ form.hranname }}</td> <td>6</td><td>{{ form.hranname }}</td>
<td>{{ form.an }}</td> <td>{{ form.an }}</td>
</tr> </tr>
<tr> <tr>
<td>7</td><td>{{ form.hrmaxname }}</td> <td>7</td><td>{{ form.hrmaxname }}</td>
<td>{{ form.max }}</td> <td>{{ form.max }}</td>
</tr> </tr>
@@ -62,92 +159,6 @@
<input type="submit" value="Update Heart Rate Zones"> <input type="submit" value="Update Heart Rate Zones">
</form> </form>
</li> </li>
<li class="grid_2">
<h2>Power Zones</h2>
<p>The power zones are defined relative to power as measured by the
indoor rower.</p>
<form enctype="multipart/form-data" action="" method="post">
{% if powerzonesform.errors %}
<p style="color: red;">
Please correct the error{{ powerzonesform.errors|pluralize }} below.
{{ powerzonesform.non_field_errors }}
</p>
{% endif %}
<table>
<thead>
<tr>
<th>ID</th><th>Zone Name</th><th>Lower Boundary (Watt)</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td><td>{{ powerzonesform.ut3name }}</td>
<td></td>
</tr>
<tr>
<td>2</td><td>{{ powerzonesform.ut2name }}</td>
<td>{{ powerzonesform.pw_ut2 }}</td>
</tr>
<tr>
<td>3</td><td>{{ powerzonesform.ut1name }}</td>
<td>{{ powerzonesform.pw_ut1 }}</td>
</tr>
<tr>
<td>4</td><td>{{ powerzonesform.atname }}</td>
<td>{{ powerzonesform.pw_at }}</td>
</tr>
<tr>
<td>5</td><td>{{ powerzonesform.trname }}</td>
<td>{{ powerzonesform.pw_tr }}</td>
</tr>
<tr>
<td>6</td><td>{{ powerzonesform.anname }}</td>
<td>{{ powerzonesform.pw_an }}</td>
</tr>
</tbody>
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input type="submit" value="Update Power Zones">
</div>
</form>
</li>
<li class="grid_2">
<form enctype="multipart/form-data" action="" method="post">
<h2>Functional Threshold Power and OTW Slack</h2>
<p>Use this form to quickly change your zones based on the power of a
recent
full out 60 minutes effort on the ergometer.
It will update all zones defined above.</p>
<p>The OTW Power Slack is the percentage drop of your On-the-water
rowing power
vs the erg power. Typical values are around 15%. This will lower
the power zones for your OTW workouts.</p>
<table>
{{ powerform.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Update">
</form>
</li>
<li class="grid_2">
<form enctype="multipart/form-data" action="" method="post">
<h2>Fitness and Performance Manager Settings</h2>
<p>Use this form to change the parameters affecting your performance management.</p>
<p>A shorter range for the CP calculations
will give you notifications of fitness improvements more often,
but will also quickly forget those breakthrough workouts. Shorter decay
time constants for the performance manager will model a quicker building up
of fitness and a faster recovery. Recommended values are 42 days (fitness)
and 7 days (fatigue).</p>
<table>
{{ cpform.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Update">
</form>
</li>
</ul> </ul>

View File

@@ -1039,3 +1039,8 @@ def previousworkout(workout, user):
return encoder.encode_hex(ws[0].id) return encoder.encode_hex(ws[0].id)
else: else:
return 0 return 0
@register.filter
def otwslack(value, user):
r = Rower.objects.get(user=user)
return int(value*(100.-r.otwslack)/100.)

View File

@@ -618,13 +618,23 @@ def rower_prefs_view(request, userid=0, message=""):
hrftp = int((r.an+r.tr)/2.) hrftp = int((r.an+r.tr)/2.)
ftp = cd['ftp'] ftp = cd['ftp']
otwslack = cd['otwslack'] otwslack = cd['otwslack']
cogganzones = cd['cogganzones']
powerfrac = 100*np.array([r.pw_ut2, powerfrac = 100*np.array([r.pw_ut2,
r.pw_ut1, r.pw_ut1,
r.pw_at, r.pw_at,
r.pw_tr, r.pw_an])/r.ftp r.pw_tr, r.pw_an])/r.ftp
if cogganzones:
powerfrac = np.array([55.,75.,90.,105.,120.])
powerzones = ['Rest',
'Active Recovery',
'Endurance',
'Tempo',
'Threshold',
'Anaerobic']
r.powerzones = powerzones
r.ftp = max(min(ftp, 650), 50) r.ftp = max(min(ftp, 650), 50)
r.otwslack = max(min(otwslack, 50), 0)
ut2, ut1, at, tr, an = (r.ftp*powerfrac/100.).astype(int) ut2, ut1, at, tr, an = (r.ftp*powerfrac/100.).astype(int)
r.pw_ut2 = ut2 r.pw_ut2 = ut2
r.pw_ut1 = ut1 r.pw_ut1 = ut1
@@ -632,7 +642,10 @@ def rower_prefs_view(request, userid=0, message=""):
r.pw_tr = tr r.pw_tr = tr
r.pw_an = an r.pw_an = an
r.hrftp = hrftp r.hrftp = hrftp
r.otwslack = max(min(otwslack, 50), 0)
r.save() r.save()
powerzonesform = RowerPowerZonesForm(instance=r)
message = "FTP and/or OTW slack values changed." message = "FTP and/or OTW slack values changed."
messages.info(request, message) messages.info(request, message)