%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%22seaborn%3E%3D0.13%22%2C%20%22urllib3%3E%3D2.2%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()%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%20Open%20AMTI%20.bsf%20file%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%20notebook%0A%0A%20%20%20%20Follow%20the%20recording%20from%20its%20binary%20container%20to%20its%20force%20and%20moment%20channels.%20Run%20the%20cells%2C%20inspect%20the%20headers%2C%20and%20make%20the%20time-axis%20calculation%20yourself%20before%20opening%20each%20worked%20solution.%20Keep%20the%20original%20file%20and%20its%20metadata%20together%20when%20exporting%20a%20derived%20analysis.%0A%0A%20%20%20%20%23%23%20Opening%20challenge%0A%0A%20%20%20%20A%20file%20contains%201000%20rows.%20Is%20that%20one%20second%20of%20movement%2C%20two%20seconds%2C%20or%20something%20else%3F%20Could%20six%20smooth%20curves%20still%20have%20the%20wrong%20units%3F%20By%20the%20end%20you%20should%20be%20able%20to%20justify%20the%20time%20base%2C%20channel%20interpretation%20and%20limits%20of%20this%20reader.%0A%0A%20%20%20%20%23%23%20Setup%0A%0A%20%20%20%20The%20notebook%20uses%20NumPy%2C%20Matplotlib%2C%20seaborn%20and%20the%20repository's%20%60AMTIbsf%60%20reader.%20The%20bundled%20recording%20supplies%20real%20data%3B%20no%20acquisition%20hardware%20or%20commercial%20software%20is%20needed%20to%20run%20the%20example.%20Binary-format%20support%20remains%20specific%20to%20the%20recorded%20version.%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%20This%20example%20reads%20a%20historical%20NetForce%20%60.bsf%60%20acquisition%20from%20an%20%5BAMTI%5D(https%3A%2F%2Fwww.amti.biz%2F)%20force%20platform.%20NetForce%20can%20also%20export%20ASCII%20data.%20The%20format%20history%20discussed%20here%20distinguishes%20version%20100%20(16-bit%20raw%20converter%20values)%20from%20version%20105%20(8-byte%20floating-point%20values).%20These%20are%20file-format%20identifiers%2C%20not%20a%20claim%20about%20the%20latest%20NetForce%20release.%20In%20the%20fully%20conditioned%20version-105%20setup%20used%20here%2C%20values%20are%20already%20in%20engineering%20units%3B%20the%20supplied%20reader%20converts%20force%20and%20moment%20to%20N%20and%20N%20m.%0A%0A%20%20%20%20The%20original%20notebook%20mentioned%20%5BBiomechanical%20ToolKit%5D(https%3A%2F%2Fgithub.com%2FBiomechanical-ToolKit%2FBTKCore)%20as%20a%20reader%20for%20older%20version-100%20files.%20Its%20former%20Google%20Code%20address%20is%20obsolete.%20Consult%20the%20toolkit's%20supported%20formats%20and%20your%20acquisition%20documentation%20rather%20than%20assuming%20every%20%60.bsf%60%20variant%20has%20the%20same%20layout.%20The%20supplied%20%60AMTIbsf.py%60%20explicitly%20targets%20version%20105%3B%20the%20acquisition%20manual%20is%20the%20authority%20for%20other%20formats.%0A%0A%20%20%20%20%60AMTIbsf.py%60%20(code%20at%20the%20end%20of%20this%20notebook)%20is%20a%20Python%20function%20to%20open%20.bsf%20files%20in%20version-105%20format%20and%20extract%20the%20file%20metadata%20and%20data%20from%20force%20platforms.%20The%20function%20signature%20for%20its%20typical%20use%20is%3A%0A%20%20%20%20%60%60%60Python%0A%20%20%20%20from%20AMTIbsf%20import%20loadbsf%0A%20%20%20%20data%2C%20mh%2C%20ih%20%3D%20loadbsf(filename%2C%20plot%3D1%2C%20axs%3DNone)%0A%20%20%20%20%60%60%60%0A%20%20%20%20Where%3A%0A%20%20%20%20-%20filename%2C%20plot%2C%20axs%20are%3A%20string%20with%20path%20and%20name%20of%20the%20file%20to%20be%20opened%3B%20option%20to%20plot%20the%20data%3B%20and%20option%20with%20the%20plot%20axes%20handle.%0A%20%20%20%20-%20data%2C%20mh%2C%20ih%20are%3A%20numpy%20array%20with%20all%20the%20data%3B%20object%20Main%20header%3B%20and%20object%20with%20all%20Instrument%20headers%20(iH%5B0%5D%2C%20iH%5B1%5D%2C%20...).%0A%0A%20%20%20%20Or%20from%20command%20line%3A%0A%20%20%20%20%60%60%60%0A%20%20%20%20python%20AMTIbsf.py%20filename%0A%20%20%20%20%60%60%60%0A%20%20%20%20This%20code%20can%20also%20open%20the%20'shfile'%20memory-mapped%20file%20by%20NetForce%2C%20just%20use%20%60shfile%60%20as%20the%20filename.%0A%0A%20%20%20%20Let's%20see%20this%20function%20in%20action%2C%20first%20load%20the%20scientific%20libraries%3A%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%20numpy%20as%20np%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20%23%20'%25matplotlib%20inline'%20command%20supported%20automatically%20in%20marimo%0A%20%20%20%20import%20seaborn%20as%20sns%0A%20%20%20%20sns.set_context(%22notebook%22%2C%20font_scale%3D1.2%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rc%3D%7B%22lines.linewidth%22%3A%202%2C%20%22lines.markersize%22%3A%208%2C%20%22axes.titlesize%22%3A%20'x-large'%7D)%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%23%20Load%20the%20version-specific%20reader%0A%0A%20%20%20%20The%20helper%20is%20supplied%20with%20this%20repository%3B%20the%20next%20cell%20locates%20it%20and%20imports%20%60loadbsf%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%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.cell%0Adef%20_(repo_file)%3A%0A%20%20%20%20import%20sys%0A%20%20%20%20sys.path.insert(0%2C%20str(repo_file('functions%2FAMTIbsf.py').parent))%20%20%23%20add%20to%20pythonpath%0A%0A%20%20%20%20from%20AMTIbsf%20import%20loadbsf%0A%0A%20%20%20%20return%20(loadbsf%2C)%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%20%E2%80%94%20inspect%20before%20decoding.**%20A%20format%20stores%20six%20channels%20as%208-byte%20doubles%20for%201000%20samples.%20How%20many%20bytes%20belong%20to%20the%20sample%20payload%2C%20excluding%20all%20headers%3F%20Why%20is%20total%20file%20size%20not%20a%20reliable%20sample%20count%20by%20itself%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Worked%20solution%20%E2%80%94%20Exercise%201%20%E2%80%94%20inspect%20before%20decoding%0A%0A%20%20%20%20The%20payload%20is%20%241000%5Ctimes6%5Ctimes8%3D48000%24%20bytes.%20Headers%2C%20instrument%20records%20and%20any%20additional%20sections%20also%20occupy%20bytes.%20Read%20the%20format%20metadata%20before%20assigning%20sample%20boundaries.%0A%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%23%20Open%20the%20recording%20and%20inspect%20its%20channels%0A%0A%20%20%20%20Before%20interpreting%20a%20curve%2C%20predict%20how%20many%20columns%20one%20six-component%20platform%20should%20supply.%20The%20example%20opens%20the%20retained%20%60AMTIdata.bsf%60%20fixture%20with%20plotting%20enabled.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(loadbsf%2C%20repo_file)%3A%0A%20%20%20%20data%2C%20mh%2C%20ih%20%3D%20loadbsf(filename%3Dstr(repo_file('data%2FAMTIdata.bsf'))%2C%20plot%3D1)%0A%20%20%20%20return%20ih%2C%20mh%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%20%E2%80%94%20construct%20time.**%20Use%20%60mh.rate%60%20and%20%60data.shape%5B0%5D%60%20to%20construct%20sample%20times%20starting%20at%20zero.%20Distinguish%20the%20final%20timestamp%20from%20the%20duration%20represented%20by%20the%20sample%20count.%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Worked%20solution%20%E2%80%94%20Exercise%202%20%E2%80%94%20construct%20time%0A%0A%20%20%20%20Use%20%60np.arange(data.shape%5B0%5D)%20%2F%20mh.rate%60.%20This%20file%20has%201000%20samples%20at%20500%20Hz%3A%20the%20interval%20is%200.002%20s%2C%20the%20last%20timestamp%20is%201.998%20s%2C%20and%20%24N%2Ff_s%3D2%24%20s%20describes%20the%20record%20length%20in%20sample%20intervals.%20There%20are%20only%20999%20intervals%20between%20first%20and%20last%20sample%20centres.%0A%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%20The%20headers%20(metadata%20from%20the%20.bsf%20file)%20are%20objects%20of%20the%20class%20AMTIbsf.%20You%20can%20visualize%20all%20the%20information%20from%20the%20headers%20typing%20for%20instance%20%60mh%60%20or%20ih%5B0%5D.%20Each%20information%20can%20be%20accessed%20as%20a%20property%20of%20the%20header%20typing%20for%20instance%20%60mh.rate%60.%20The%20headers%20can%20also%20be%20accessed%20as%20dictionaries%20typing%20for%20instance%20%60mh.__dict__%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mh)%3A%0A%20%20%20%20mh.rate%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mh)%3A%0A%20%20%20%20mh%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ih)%3A%0A%20%20%20%20ih%5B0%5D.__dict__%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%20-%20Which%20header%20field%20establishes%20time%20spacing%3F%20Does%20an%20instrument's%20own%20%60rate%3D0%60%20override%20the%20main%20recording%20rate%3F%0A%20%20%20%20-%20Why%20should%20engineering-unit%20data%20not%20be%20multiplied%20by%20the%20factory%20calibration%20a%20second%20time%3F%0A%20%20%20%20-%20What%20information%20would%20you%20retain%20when%20saving%20the%20array%20in%20another%20format%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Checkpoint%20answers%0A%0A%20%20%20%20The%20supplied%20file%20uses%20the%20main%20header's%20%60mh.rate%3D500%60%3B%20inspect%20format%20semantics%20before%20substituting%20another%20header%20field.%20A%20second%20calibration%20would%20alter%20values%20already%20converted%20by%20the%20acquisition%2Freader.%20Retain%20sample%20rate%2C%20channel%20identities%2Forder%2C%20units%2C%20reference%20frame%2C%20instrument%20information%2C%20file%20version%20and%20provenance%20alongside%20the%20samples.%0A%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%20Function%20%60AMTIbsf.py%60%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20repo_file)%3A%0A%20%20%20%20mo.ui.code_editor(repo_file(%22functions%2FAMTIbsf.py%22).read_text()%2C%20language%3D%22python%22%2C%20disabled%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%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%201.%20For%20the%20supplied%20file%2C%20report%20array%20shape%2C%20sampling%20interval%2C%20final%20timestamp%20(time%20starts%20at%20zero)%2C%20and%20peak%20value%20in%20column%202%20when%20interpreted%20as%20%24F_z%24.%0A%20%20%20%202.%20An%20otherwise%20identical%20recording%20has%202400%20samples%20at%201200%20Hz.%20Report%20the%20record%20duration%20%24N%2Ff_s%24%20and%20final%20timestamp.%0A%20%20%20%203.%20You%20receive%20a%20version-100%20raw-integer%20file.%20Is%20changing%20the%20filename%20in%20this%20example%20sufficient%20to%20guarantee%20engineering-unit%20output%3F%20State%20the%20necessary%20next%20step.%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Final%20answers%20to%20the%20problems%0A%0A%20%20%20%201.%20%60(1000%2C%206)%60%3B%200.002%20s%3B%201.998%20s%3B%20approximately%20737.969%20N.%0A%20%20%20%202.%202%20s%3B%201.999167%20s.%0A%20%20%20%203.%20No.%20Use%20a%20version-100-capable%20reader%20and%20the%20documented%20calibration%2Fchannel%20metadata%2C%20or%20obtain%20a%20documented%20engineering-unit%20export%20from%20the%20acquisition%20software.%0A%0A%20%20%20%20%2F%2F%2F%0A%0A%20%20%20%20%23%23%20Go%20deeper%0A%0A%20%20%20%20Compare%20a%20vendor%20ASCII%20export%20with%20this%20reader%20channel%20by%20channel%2C%20including%20sample%20count%2C%20units%20and%20signs.%20A%20numerical%20match%20is%20a%20stronger%20validation%20than%20two%20similar-looking%20plots.%20The%20historical%20%60shfile%60%20memory-mapped%20option%20in%20the%20reader%20is%20a%20separate%20acquisition%20mode%3B%20it%20is%20not%20used%20by%20this%20saved-file%20example.%0A%0A%20%20%20%20%23%23%23%20Video%20lectures%20on%20the%20Internet%0A%0A%20%20%20%20-%20%5BMIT%208.01SC%20Classical%20Mechanics%5D(https%3A%2F%2Focw.mit.edu%2Fcourses%2F8-01sc-classical-mechanics-fall-2016%2F)%20%E2%80%94%20use%20the%20force%20and%20torque%20lessons%20to%20interpret%20the%20six%20physical%20channels.%20These%20lessons%20supply%20mechanics%20background%2C%20not%20instructions%20for%20the%20proprietary%20binary%20format.%0A%0A%20%20%20%20%23%23%20References%0A%0A%20%20%20%20-%20%5BBMC's%20AMTI%20version-105%20reader%5D(https%3A%2F%2Fgithub.com%2FBMClab%2FBMC%2Fblob%2Fmaster%2Ffunctions%2FAMTIbsf.py)%20%E2%80%94%20source%20and%20format%20assumptions%20used%20by%20this%20example.%0A%0A%20%20%20%20-%20%5BAMTI%5D(https%3A%2F%2Fwww.amti.biz%2F)%20%E2%80%94%20obtain%20the%20documentation%20for%20the%20actual%20acquisition%20system%20and%20file%20version.%0A%0A%20%20%20%20-%20%5BBiomechanical%20ToolKit%20source%5D(https%3A%2F%2Fgithub.com%2FBiomechanical-ToolKit%2FBTKCore)%20and%20%5Bdocumentation%5D(https%3A%2F%2Fbiomechanical-toolkit.github.io%2Fdocs%2F)%20%E2%80%94%20preserved%20alternative-reader%20context%20from%20the%20original%20guide.%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
035014a06b55834df8c6fad3858f1ceb