Welcome Guest,Register Now
Log In

ANT Forum

Welcome guest, please Login or Register

You are here: Forum Home → ANT+ Forums → ANT+ Bike Power → Thread

   

Implementation of Speed Computation from Power Profile Formula

Rank

Total Posts: 12

Joined 2020-02-12

PM

Hello Folks,
I'm not certain that I've coded the formula correctly so I'm posting here to double-check. My question concerns the handling of the event_count and wheel_period variables.

My development environment is Python 3.7 on a Win10 machine using Atom v1.45 with Script v3.25. My Python script gathers the data streams from all my ANT+ and BLE sensors and inserts said data into a SQLite3 relational database.

So....using the formula from page 35 of the ANT+ Bicycle Power Profile, I've created the following code (snippet):
if mv2[0] == 17:        # Page 0x11. Standard Wheel Torque Main Data Page
    
event_count mv2[1]
    
    
# Handle the rollover condition for the event count
    
if event_count_old is None:
        
# 'event_count_old' is globally initialized, so this 'None' part might not be needed
        
pass
    elif event_count 
event_count_old:
        
# rollover
        
event_count event_count event_count_old 256
    
else:
        
# event_count = mv2[1]
        
pass

    wheel_period 
int((mv2[5] << 8) | mv2[4])

    
# Update the global value(s)
    # Update the speed variable if we have a new event, and the wheel's turning
    
if event_count event_count_old and wheel_period wheel_period_old != 0:
        
# My wheel diameter in approximate meters. Omit the division by ~1.6 to return to units of km/h
        
val_speed = (3600/1000) * ((0.678 * (event_count event_count_old)) / ((wheel_period wheel_period_old) / 2048)) * pi 1.609344
        
# print(f"\tval_speed... {val_speed:.1f}")
    
else:
        
# The wheel isn't turning, speed is zero
        
val_speed equals 0.0

    
# After a valid wheel speed value is recorded, update the previous values. The *_old values are persistent outside this code section.
    
event_count_old equals event_count
    wheel_period_old equals wheel_period 

The code as a whole inserts my various sensor values into the respective table, but I'm not sure that my equation logic is correct. Would anyone care to comment?
Thanks,
Eric
     

Image Attachments

AvgSpeedFormula.png

Click thumbnail to see full-size image

RankRankRankRank

Total Posts: 370

Joined 2012-06-27

PM

"if event_count_old is None:" should be skipping the computation.

Your rollover handling is not correct. Ex old 255 new 0. event_count becomes 0 - 255 + 256 = 1 and the calculation below becomes 1 - 255 = -254 so val_speed is set to 0.

You are setting a constant value for the wheel circumference, which may not be constant depending on your use case.      

Signature

Ian Haigh

Rank

Total Posts: 12

Joined 2020-02-12

PM

Thanks Ian. Very much appreciated. Trying a fix right now...      
Rank

Total Posts: 12

Joined 2020-02-12

PM

Hello Ian,
To confirm, for example, the wheel_period value provided by mv2[5] << 8) | mv2[4] might be 8603, whereas the immediately previous value might be 7029. If the difference is 8603 - 7029 = 1574 then divided by 2048 to give me about 0.77 seconds of rotation. Is this understanding correct?

Thanks for your help (again),
Eric      
RankRankRankRank

Total Posts: 370

Joined 2012-06-27

PM

In you example if the event count incremented by 1, then yes that means the wheel rotation took 0.77 seconds. However the event count could also increment by 2, 3, 4, etc if more than one wheel rotation occurred. Hence equation 2 incorporates the event count, and the wheel period.

You need to handle both the event count, and the wheel period rolling over.      

Signature

Ian Haigh

Rank

Total Posts: 12

Joined 2020-02-12

PM

Right! Thanks!
I'm breaking the process down into smaller chunks to ensure I understand what is supposed to happen versus what I've actually coded. Initially, I thought if I coded strictly per the equation (and what I read/saw what others have done,) it would be correct. Obviously though, I'm way off target. I've much more work and thinking to do.

Cheers,
Eric      
RankRankRankRank

Total Posts: 370

Joined 2012-06-27

PM

So you can code to exactly match the equation if you are using unsigned arithmetic, which is the most common case for embedded C code.

In python you have to handle the rollover more explicitly to prevent the subtractions from yielding negative results.      

Signature

Ian Haigh

Rank

Total Posts: 12

Joined 2020-02-12

PM

Hi Ian,
Thanks for the guidance! In thinking about the event count instance, the following handling (code snippet) seems to provide similar (script editor console print) output compared to the handlebar/head unit display (values) for the Powertap hub:
# The event counter has reached 256, so the next event_count value equals 1, thus ...
if event_count event_count_old:
    
# It's a rollover condition; adjust the previous value to an arbitrary value of 1
    
event_count_old event_count_old 255

# Allow the equation to run under specific conditions
if (event_count event_count_old) > and ((wheel_period wheel_period_old) / 2048) > 0:
    
# The wheel is turning...run the formula (km/h)
    
speed = (3600/1000) * ((2.133 * (event_count event_count_old)) / ((wheel_period wheel_period_old) / 2048))
    
# Compare this value to the speed displayed in the Joule GPS head unit
    
print(f"speed... {speed:.1f}")
# Some condition statement is likely needed here...
else:    
    
# The wheel isn't turning, speed is zero.
    
speed 0.0
    
# Compare the value...
    
print(f"speed... {speed:.1f}\n")

# See what's happening with the other parts of the formula
print(f"events new, old: {event_count} {event_count_old}\n"
    
f"wheel periods new, old: {wheel_period} {wheel_period_old} {(wheel_period - wheel_period_old) / 2048} seconds\n"
    
f"partial formula: {(event_count - event_cound_old) / ((wheel_period - wheel_period_old) / 2048)}")

event_count_old event_count
wheel_period_old 
wheel_period 

In this rendition, both output speed values are nearly identical. An exception is the division-by-zero error raised when, without closer inspection, the dynamic wheel_period difference becomes negative. I haven't addressed this condition yet. I believe this is an example of your "...subtractions from yielding negative results."
At this point, I think the event count handling is performing correctly...thoughts?
Cheers,
Eric      
RankRankRankRank

Total Posts: 370

Joined 2012-06-27

PM

You need to handle rollover on both event_count and wheel_period.

The following code in your example is not correct:

# The event counter has reached 256, so the next event_count value equals 1, thus ...
if event_count < event_count_old:
# It's a rollover condition; adjust the previous value to an arbitrary value of 1
event_count_old = event_count_old - 255

The first comment is not true because the event count can only reach 255 and does not necessarily increase in increments of 1. The if check is correct. The adjustment is incorrect. ex old_event_count = 255 and new event count = 3 which represents a diff of 4 your equation gives 3-0 = 3. When subtracting from the old count, or adding to the new count to handle rollover you need to use 256 and 65536 for event count and wheel period.

The following is one way to handle rollover:

if event_count < event_count_old:
# Rollover
event_count_diff = event_count + 256 - event_count_old
else:
event_count_diff = event_count - event_count_old

if wheel_period < wheel_period_old:
# Rollover
wheel_period_diff = wheel_period + 65536 - wheel_period_old
else:
wheel_period_diff = wheel_period - wheel_period_old      

Signature

Ian Haigh

Rank

Total Posts: 12

Joined 2020-02-12

PM

Thank you so much for your help, Ian! My db table shows accurate values compared to the head unit.
Best regards,
Eric