ivoflipse / Pawlabeling

Tool for processing and analyzing pressure measurements
Other
18 stars 1 forks source link

Add extra results to the analysis #45

Open ivoflipse opened 10 years ago

ivoflipse commented 10 years ago

Lyn Forster requested additional results:

Vertical impulse

From Oosterlinck:

Vertical impulse (VI) was calculated by time integration of the force–time curves and multiplied by time, normalised by weight and expressed as Newton-seconds per kilogram (N s/kg)

So wouldn't that just be one value? Namely the surface under the entire force curve?

Time of peak force

Simply the argmax of the maximum value (assuming there is only one...). I can either calculate this on the average or calculate this for each contact and then take an average over those values. Though this should use the frequency of the measurement to express it in milliseconds.

Stance/Swing Duration

The stance time is simple, since its just the duration of the contact. The swing time can only be calculated if I know when it stopped swinging, so I need at least 2 consecutive prints of the same paw (not so trivial).

Foot dimensions

Simply multiplying the (nonzero) shape of the max of max image with the sensor dimensions. I'll also probably add a graph for the changes in surface. Like so: Surface over time graph

Spatial/temporal variables

I calculated these in my previous app, but haven't ported the calculation yet. I haven't figured out an elegant way to calculate these results while dealing with 'missing' paws.

Speed of the dog

There are some options here, I can simply try and estimate the velocity in meters/second, based on the placement of a given paw (or all of them). For example, if I have multiple left front contacts, I can take the moment they touched the ground and the distance between them to estimate how fast the dog must have moved to get there. Possibly by averaging this over all paws to make it somewhat more stable against small variations.

Another option would be using the velocity of the COP (of all paws), this could be converted to a measure of mm/cm/m per second and split up in x and y or a euclidean/manhattan distance between consecutive points.

From this we could derive the gait type, possibly in combination with the order in which the paws land and what gait type that's associated with.

Direction of the dog

Currently I detect this (and log it) and automatically rotate the measurement if it happens. However, this is a nasty hack and it would be better to detect the orientation and store that independently. I could still rotate the paws, so calculations like averaging aren't affected and deal with spatial variables ignoring direction, but I'll figure something out.

Perhaps I can add a new tab with some of these values, like (a)symmetry indices and vertical impulse.

Dashboard with useful stats

lynforster commented 10 years ago

VI - yep, area under the curve. I used the trapezoidal rule to calculate it before. VI can be handy for quadrupeds as if the dog is maintaining altitude the sum of the VI for the four feet (for one contact of each foot for a gait cycle for example) will be numerically equal to the dogs weight in Newtons, so the VI of a particular foot can tell you whether a dog is shifting it's weight away from a limb.

Time of peak force - either in ms %stance (or both) would be suitable units. I use %stance as faster animals will have a shorter time of peak force in ms, simply because they are moving faster, but as long as you have both stance duration and time of peak force in ms %stance can easily be calculated during analysis.

Stance/swing duration - I forgot to mention also that when working out swing you can also work out stride length. Then, stride length divided by stride duration (stance duration + swing duration) = stride speed. Average of stride speeds for all four legs for the trial gives you speed of dog. I also like the average COP velocity idea, that's really neat. With stance and swing durations you can also get duty factor which is very useful.

Speed/gait of dog - The walk-trot gaits of a dog/cat are a continuum rather than discrete - they will perform a walk, then a trot-like-walk, then a walk-like-trot, then a trot. For differentiating between gaits it usually involves a human (looking at gait diagrams) as it's subjective - I ended up with walk, trot and 'intermediate' for things that were in between. Plus any animal that is lame or only has 3 legs will result in a totally different rhythm. A good book on gaits btw is Dogs in Motion by Fischer and Lilje - http://www.vdh.de/dogs-in-motion.html

ivoflipse commented 10 years ago

I've been working on calculating temporal/spatial stuff again: Temporal spatial

Though I haven't decided how to create an average yet, lets just say the code from iApp was ugly to say the least...

I'm also not 100% sure what would be the best definition. Should I compare the center points, the origin of the bounding box (i.e. the lower left corner) or something else. Likewise for step times. Any suggestions?

ivoflipse commented 10 years ago

I've actually coded up a whole bunch of these for the article we're working on, so I'm hoping to add these in the coming week.

ivoflipse commented 10 years ago

I've been adding these, but now there's an issue when loading contacts. Contacts.create_contact checks the table to see if the result is there and if so returns that. If not, it creates a new array in the table. But that's where the problem is, these results are calculated when the contacts are created. So already existing contacts don't have these results anywhere.

My idea was to create functions like time_of_peak_force, which when called check if the requested attribute is there. If so, they return it, if not, they calculate it and store it in an attribute, like _time_of_peak_force.

Alternatively, it is getting a bit messy to have all these implementation details available as class attributes. Perhaps it would be cleaner to have them all stored in a dictionary. That way storing and restoring should be easier too, because its easier to separate concerns

ivoflipse commented 10 years ago

That turned out to be harder than I thought, because to calculate some results, I need access to the right plate and measurement information. I'm tempted to add the plate information to the measurement.

I ended up modifying the loading code to make sure it passes the plate information as well.

ivoflipse commented 10 years ago

Now I'm running into another issue, some results like the time of peak force or vertical impulse aren't arrays, so storing them the way I normally do is problematic. I guess I could turn them into an array with a singular value...

ivoflipse commented 10 years ago

Which apparently doesn't work, because the shape of the resulting array is just empty. So perhaps I should add another table, that contains all these results.

That might not be a bad idea, since the temporal spatial results also need a table to be stored in.

ivoflipse commented 10 years ago

I've written a function that checks most tables in the database and if they aren't up to spec, tries to convert it. Which works for now, as long as you don't change the names/format of existing columns.

Next up, reprocess a contact to calculate missing results.

ivoflipse commented 10 years ago

I just merged in some changes, which required a different database layout. Upgrading seems to work OK, but it doesn't calculate any missing results by default, so you might have to save all your measurements again (no need to change the labeling though).

I also added two new widgets, one showing the ASI scores for several results another showing the mean values for those results, split up into the four contacts. However, I didn't tweak them for humans just yet (lazy me).