%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%22marimo%3E%3D0.23.9%22%2C%20%22numpy%3E%3D2.0%22%2C%20%22matplotlib%3E%3D3.9%22%2C%20%22pandas%3E%3D2.2%22%2C%20%22urllib3%3E%3D2.2%22%2C%20%22c3d%3E%3D0.6%22%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.25.2%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Read%20C3D%20data%20into%20labelled%20tables%0A%0A%20%20%20%20%3E%20Marcos%20Duarte%2C%20Renato%20Naville%20Watanabe%3Cbr%3E%0A%20%20%20%20%3E%20%5BLaboratory%20of%20Biomechanics%20and%20Motor%20Control%5D(https%3A%2F%2Fbmclab.pesquisa.ufabc.edu.br%2F)%3Cbr%3E%0A%20%20%20%20%3E%20Federal%20University%20of%20ABC%2C%20Brazil%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20How%20to%20use%20this%20guide%0A%0A%20%20%20%20A%20motion-capture%20recording%20contains%20both%20marker%20positions%20and%20analog%20channels.%20Why%20do%20their%20tables%20have%20different%20row%20counts%3F%0A%0A%20%20%20%20We%20will%20read%20the%20same%20synchronized%20recording%20into%20two%20pandas%20tables%20and%20inspect%20units%2C%20labels%2C%20missing%20points%2C%20and%20sampling%20rates.%0A%0A%20%20%20%20Predict%20the%20result%20before%20running%20each%20example.%20Try%20the%20**Exercises**%20before%20opening%20their%20worked%20solutions.%20Finish%20with%20the%20**Checkpoint%20questions**%20and%20**Problems**%3B%20the%20latter%20provide%20final%20answers%20only.%0A%0A%20%20%20%20Open%20this%20file%20locally%20in%20marimo%2C%20on%20%5Bmarimo.app%5D(https%3A%2F%2Fmarimo.app%2F)%2C%20or%20in%20%5Bmolab%5D(https%3A%2F%2Fmolab.marimo.io%2Fnotebooks).%20The%20example%20is%20%60data%2FGait.c3d%60%2C%20distributed%20with%20this%20repository.%20Local%20files%20take%20precedence%3B%20otherwise%20the%20same%20public%20recording%20is%20downloaded.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Python%20setup%0A%0A%20%20%20%20The%20pure-Python%20%60c3d%60%20package%20decodes%20the%20file%2C%20NumPy%20handles%20arrays%2C%20pandas%20labels%20them%2C%20and%20Matplotlib%20plots%20them.%20The%20readers%20are%20included%20in%20this%20notebook%20so%20a%20single-file%20cloud%20session%20can%20run%20it.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20return%20mo%2C%20plt%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20from%20notebook_resources%20import%20repo_file%0A%20%20%20%20except%20ModuleNotFoundError%20as%20_error%3A%0A%20%20%20%20%20%20%20%20if%20_error.name%20!%3D%20%22notebook_resources%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%0A%20%20%20%20%20%20%20%20raise%20ModuleNotFoundError(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22This%20notebook%20needs%20notebook_resources.py.%20Download%20it%20from%3A%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22https%3A%2F%2Fraw.githubusercontent.com%2FBMClab%2FBMC%2Fmaster%2Ffunctions%2Fnotebook_resources.py%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Save%20it%20in%20the%20same%20folder%20as%20this%20notebook%2C%20then%20rerun%20this%20cell.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22notebook_resources%22%2C%0A%20%20%20%20%20%20%20%20)%20from%20None%0A%20%20%20%20return%20(repo_file%2C)%0A%0A%0A%40app.function%0Adef%20load_c3d(path)%3A%0A%20%20%20%20%22%22%22Return%20metadata%2C%20marker%20coordinates%2C%20and%20calibrated%20analog%20samples.%0A%0A%20%20%20%20Times%20are%20seconds%20relative%20to%20the%20first%20recorded%20point%20frame.%20Negative%0A%20%20%20%20residuals%20mark%20invalid%20points%3B%20a%20zero%20coordinate%20is%20a%20valid%20measurement.%0A%20%20%20%20Analog%20scaling%20is%20performed%20once%20by%20c3d.Reader.%20Analog%20channels%20are%20not%0A%20%20%20%20assumed%20to%20be%20force%20components%20or%20rotated%20in%20arbitrary%20groups%20of%20three.%0A%20%20%20%20%22%22%22%0A%20%20%20%20import%20c3d%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%0A%20%20%20%20def%20normalized_labels(reader%2C%20group%2C%20used)%3A%0A%20%20%20%20%20%20%20%20%23%20USED%20defines%20data%20width%3B%20LABELS%20can%20legally%20be%20shorter%20or%20longer.%0A%20%20%20%20%20%20%20%20labels%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20suffix%20%3D%20%22%22%0A%20%20%20%20%20%20%20%20while%20len(labels)%20%3C%20used%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20parameter%20%3D%20reader.get(f%22%7Bgroup%7D%3ALABELS%7Bsuffix%7D%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20parameter%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20labels.extend(parameter.string_array)%0A%20%20%20%20%20%20%20%20%20%20%20%20suffix%20%3D%202%20if%20suffix%20%3D%3D%20%22%22%20else%20suffix%20%2B%201%0A%20%20%20%20%20%20%20%20labels%20%3D%20%5Bstr(label).strip(%22%20%5Ct%5Cr%5Cn%5Cx00%22)%20for%20label%20in%20labels%5B%3Aused%5D%5D%0A%20%20%20%20%20%20%20%20labels.extend(%5B%22%22%5D%20*%20(used%20-%20len(labels)))%0A%20%20%20%20%20%20%20%20reserved%20%3D%20set(labels)%0A%20%20%20%20%20%20%20%20seen%20%3D%20set()%0A%20%20%20%20%20%20%20%20result%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20index%2C%20label%20in%20enumerate(labels)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20base%20%3D%20label%20or%20f%22%7Bgroup%7D_%7Bindex%20%2B%201%7D%22%0A%20%20%20%20%20%20%20%20%20%20%20%20candidate%20%3D%20base%0A%20%20%20%20%20%20%20%20%20%20%20%20number%20%3D%202%0A%20%20%20%20%20%20%20%20%20%20%20%20while%20candidate%20in%20seen%20or%20(candidate%20!%3D%20label%20and%20candidate%20in%20reserved)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20candidate%20%3D%20f%22%7Bbase%7D_%7Bnumber%7D%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20number%20%2B%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20result.append(candidate)%0A%20%20%20%20%20%20%20%20%20%20%20%20seen.add(candidate)%0A%20%20%20%20%20%20%20%20return%20result%0A%0A%20%20%20%20with%20open(path%2C%20%22rb%22)%20as%20handle%3A%0A%20%20%20%20%20%20%20%20reader%20%3D%20c3d.Reader(handle)%0A%20%20%20%20%20%20%20%20frames%20%3D%20list(reader.read_frames())%0A%20%20%20%20%20%20%20%20if%20not%20frames%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22The%20C3D%20file%20contains%20no%20data%20frames%22)%0A%20%20%20%20%20%20%20%20point_labels%20%3D%20normalized_labels(reader%2C%20%22POINT%22%2C%20reader.point_used)%0A%20%20%20%20%20%20%20%20analog_labels%20%3D%20normalized_labels(reader%2C%20%22ANALOG%22%2C%20reader.analog_used)%0A%20%20%20%20%20%20%20%20units%20%3D%20reader.get(%22POINT%3AUNITS%22)%0A%20%20%20%20%20%20%20%20event_used%20%3D%20reader.get(%22EVENT%3AUSED%22)%0A%20%20%20%20%20%20%20%20events%20%3D%20reader.get(%22EVENT%3ALABELS%22)%0A%20%20%20%20%20%20%20%20event_times%20%3D%20reader.get(%22EVENT%3ATIMES%22)%0A%20%20%20%20%20%20%20%20info%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22point_rate%22%3A%20float(reader.point_rate)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22analog_rate%22%3A%20float(reader.analog_rate)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22first_frame%22%3A%20int(reader.first_frame)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22frames%22%3A%20len(frames)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22point_units%22%3A%20units.string_value.strip().strip(%22%5Cx00%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20units%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%22unspecified%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22analog_units%22%3A%20list(reader.get(%22ANALOG%3AUNITS%22).string_array)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20reader.get(%22ANALOG%3AUNITS%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%5B%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22parameter_groups%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%5Bkey%20for%20key%2C%20_%20in%20group.param_items()%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20name%2C%20group%20in%20reader.group_items()%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22events%22%3A%20list(events.string_array)%20if%20events%20else%20%5B%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22event_times%22%3A%20event_times.float_array.tolist()%20if%20event_times%20else%20%5B%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22event_count%22%3A%20int(event_used.int16_value)%20if%20event_used%20else%200%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20all_points%20%3D%20np.stack(%5Bpoints%20for%20_%2C%20points%2C%20_%20in%20frames%5D)%0A%20%20%20%20%20%20%20%20xyz%20%3D%20all_points%5B%3A%2C%20%3A%2C%20%3A3%5D.copy()%0A%20%20%20%20%20%20%20%20xyz%5Ball_points%5B%3A%2C%20%3A%2C%203%5D%20%3C%200%5D%20%3D%20np.nan%0A%20%20%20%20%20%20%20%20columns%20%3D%20pd.MultiIndex.from_product(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5Bpoint_labels%2C%20list(%22XYZ%22)%5D%2C%20names%3D%5B%22Marker%22%2C%20%22Coordinate%22%5D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20points%20%3D%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%20%20%20%20xyz.reshape(len(frames)%2C%20-1)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20columns%3Dcolumns%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20index%3Dnp.arange(len(frames))%20%2F%20reader.point_rate%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20if%20reader.analog_used%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20samples%20%3D%20np.concatenate(%5Banalog%20for%20_%2C%20_%2C%20analog%20in%20frames%5D%2C%20axis%3D1).T%0A%20%20%20%20%20%20%20%20%20%20%20%20analog%20%3D%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20samples%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20columns%3Danalog_labels%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3Dnp.arange(len(samples))%20%2F%20reader.analog_rate%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20analog%20%3D%20pd.DataFrame()%0A%20%20%20%20points.index.name%20%3D%20analog.index.name%20%3D%20%22Time%20%5Bs%5D%22%0A%20%20%20%20return%20info%2C%20points%2C%20analog%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Read%20one%20synchronized%20acquisition%0A%0A%20%20%20%20This%20guide%20replaces%20the%20old%20native%20EZC3D%20example%20and%20unavailable%20private%20path%20with%20a%20portable%20reader%20and%20a%20public%20fixture.%20%60load_c3d%60%20returns%20metadata%2C%20point%20coordinates%2C%20and%20analog%20samples.%20It%20keeps%20the%20calibrated%20analog%20values%20supplied%20by%20the%20reader%3B%20do%20not%20apply%20the%20scale%20factors%20a%20second%20time.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(repo_file)%3A%0A%20%20%20%20info%2C%20pt%2C%20an%20%3D%20load_c3d(repo_file(%22data%2FGait.c3d%22))%0A%20%20%20%20info%0A%20%20%20%20return%20an%2C%20pt%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Exercise%201.**%20For%20point%20rate%20100%20Hz%20and%20analog%20rate%201%2C000%20Hz%2C%20how%20many%20analog%20samples%20belong%20to%20one%20point%20frame%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%201%0A%0A%20%20%20%20There%20are%20%241000%2F100%3D10%24%20analog%20samples%20per%20point%20frame.%20Align%20using%20time%2C%20not%20equal%20row%20numbers.%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pt)%3A%0A%20%20%20%20pt.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(an)%3A%0A%20%20%20%20an.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Select%20coordinates%20and%20channels%0A%0A%20%20%20%20The%20point%20columns%20have%20two%20levels%3A%20marker%20and%20coordinate.%20The%20analog%20columns%20retain%20channel%20names.%20Repeated%20labels%20receive%20a%20numeric%20suffix%20so%20selection%20is%20unambiguous.%20Positions%20use%20the%20point%20units%20in%20the%20metadata%3B%20analog%20units%20can%20differ%20by%20channel.%20A%20channel%20measured%20in%20volts%20is%20not%20automatically%20a%20force.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pt)%3A%0A%20%20%20%20pt.loc%5B%3A%2C%20(%22RASI%22%2C%20%22X%22)%5D.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(an)%3A%0A%20%20%20%20an%5B%5B%22F1Z%22%2C%20%22F2Z%22%5D%5D.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Exercise%202.**%20Should%20a%20point%20with%20X%3D0%20be%20marked%20missing%3F%20What%20evidence%20does%20the%20reader%20use%20instead%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%202%0A%0A%20%20%20%20No%3A%20the%20coordinate%20origin%20may%20pass%20through%20a%20valid%20point.%20A%20negative%20C3D%20residual%20flags%20invalid%20point%20data.%20The%20reader%20marks%20all%20three%20coordinates%20of%20that%20point%20NaN%2C%20while%20preserving%20valid%20zero%20values.%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(an%2C%20plt%2C%20pt)%3A%0A%20%20%20%20_fig%2C%20_axs%20%3D%20plt.subplots(2%2C%201%2C%20sharex%3DTrue%2C%20figsize%3D(9%2C%205))%0A%20%20%20%20pt.loc%5B%3A%2C%20(%22RASI%22%2C%20%22X%22)%5D.plot(ax%3D_axs%5B0%5D)%0A%20%20%20%20an%5B%5B%22F1Z%22%2C%20%22F2Z%22%5D%5D.plot(ax%3D_axs%5B1%5D)%0A%20%20%20%20_axs%5B0%5D.set_ylabel(%22Position%20%5Bmm%5D%22)%0A%20%20%20%20_axs%5B1%5D.set_ylabel(%22Force%20%5BN%5D%22)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Checkpoint%20questions%0A%0A%20%20%20%201.%20Why%20are%20force%20and%20marker%20rows%20not%20interchangeable%3F%0A%0A%20%20%20%202.%20Do%20analog%20channels%20always%20come%20in%20XYZ%20triplets%3F%0A%0A%20%20%20%203.%20What%20defines%20time%20zero%20in%20these%20tables%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Checkpoint%20answers%0A%0A%20%20%20%201.%20Their%20sample%20rates%20differ.%0A%20%20%20%202.%20No%3B%20they%20may%20contain%20forces%2C%20moments%2C%20EMG%20voltages%2C%20or%20other%20signals.%0A%20%20%20%203.%20The%20first%20recorded%20point%20frame.%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Problems%0A%0A%20%20%20%20Try%20these%20independently%3B%20open%20a%20panel%20only%20to%20check%20your%20final%20answer.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Problem%201.**%20How%20many%20analog%20rows%20correspond%20to%20487%20point%20frames%20when%20the%20rate%20ratio%20is%2010%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Answer%20to%20Problem%201%0A%0A%20%20%20%204%2C870.%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Problem%202.**%20What%20is%20the%20interval%20between%20marker%20rows%20at%20100%20Hz%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Answer%20to%20Problem%202%0A%0A%20%20%20%200.01%20s.%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Go%20deeper%0A%0A%20%20%20%20Use%20the%20%5BC3D%20format%20guide%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Fopen_c3d_file.py)%20to%20inspect%20the%20binary%20header%20and%20browse%20marker%20frames.%20The%20%5Bpandas%20guide%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Fpandas_data.py)%20expands%20on%20labelled%20selection.%0A%0A%20%20%20%20%23%23%23%20Video%20lectures%20on%20the%20Internet%0A%0A%20%20%20%20%5BOpenSim%20webinar%20archive%5D(https%3A%2F%2Fopensim.stanford.edu%2Fsupport%2Fevent_details.php%3Fid%3D30)%20provides%20motion-analysis%20context.%20%5BMIT%20Signals%20and%20Systems%20lectures%5D(https%3A%2F%2Focw.mit.edu%2Fcourses%2Fres-6-007-signals-and-systems-spring-2011%2Fvideo_galleries%2Fvideo-lectures%2F)%20explain%20the%20sampling-rate%20distinction%20used%20here.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20References%0A%0A%20%20%20%20-%20%5BC3D%20technical%20user%20guide%5D(https%3A%2F%2Fc3d.org%2Fdocs%2FC3D_User_Guide.pdf).%0A%0A%20%20%20%20-%20%5BPython%20c3d%20reader%5D(https%3A%2F%2Fgithub.com%2FEmbodiedCognition%2Fpy-c3d).%0A%0A%20%20%20%20-%20%5BC3D%20example%20data%5D(https%3A%2F%2Fwww.c3d.org%2Fsampledata.html).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
c753ad325b17a12f5b1162430e7ed6bb