Skip to content

Commit 46e15b1

Browse files
Update README.md
1 parent 07439a8 commit 46e15b1

File tree

1 file changed

+43
-25
lines changed

1 file changed

+43
-25
lines changed

README.md

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
[![codecov](https://codecov.io/gh/halleysfifthinc/C3D.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/halleysfifthinc/C3D.jl)
77
[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
88

9-
C3D is a common file format for motion capture and other biomechanics related measurement systems (force plate data, EMG, etc). The goal of this package is to completely implement the [C3D file spec](https://www.c3d.org), and be compatible with files from major C3D producing programs (Vicon Nexus, etc.) where they might differ from or extend the C3D file spec.
9+
C3D is a common file format for motion capture and other biomechanics related measurement systems (force plate data, EMG, etc). This package completely implements the [C3D file spec](https://www.c3d.org), and can read files from all major manufacturers where they might differ from or extend the C3D file spec.
1010

11-
Current test data is gathered from sample data found on the [C3D website](https://www.c3d.org/sampledata.html).
12-
Pull requests welcome! Please open an issue if you have a file that is not being read correctly.
11+
C3D.jl is exhaustively tested against sample data found on the [C3D website](https://www.c3d.org/sampledata.html) and can read many technically out-of-spec files.
12+
Please open an issue if you have a file that is not being read correctly. Pull requests welcome!
1313

1414
## Usage
1515

@@ -22,7 +22,7 @@ julia> # The artifacts with the test data can only be used from the `C3D.jl` dir
2222

2323
julia> pc_real = readc3d(artifact"sample01/Eb015pr.c3d")
2424
C3DFile("~/.julia/artifacts/318c299a26ba07c015fa86768512b677fbb7e64c/Eb015pr.c3d")
25-
0:9+0 frames
25+
Duration: 9 s
2626
26 points @ 50 Hz; 16 analog channels @ 200 Hz
2727

2828
julia> pc_real.point["LTH1"]
@@ -46,14 +46,31 @@ julia> pc_real.analog["FZ1"]
4646
-22.32
4747
```
4848

49+
### Writing data
50+
51+
Write a C3D file using the `writec3d` function. The groups and parameters of a .c3d file describe the data contained by the file. As of v0.8, there are no C3D.jl functions that coordinate modifying a `C3DFile` object, therefore, it is your responsibility to ensure that any modifications (adding/removing a marker or analog channel, etc) produce a internally-consistent (i.e. groups/parameters have been correctly updated to match the modified data, etc) file before writing.
52+
53+
```julia
54+
julia> writec3d("myfile.c3d", pc_real)
55+
307200 # number of bytes written
56+
```
57+
58+
Writing c3d files is exhaustively tested against the corpus of sample data from the C3D.org website, and `writec3d` is tested to ensure that all files that are written are functionally[^1] and/or bitwise identical to the original at the binary file level in the vast majority[^2] of cases, and in all cases, the groups, parameters, and data for a `C3DFile` that was "copied" with `writec3d` will be exactly identical to the groups, parameters, and data from the original `C3DFile`.
59+
60+
[^1]: Many manufacturers include unnecessary trailing whitespace in string parameters. C3D.jl strips trailing whitespace when reading .c3d files; this results in slightly different (smaller) parameters when written to file, but the parameter data is otherwise the same.
61+
62+
[^2]: There are only two situations in which the binary data in the file will differ from the original file:
63+
1. Some manufacturers write residuals as unsigned integers; this is incorrect according to the file-spec and C3D.jl follows the spec when writing the residuals back to file. However, the actual residual data is unchanged.
64+
2. Limitations of [floating-point arithmetic](https://en.wikipedia.org/wiki/Floating-point_arithmetic) mean that some analog samples may not convert exactly back after un-scaling (i.e. slightly different in the file), but the scaled values are exactly identical.
65+
4966
#### Point residuals, invalid and calculated points
5067

51-
According to the C3D format documentation, invalid data points are signified by setting the residual word to `-1.0`. This convention is respected in C3D.jl by changing the residual and coordinates of invalid points/frames to `missing`. If your C3D files do not respect this convention, or if you wish to ignore this for some other reason, this behavior can be disabled by setting keyword arg `missingpoints=false` in the `readc3d` function. Convention is to signify calculated points (e.g. filtered, interpolated, etc) by setting the residual word to `0.0`.
68+
According to the C3D format documentation, invalid data points are signified by setting the residual word to `-1.0`. This convention is respected in C3D.jl by changing the residual and coordinates of invalid points/frames to `missing`. If your C3D files do not respect this convention, or if you wish to ignore this for some other reason, this behavior can be disabled by setting keyword arg `missingpoints=false` in the `readc3d` function. Convention is to signify calculated points (e.g. filtered, interpolated, etc) by setting the residual value to `0.0`.
5269

5370
```julia
5471
julia> bball = readc3d(artifact"sample16/basketball.c3d")
5572
C3DFile("~/.julia/artifacts/042cc43a45ace35e97473c6cf0d08e25f1c73fcb/basketball.c3d")
56-
0:1+9 frames
73+
Duration: 1+09 s+ff
5774
22 points @ 25 Hz
5875

5976
julia> bball.point["2003"]
@@ -81,13 +98,13 @@ Point residuals can be accessed using the `residual` field which is indexed by m
8198
```julia
8299
julia> pc_real.residual["RFT2"]
83100
450-element Array{Union{Missing, Float32},1}:
84-
10.333334f0
85-
10.333334f0
86-
9.666667f0
101+
2.0833335f0
102+
2.3333335f0
103+
1.6666667f0
87104
88-
2.0f0
89-
2.0f0
90-
2.0f0
105+
0.6666667f0
106+
1.4166667f0
107+
0.5833334f0
91108
```
92109

93110
### Accessing C3D parameters
@@ -104,7 +121,17 @@ Dict{Symbol,C3D.Group} with 5 entries:
104121
:FPLOC => Symbol[:INT, :OBJ, :MAX]
105122

106123
julia> pc_real.groups[:POINT]
107-
Symbol[:DESCRIPTIONS, :RATE, :DATA_START, :FRAMES, :USED, :UNITS, :Y_SCREEN, :LABELS, :X_SCREEN, :SCALE]
124+
Group(:POINT), "3-D point parameters"
125+
POINT:DESCRIPTIONS::String @ (20,) ["DIST/LAT FOOT", "INSTEP", "PROX LAT FOOT", "SHANK", "SHANK", "SHANK", "SHANK", "ANKLE", "KNEE", "DISTAL FOOT", "*", "*", "*", "*", "*", "*", "*", "*", "*", "TARGET"]
126+
POINT:X_SCREEN::String ["+Y"]
127+
POINT:Y_SCREEN::String ["+Z"]
128+
POINT:LABELS::String @ (48,) ["RFT1", "RFT2", "RFT3", "LFT1", "LFT2", "LFT3", "RSK1", "RSK2", "RSK3", "RSK4" "", "", "", "", "", "", "", "", "", ""]
129+
POINT:UNITS::String ["mm"]
130+
POINT:USED::UInt16 26
131+
POINT:FRAMES::UInt16 450
132+
POINT:SCALE::Float32 -0.0833333
133+
POINT:DATA_START::UInt16 11
134+
POINT:RATE::Float32 50.0
108135
```
109136

110137
Parameter values can be accessed like this:
@@ -123,16 +150,15 @@ julia> pc_real.groups[:POINT][:LABELS]
123150
""
124151
""
125152

126-
julia> # Or, if you know the type (and you need the type-stability)
127-
153+
# Or, if you know the type (and you need the type-stability)
128154
julia> pc_real.groups[:POINT][Int, :USED]
129155
26
130156

131157
```
132158

133159
# Advanced: Debugging
134160

135-
There are two main steps to reading a C3D file: reading the parameters, and reading the point and/or analog data. In the event a file read fails, the stacktrace will show whether the error happened in `_readparams` or `readdata`. If the error occurred in `readdata`, try only reading the parameters, optionally setting the keyword argument `validate` to `false`:
161+
Set the `JULIA_DEBUG` environment variable to `"C3D"` (e.g. from within Julia, `ENV["JULIA_DEBUG"] = "C3D"`) to enable debug logging. In addition, there are two keyword arguments to `readc3d` which may be useful if a file is error'ing when being read: `paramsonly=true` will only read the parameter section and skip reading the data, and `validate=false` will disable parameter validation.
136162

137163
```julia
138164
julia> pc_real = readc3d("data/sample01/Eb015pr.c3d"; paramsonly=true)
@@ -152,12 +178,4 @@ Dict{Symbol,C3D.Group} with 5 entries:
152178
:FPLOC => Symbol[:INT, :OBJ, :MAX]
153179
```
154180

155-
If the error occurred in `readdata`, it is likely that there is an incorrect setting in one of the parameters. (If this is consistent among several files from the same vendor, open an issue and send an example file so I can fix whatever is causing the problem.)
156-
157-
If the error occurred in `_readparams`, try starting julia with `$ JULIA_DEBUG=C3D julia`. This will enable debug messages that may help narrow down the parameter causing the problem.
158-
159-
Please open an issue if you have a file that is being read incorrectly.
160-
161-
## Roadmap
162-
163-
I plan to eventually add support for saving files that have been modified and for creating new files, but this is not a use case that I require currently or in the foreseeable future. If this is important to you, open an issue or submit a PR!
181+
Please open an issue if you have a file that C3D.jl is unable to read.

0 commit comments

Comments
 (0)