PageRenderTime 28ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/external/fieldtrip/trunk/fileio/private/read_neuralynx_dma.m

http://open-realtime-fmri.googlecode.com/
MATLAB | 280 lines | 175 code | 16 blank | 89 comment | 40 complexity | 74089d797fb0187d136ab5e8bbe77247 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
  1. function [dat] = read_neuralynx_dma(filename, begsample, endsample, channel);
  2. % READ_NEURALYNX_DMA reads specified samples and channels data from a Neuralynx DMA log file
  3. %
  4. % Use as
  5. % [hdr] = read_neuralynx_dma(filename)
  6. % [dat] = read_neuralynx_dma(filename, begsample, endsample)
  7. % [dat] = read_neuralynx_dma(filename, begsample, endsample, chanindx)
  8. %
  9. % The channel specification can be a vector with indices, or a single string with the value
  10. % 'all', 'stx', 'pid', 'siz', 'tsh', 'tsl',
  11. % 'cpu', 'ttl', 'x01', ..., 'x10'
  12. %
  13. % This function returns the electrophysiological data in AD units
  14. % and not in uV. You should look up the details of the headstage and
  15. % the Neuralynx amplifier and scale the values accordingly.
  16. % Copyright (C) 2005-2008, Robert Oostenveld
  17. %
  18. % This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
  19. % for the documentation and details.
  20. %
  21. % FieldTrip is free software: you can redistribute it and/or modify
  22. % it under the terms of the GNU General Public License as published by
  23. % the Free Software Foundation, either version 3 of the License, or
  24. % (at your option) any later version.
  25. %
  26. % FieldTrip is distributed in the hope that it will be useful,
  27. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. % GNU General Public License for more details.
  30. %
  31. % You should have received a copy of the GNU General Public License
  32. % along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
  33. %
  34. % $Id: read_neuralynx_dma.m 2885 2011-02-16 09:41:58Z roboos $
  35. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  36. % The data is simply a stream of constant size records, the size of the
  37. % record is dependant on the number of Input Boards in the system. 8 in your
  38. % case, there are 32 - 32 bit integers from each Input Board.
  39. %
  40. % // Digital Lynx Packets look like this for a 1 board system:
  41. % // stx (or SOP) 0x00000800
  42. % // Packet ID 0x00000001
  43. % // siz 0x0000002A (# A/D data ints + #extra wds = 32+10)
  44. % // TimeStamp Hi 1 32 bit word
  45. % // TimeStamp Low 1 32 bit word
  46. % // cpu 1 32 bit word
  47. % // ttl 1 32 bit word
  48. % // 10 extras 10 32 bit words
  49. % // A/D data 32 32 bit words per board
  50. % // CRC 1 32 bit XOR of the entire packet including stx
  51. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  52. needhdr = (nargin==1);
  53. needdat = (nargin>=2);
  54. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  55. % since Cheetah 4.80 the DMS log files have a 16384 byte header
  56. % determine whether that is the case in this file
  57. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  58. fid = fopen(filename, 'rb', 'ieee-le');
  59. buf = fread(fid, 10, 'uchar=>uchar');
  60. if all(buf(1:4)==35)
  61. % the file starts with "####"
  62. hdroffset = 16384;
  63. elseif all(buf>31 & buf<127)
  64. % the file does not start with "####" but the header seems to be ascii anyway
  65. hdroffset = 16384;
  66. else
  67. hdroffset = 0;
  68. end
  69. if hdroffset
  70. % read the ascii header from the file, it does not contain much usefull information
  71. orig = neuralynx_getheader(filename);
  72. end
  73. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  74. % since Cheetah 5.0 the DMA log file does not always start with a complete
  75. % packet but can start with an incomplete "junk" packet after the header.
  76. % The junk due to that incomplete packet should then also be skipped.
  77. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  78. if hdroffset
  79. % skip the standard ascii header
  80. fseek(fid, hdroffset, 'bof');
  81. % read a single block
  82. buf = fread(fid, 274, 'uint32=>uint32');
  83. % search for the first known values of a proper packet
  84. junk = find((buf(1:(end-1))==2048) & (buf(2:(end-0))==1), 1) - 1;
  85. if ~isempty(junk)
  86. % add the additional junk samples to the header offset
  87. hdroffset = hdroffset + junk*4;
  88. end
  89. end
  90. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  91. % since modifying our hardware from 256 to 32 channel (19 March 2007), the
  92. % number of channels in a DMA log file can vary. Start with the assumption
  93. % that the file is from the 256 channel system with 8 boards that we have
  94. % in Nijmegen and verify the CRC
  95. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  96. nboards = 8;
  97. nchanboard = 32;
  98. blocksize = nboards*nchanboard+18; % in 4 byte words
  99. fseek(fid, hdroffset, 'bof');
  100. % read a single block
  101. buf = fread(fid, blocksize, 'uint32=>uint32');
  102. % determine the number of boards by systematically checking the CRC value
  103. while (nboards>0)
  104. if neuralynx_crc(buf(1:blocksize-1))==buf(blocksize)
  105. % the CRC is correct for this number of boards
  106. break
  107. else
  108. nboards = nboards - 1; % decrease by one
  109. blocksize = nboards*nchanboard+18; % in 4 byte words
  110. end
  111. end
  112. fclose(fid);
  113. if ~nboards
  114. error('could not determine the number of boards and channels');
  115. end
  116. % deal with ascii and numeric input for the channel selection
  117. if nargin>3 && ~ischar(channel)
  118. chanindx = channel;
  119. channel = 'selection';
  120. elseif nargin>3 && ischar(channel)
  121. switch channel
  122. case 'stx'
  123. chanindx = 1;
  124. case 'pid'
  125. chanindx = 2;
  126. case 'siz'
  127. chanindx = 3;
  128. case 'tsh'
  129. chanindx = 4;
  130. case 'tsl'
  131. chanindx = 5;
  132. case 'cpu'
  133. chanindx = 6;
  134. case 'ttl'
  135. chanindx = 7;
  136. case 'x01'
  137. chanindx = 8;
  138. case 'x02'
  139. chanindx = 9;
  140. case 'x03'
  141. chanindx = 10;
  142. case 'x04'
  143. chanindx = 11;
  144. case 'x05'
  145. chanindx = 12;
  146. case 'x06'
  147. chanindx = 13;
  148. case 'x07'
  149. chanindx = 14;
  150. case 'x08'
  151. chanindx = 15;
  152. case 'x09'
  153. chanindx = 16;
  154. case 'x10'
  155. chanindx = 17;
  156. case 'crc'
  157. chanindx = blocksize;
  158. case 'all'
  159. chanindx = 1:blocksize;
  160. otherwise
  161. error('unknown value in channel');
  162. end
  163. elseif nargin<4
  164. channel = 'all';
  165. chanindx = 1:blocksize;
  166. end
  167. if needhdr
  168. % these have to be hardcoded, since the DMA logfile does not contain header information
  169. hdr = [];
  170. if hdroffset
  171. % remember the ascii header from the file, it does not contain much usefull information
  172. hdr.orig = orig;
  173. end
  174. hdr.Fs = 32556; % sampling frequency
  175. hdr.nChans = nboards*nchanboard; % number of analog channels
  176. hdr.nSamples = inf; % number of samples per trial
  177. hdr.nSamplesPre = 0; % number of pre-trigger samples in each trial
  178. hdr.nTrials = 1; % number of trials
  179. hdr.label = {}; % cell-array with labels of each channel
  180. for i=1:hdr.nChans
  181. chanlabel{i} = sprintf('csc%03d', i);
  182. end
  183. statuslabel = {
  184. 'stx'
  185. 'pid'
  186. 'siz'
  187. 'tsh'
  188. 'tsl'
  189. 'cpu'
  190. 'ttl'
  191. 'x01'
  192. 'x02'
  193. 'x03'
  194. 'x04'
  195. 'x05'
  196. 'x06'
  197. 'x07'
  198. 'x08'
  199. 'x09'
  200. 'x10'
  201. };
  202. hdr.label = cat(1, statuslabel(:), chanlabel(:), {'crc'}); % concatenate all channel labels
  203. hdr.nChans = length(hdr.label); % this includes all channels
  204. % determine the length of the file, expressed in samples
  205. fid = fopen(filename, 'rb', 'ieee-le');
  206. fseek(fid, 0, 'eof');
  207. hdr.nSamples = floor((ftell(fid)-hdroffset)/(blocksize*4));
  208. % determine the timestamp of the first and of the last sample
  209. datoffset = 0*blocksize;
  210. fseek(fid, hdroffset + datoffset, 'bof');
  211. buf = fread(fid, blocksize, 'uint32=>uint32');
  212. beg_stx = buf(1);
  213. beg_tsh = buf(4);
  214. beg_tsl = buf(5);
  215. datoffset = (hdr.nSamples-1)*blocksize*4;
  216. fseek(fid, hdroffset + datoffset, 'bof');
  217. buf = fread(fid, blocksize, 'uint32=>uint32');
  218. end_stx = buf(1);
  219. end_tsh = buf(4);
  220. end_tsl = buf(5);
  221. fclose(fid);
  222. % check that the junk at the beginning was correctly detected
  223. if (beg_stx~=2048)
  224. error('problem with STX at the begin of the file');
  225. end
  226. % check that the file is truely continuous, i.e. no gaps with junk in between
  227. if (end_stx~=2048)
  228. error('problem with STX at the end of the file');
  229. end
  230. % combine the two uint32 words into a uint64
  231. hdr.FirstTimeStamp = timestamp_neuralynx(beg_tsl, beg_tsh);
  232. hdr.LastTimeStamp = timestamp_neuralynx(end_tsl, end_tsh);
  233. hdr.TimeStampPerSample = double(hdr.LastTimeStamp-hdr.FirstTimeStamp)./(hdr.nSamples-1); % this should be double, since it can be fractional
  234. % only return the header information
  235. dat = hdr;
  236. dat.orig.Offset = hdroffset;
  237. elseif length(chanindx)>1
  238. % read the desired samples for all channels
  239. fid = fopen(filename, 'rb', 'ieee-le');
  240. datoffset = (begsample-1)*blocksize*4;
  241. fseek(fid, hdroffset + datoffset, 'bof'); % skip the header and samples that do not have to be read
  242. % read the data
  243. dat = fread(fid, [blocksize (endsample-begsample+1)], 'int32=>int32');
  244. fclose(fid);
  245. if size(dat,2)<(endsample-begsample+1)
  246. error('could not read all samples');
  247. end
  248. if ~strcmp(channel, 'all')
  249. % select the subset of desired channels
  250. dat = dat(chanindx,:);
  251. end
  252. elseif length(chanindx)==1
  253. % read the desired samples for only one channel
  254. fid = fopen(filename, 'rb', 'ieee-le');
  255. datoffset = (begsample-1)*blocksize*4;
  256. fseek(fid, hdroffset + datoffset, 'bof'); % skip the header and samples that do not have to be read
  257. fseek(fid, (chanindx-1)*4, 'cof'); % skip to the channel of interest
  258. % Note that the last block with 274*4 bytes can sometimes be incomplete, which is relevant when endsample=inf
  259. dat = fread(fid, [1 (endsample-begsample+1)], 'int32=>int32', (nboards*32+18-1)*4);
  260. if size(dat,2)<(endsample-begsample+1)
  261. error('could not read all samples');
  262. end
  263. fclose(fid);
  264. end