Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sensor's z-coordinate in CoP calculation? #354

Closed
felixchenier opened this issue Jan 14, 2025 · 5 comments
Closed

Sensor's z-coordinate in CoP calculation? #354

felixchenier opened this issue Jan 14, 2025 · 5 comments

Comments

@felixchenier
Copy link
Contributor

felixchenier commented Jan 14, 2025

Hi @pariterre

I'm wondering if the calculation of the CoP by ezc3d is accurate. I get slightly different results by doing it by hand. I checked ezc3d code and I found the cause of the difference. I'll try to be clear and I may very well be wrong.

Let's start by defining the force plate local coordinate system: x forward, y right, z bottom. The sensor is located at a vertical distance of z of the top of the plate.

image

CoP calculation is based on the fact that the only moment between the foot and the top of the plate is around the vertical axis. Therefore, there is no moment generated by the foot on the top of the plate in either the frontal plane and the sagittal plane. Consequently:

  • Mx is a function of only Fz (with x as lever arm) and Fy (with z as lever arm)
  • My is a function of only Fz (with y as lever arm) and Fx (with z as lever arm)

The equations for finding x and y (which are the CoP coordinates) are in the figure above. Those are the equations I implemented on my side. To be sure, I checked with David Winter's Biomechanics and Motor Control of Human Movement, and apart from the different coordinate systems, this is what they have in Eq (5.6):

image

However, in lines 385-386 of ezc3d/src/modules/ForcePlatorms.cpp, we have:

        ezc3d::Vector3d CoP_raw(-moment_raw(1) / force_raw(2),
                                moment_raw(0) / force_raw(2), 0);

which ignores the force components that generate moments via the z lever arm.

This creates a small discrepancy between the CoP I calculate and the CoP calculated by ezc3d, here with the BTS.c3d in ezc3d's test suite:

image

If I remove the (Fy z) and (Fx z) components as in ezc3d, I get the same (wrong?) CoP as ezc3d.

What do you think about it? I may be completely wrong though, maybe you used this z lever arm elsewhere as an intermediate calculation and therefore I account for it twice without knowing.

felixchenier added a commit to kineticstoolkit/kineticstoolkit that referenced this issue Jan 14, 2025
@felixchenier
Copy link
Contributor Author

I tried to make it still clearer for myself to be sure I don't mess with signs. Here's what I have.

image

When I calculate the CoP on the force plate 0 of BTS.c3d, I get these results:

image

In this file, the force platform's local y axis is pointing backward (posterior), which mean I'm pretty sure ezc3d calculates a CoP a few millimeters more forward than it should, mainly during the propulsion at the end of the weight bearing phase.

@pariterre
Copy link
Member

pariterre commented Jan 16, 2025

Hi @felixchenier, hope you are good!

I remember having a problem with this at some point when coding the force platform module. If I recall well, some c3d needed to be offseted and some not.

If I understand well, you are using a Kistler (TYPE-3) force platform which an offset is added right after (lines 387-410). This was double-check by another user here: #253

Can you confirm that your problem is 1) indeed (or is not) from a Type-3 force platform and 2) that it indeed needs to be corrected more than the already performed correction :)

Thanks for reporting!

@felixchenier
Copy link
Contributor Author

felixchenier commented Jan 16, 2025

Hi @pariterre

It's not related to a particular type of platform. It's strictly related to how the depth of the sensor(s), whichever sensor(s) it is, have an effect on the calculation of the CoP.

If the sensor is lower than the ground surface (it always is regardless of the technology), then the horizontal forces generate a torque not only around z, but also around x or y. This is because of this vertical distance between the sensor and surface that is a lever arm for Mx and My.

What I understand in ezc3d is that for either type of force plate, you generate a local coordinate system at the centre of the platform, at the same height as the force sensor(s), and you express the forces/moments in this coordinate system. It's already what we obtain from type 2,4 and I guess you convert the type 3's forces to that form. Am I right?

Once the forces and moments are expressed in this reference frame (which is below the surface), then the CoP can be calculated and I think this is where you may have forgotten the sensor vertical offset in lines 385-386 of ezc3d/src/modules/ForcePlatorms.cpp

I may also be wrong on how ezc3d reports moments.

This is based on my assumption that the moments reported by ezc3d are the moments measured around the force sensor, without modification. This seems to be the case as variable name in lines 385-386 of ezc3d/src/modules/ForcePlatorms.cpp is moment_raw and not moment_ground or something like that. CoP calculation using this line would be correct only if the moment have been reported around the ground surface instead of around the force sensor. Maybe this is what you do? In that case, the moments we get from the function are not the moments measured by the force sensor, but the moments calculated by ezc3d reported at the ground surface, using both the raw moments and the raw forces. I sure want to know if it's the case, to avoid performing double compensation.

Is it clearer? We may have a small Zoom session to discuss if you need.

@felixchenier
Copy link
Contributor Author

@pariterre

I just inspected the function ezc3d::Modules::ForcePlatform::extractData and I believe you effectively compute/report the force and moment around the sensor origin, as provided by the analog channels, at least for types 2 and 4 (I'm less familiar with Kistler and even less with their offset procedure for CoP):

Line 376, force_raw and moment_raw are built directly from the c3d raw data:

          for (size_t j = 0; j < 3; ++j) {
            force_raw(j) = data_raw(j);
            moment_raw(j) = data_raw(j + 3);
          }

This is what I expect.

Then on line 385, CoP is calculated from raw data indiscriminately of the sensor distance to the ground:

ezc3d::Vector3d CoP_raw(-moment_raw(1) / force_raw(2),
                                moment_raw(0) / force_raw(2), 0);

This is not what I expect.

@pariterre
Copy link
Member

After reviewing the code together, we arrived at the conclusion that the moments were indeed transported to the geometrical center (thanks to

moment_raw += force_raw.cross(_origin);
)

This means, the line 385 is correct to assume 0 for the Z distance.

A note was added the to ReadMe!

Thanks for reporting :)

felixchenier added a commit to kineticstoolkit/kineticstoolkit that referenced this issue Jan 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants