Code Monkey home page Code Monkey logo

Comments (17)

WouterJD avatar WouterJD commented on August 10, 2024 1

Indeed; with implicit challenge to implement multi-threading or even mult-tasking ...
Since FortiusANT is my -get-to-know-python project that's valuable; hints welcome :-)

from fortiusant.

WouterJD avatar WouterJD commented on August 10, 2024

Hi @mattipee
Since you known antifier, you understand that FortiusANT is a sort of antifier 2.0; the lop handling ANT+ and TacxTrainer is still the same and indeed, the 4/sec is based upon ANT+ frequency.
If I understand right, there is a maximum for the trainer-read as well.

Please detail what you did and how and I may implement this; please explain as well why you need it; what software does the polar view analysis?

Thanks for joining!

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

Cheers, @WouterJD. I see the similarities to antifier.

While waiting for the user to start pedalling, I had a loop that was a little like this:

while (speed == 0):
    trainer.send(...)
    blah = trainer.receive(...)

with no sleep in the loop. Adding some instrumentation to the loop, I determined the ~60Hz frequency.

I haven't touched FortiusANT yet, merely observed that more frequent power/speed values from the trainer were possible. If trainer reads are allowed to happen as often as possible (eg 60Hz), branching to perform ANT comms only as often as desired (eg 4Hz), a greater resolution of data would be available internal to FortiusANT than would be being transmitted over ANT.

Within that finer grained data, we may have 60 or so data points for speed, power and pedecho per second. These may or may not be useful - I don't know how often and with what accuracy they are updated internal to the motor/controller. It may be that six or seven consecutive read results actually contain the same values. Further investigation required.

Anyway, the idea is that, given pedecho, we have a reference rising edge to indicate the start of a pedal revolution. There may be some angular/timing subtleties to consider, but basically between pedecho rising edges there are some number of samples - say 40, or 50 or 42, each with speed and power. Exactly how many samples will depend on cadence, sample frequency, accuracy of rising edge, etc...

There may be many ways to then process each set of samples, but I imagined one might scale and interpolate the N-or-so samples you get for each revolution to a fixed number, say 128 samples, and then stack/average several revolutions together to reduce noise. Then plot on a polar graph, most likely as another widget on the FortiusANT GUI.

I've just captured some data (pedecho + force), and for a fairly slow-cadence ramp up in top gear, I graphed a single revolution, which is clearly two-lobed, representing left/right, though probably rotated 100 degrees or so, given the location of my cadence sensor.

polar_example

Once at my desired cadence, the graph I get is less appealing, and perhaps not actually that useful.

Perhaps by averaging several pedal revolutions, one can reduce noise and get a better visual. I may try my resample+average idea at a reasonable cadence (eg 73rpm @ 200W) and see what I can come up with, It may be that the rotational inertia of the wheel+tyre also masks some of the variations in power at the pedal, and perhaps it is necessary to account for this.

All that said, I'm thinking out loud. If it's not useful, it's probably not worth continuing with the idea at all. I can't think of any other use for a higher frequency of data.

from fortiusant.

WouterJD avatar WouterJD commented on August 10, 2024

Would sure be added value, drawing such a graph on the FortiusANT interface.

Two questions:

  • Does Fortius tacx provide the data 360/revolution?
  • How do you know whether the pedal is at top/front/bottom/back to have the angle?
  • If so: how to draw the graph in python

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

The data series is simply a series of samples - for this purpose care only about pedecho (0/1) and instantaneous force (some value 0-NNNN). How many of them? Something around 60/sec and depends on cadence how many samples/revolution. The rising edge of pedecho 0->1 or perhaps the mid-point of a series of consecutive 1s would indicate the "start" of a revolution.

Each revolution starts in space wherever the cadence sensor is situated on the bike - eg my chainstay, slightly below horizontal, and whenever the magnetic field from the magnet on the crank activates it, probably just before it arrives in-line with it. In plotting a polar graph, that angular offset should be configurable.

So you only know when the pedal passes the sensor. And you only know that approximately. You need to assume the rest of the revolution, I suppose. You can see variations in wheel speed under load, and you could use those variations to infer angular progression of the crank for a given gear ratio, but read on.

The series of data points between two "pedal passes the sensor" events is the data for one revolution. Even determining where that event is in a series such as 111100000000000000111000000000001111100000000000000011111 is subject to a bit of guesswork.

Then, unless we have arrival time associate with each sample, one could start by assuming that for example our 50-or-so samples are uniformly separated in time, and if one assumes pedal rotation is constant (which it isn't), that the samples are equi-angular, which they won't be.

Once you start averaging a few pedal strokes together, the finer points above perhaps matter less. But I suspect this approach is fundamentally flawed for a wheel-on trainer anyway, given the wheel's own inertia.

Graphing it in python is probably the least complex issue here.

from fortiusant.

WouterJD avatar WouterJD commented on August 10, 2024

First time I get an explanation for pedecho, never understood it before.
Very appealing idea; I will see what can be done.

One concern at this moment is that the userinterface takes time to refresh which holds the loop...

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

I hope I'm not incorrect in my own understanding.

I expect the comms loop would need to be split into two threads anyway, at least trainer comms should be distinct from anything else.

If... the trainer was to be allowed to supply samples as quickly as possible, then it would be unhelpful to every 10th or 15th time round the loop to then say "hold on, let's do ANT stuff this time", as the trainer samples would then be very much not equally spaced in time, with discontinuities each time ANT comms occurred.

Shared state I guess is "what ANT is asking of the trainer" and "what the trainer needs to tell ANT".

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

I'll get back to you with more data, see if it makes sense doing anything at all.

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

Hmmm. Well, you can certainly capture, resample and average - it smooths out the data nicely.

However, I'm not clipped in and was stomping pedals like a noob and the graph was pretty rounded - I don't think this idea is a good one overall, not with this trainer anyway.

Nice idea, while it lasted.

from fortiusant.

WouterJD avatar WouterJD commented on August 10, 2024

Well @mattipee, perhaps I did not respond very much, but I was occupied with the i-Vortex.

The pedal analysis is very appealing, especially because it is a great added benefit, something nobody else has and graphically appealing :-)

So I did a test and used the Runoff loop for it, adding some additional prints and a cycle-time of 0.01 second, just to see whether it works and YES IT DOES.

The PedalEcho is actually well returned and is the basis for ZERO, the timestamps then reveal the angle.

        delta = (TimeStamp - PedelEchoTime) * 24 * 60 * 60
        cycle = 60 / Cadence
        Angle = Round(delta / cycle * 360, 0)

Putting that into a graph gives the following result; it's absolutely quick and dirty, the power is the average on the measured angle (causing the strange jumps).
But I would say

  • Fortius can be polled pretty fast (10 ms works)
  • Data is returned and usable
  • Pedal stroke analysis can be done

Important action before I can further implement it is to split into separate processes so that the GUI will not delay the loop; a task I did not yet complete - finding out how that works. having issues with hangups but working on it.

image

Find attacched the produced logfile which should be considered as a basic Proof Of Concept.

FortiusANT.2020-04-24 20-06-06 PedalStrokeAnalysis.log

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

Interesting stuff, glad you have had time to have a play. Well done with the iVortex addition.

If nothing else, trying to incorporate something like this motivates a lot of the other changes on my mind. Not convinced, even once smoothed, that the results will be particularly telling wrt formal pedal stroke analysis. But if it's good enough to show left-right imbalance for example, or any difference between two pedalling techniques, it's an interesting thing to try.

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

The following code might be useful:

import numpy
from scipy import interpolate

def resample(x, n, kind='linear'):
    f = interpolate.interp1d(numpy.linspace(0, 1, x.size), x, kind)
    return f(numpy.linspace(0, 1, n))

a=numpy.array([5,6,7,8,8,4,0,2,4,6,6,4,3,3,5,7,8,4])
print(resample(a,128))

I started by assuming my responses from trainer would be perfectly regular/periodic. Each time I got a force sample, I appended to an array. When I saw my next pedecho=1, I would have N samples in the array.

I used the routine above to resize the array from N to, for example, 128, or 360 or whatever. It would linearly interpolate any missing samples. Then, with my new 128-sample rotation array, I could store it and either calculate a moving-average of the last 10 rotations, or whatever.

Note that if we use the millisecond timing instead of assuming regular timing, then you may need to go from samples and their arrival time, to an intermediate array of timing-regularised points (possibly longer than the final), to the final 360-sample array. May need to linearly interpolate manually to fill sub-sample holes as you're samplewise filling the intermediate array. I can explain my thinking later, as I think this paragraph is probably poorly worded.

Plenty of food for thought if you google "pedal stroke analysis" for images.

My concern is that there may not be a sufficient dip in power reported by the Fortius to really demonstrate the shape as seen in the figure of eight or peanut on this page... https://support.wattbike.com/hc/en-gb/articles/115001848609-A-Beginner-s-Guide-To-Perfect-Pedalling. I think, once smoothed, we'll all look elite. I don't know if setting virtual flywheel to 0 would help, or if you need to subtract calibration value or what.

from fortiusant.

totalreverse avatar totalreverse commented on August 10, 2024

Some time ago I had a similar idea for the iMagic. There, you have the raw TTL signals from pedal sensor and the wheel (the problem here is the real fly wheel.)

For the Fortius, things are different but probably still good enough.

  1. I would recommend to try the 16 bit value in bytes 34,35 of the answer. This is the most sensitive value you can get from the trainer. It's probably the raw value of the internal current or voltage measurement and not interpolated. I do not know, if this value is linear to the force, but it is at least worth a try.

  2. Polling with 10ms does not make sense. The protocol between the head unit and the trainer is (about) 19200 baud. An answer data frame between the trainer and the head unit needs 52 bytes. With 8N1 coding you will get 19200/10/52 = 37 data frames per second (= about 27ms).
    The real polling time should be even lower, because the trainer only sends an answer after getting a command from the head unit. So, the polling time is also limited by the rate the head units sends commands to the trainer.

from fortiusant.

mattipee avatar mattipee commented on August 10, 2024

@totalreverse great points, thanks.

I was getting ~60Hz from the head unit, but the lower rate between head and trainer makes sense as you describe. That explains multiple repeated samples from the head unit getting the same value - like a kid in the car asking "are we there yet?" It think it is possible, by averaging many revolutions, assuming consistent rider pedal strokes, to get sub-sample resolution over time.

But the rear wheel is indeed a flywheel of sorts.

I truly think this was an interesting idea, but too much for the tech we're using. Limited by a) physics, and b) baud rate.

from fortiusant.

WouterJD avatar WouterJD commented on August 10, 2024

great info. 10ms was just a blind 1st try.
Will proceed

from fortiusant.

WouterJD avatar WouterJD commented on August 10, 2024

And yes; Pedal Stroke Analysis works.
Some final stability tests to be done...

Left/right balance is nicely displayed and even if this is just for user-entertainment; that's exactly what we need instead of dull screens to loook at :-)

Sampling at 20ms works. Side-effect of fast sampling is that the headunit buttons repeat over consecutive readings, which explains why I experienced "double entries" in the past.

image

from fortiusant.

WouterJD avatar WouterJD commented on August 10, 2024

Implemented and activated with the -A flag. A = Analyse Pedal Stroke

from fortiusant.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.