MATLAB: Use of the fread function

c3dfread

Hey I'm trying to open .c3d files by the means of the fread function The problem I have is when searching the first frame and the last frame of the file with fread(fid,1,'int16') with fid = 8; If I do it with some non heavy files, I got a startframe = 1 and a endframe =~ 26000 and the script works but if I do it with more heavy files, then I got an enframe =~ -12000 which makes the script wrong and me angry 😉 Sure someone has an idea… Thanks in advance!

Best Answer

When the C3D file format has been invented, large measurement files have been rare and int16 seemed to be a valid range for the number of frames. Many modern software packages use uint16 instead, because a negative number of frames is not valid at all.
I use this to import the header of C3Ds:
I8 = 'int8';
I16 = 'int16';
U16 = 'uint16'; % Signed is not meaningful!
F32 = 'float32';
% Spool to the beginning:
fseek(FID, 0, 'bof');
% Reading record number of parameter section:
Head.ParamRec = fread(FID, 1, I8);
MagicKey = fread(FID, 1, I8);
if isequal(MagicKey, 80) == 0
error(['JSimon:', mfilename, ':BadMagicKey'], 'Bad magic key: %d', MagicKey);
end
% Getting all the necessary parameters from the header record
Head.nCoor = fread(FID, 1, U16); % number of trajectories
Head.AnalogChunk = fread(FID, 1, U16); % analog values per video frame
Head.iFrame = fread(FID, 1, U16); % index of first video frame
Head.fFrame = fread(FID, 1, U16); % index of last video frame
Head.MaxGap = fread(FID, 1, U16); % max allowed interpolation gaps
Scale = fread(FID, 1, F32); % scale integers to ref. units
Head.DataRec = fread(FID, 1, U16); % 1st record of data section
Head.AnalogRate = fread(FID, 1, U16); % analog samples per video frame
Head.VideoFreq = fread(FID, 1, F32); % frequency of video data
% If scale is negative, the data is stored in float format:
Head.FloatMode = (Scale < 0.0);
Head.Scale = abs(Scale);
% Number of frames:
Head.nFrame = Head.fFrame - Head.iFrame + 1;
% Number of analog channels (FRC + EMG + ?):
if Head.AnalogRate % Avoid division by zero:
Head.nAnalog = round(Head.AnalogChunk / Head.AnalogRate);
else
Head.nAnalog = 0;
end
But note, that today even the range of UINT16 is small and e.g. Vicon software write the actual number of frames to the parameter section as TRIAL.ACTUAL_START_FIELD and TRIAL.ACTUAL_END_FIELD. Then we need to modify the values:
End_Field2 = TRIAL.ACTUAL_END_FIELD; % Or how ever you obtain parameters
Start_Field2 = TRIAL.ACTUAL_START_FIELD;
End_Field = End_Field2(1) + 65536 * End_Field2(2);
if ~isequal(End_Field, Head.fFrame)
if Head.fFrame ~= 65535
warning(['GetC3D:', mfilename, ':Unexpected_nFrame'], ...
'Long C3D, but [Head.fFrame] is not 65535?!');
end
Start_Field = Start_Field2(1) + 65536 * Start_Field2(2);
Head.iFrame = Start_Field;
Head.fFrame = End_Field;
Head.nFrame = End_Field - Start_Field + 1;
end