Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

saveNSx.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. function saveNSx(NSx,varargin)
  2. %%
  3. % Save an .NSx file from an NSx structure (gained by using openNSx)
  4. % Works with file spec 2.3 and 3.0
  5. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  6. % Use: saveNSx(NSx,optionalinputarguments)
  7. % NSx: The NSx data structure.
  8. % All arguments below are optional:
  9. % Filename: A complete filepath for the output file.
  10. % Default: CurrentFilename-Modified.NSx
  11. % Filespec: Save the file using the filespec specified e.g. 2.3 or 3.0
  12. % Default: same as the filespec loaded
  13. %saveNSx version = '1.0.0.1';
  14. % Version History
  15. %
  16. % 1.0.0.1:
  17. % - Added ability to save to a specific filespec
  18. %
  19. %%
  20. % Verify FilePath and establish overwrite paramaters
  21. FilePath = [fullfile(NSx.MetaTags.FilePath,NSx.MetaTags.Filename) '-modified' NSx.MetaTags.FileExt];
  22. if length(varargin) >= 1
  23. if not(isempty(varargin{1}))
  24. FilePath = varargin{1};
  25. end
  26. end
  27. % save to a specific filespec
  28. if length(varargin) >= 2
  29. if (varargin{2} == 2.3)
  30. NSx.MetaTags.FileTypeID(1:8) = 'NEURALCD';
  31. NSx.MetaTags.FileSpec(1:3) = '2.3';
  32. end
  33. if (varargin{2} == 3.0)
  34. NSx.MetaTags.FileTypeID(1:8) = 'BRSMPGRP';
  35. NSx.MetaTags.FileSpec(1:3) = '3.0';
  36. end
  37. end
  38. disp('This script will save a new file with the proper .NSx extensions');
  39. disp('but you should retain the previous file. Do you acknowledge the');
  40. Accept = input('risk inherent in saving modified versions of data files? (Y/N)','s');
  41. if strcmpi(Accept,'y')
  42. else
  43. disp('Ending Script...');
  44. return
  45. end
  46. %%
  47. % Write the basic header into the file
  48. %FullFile
  49. Debug = 0;
  50. if exist(FilePath)
  51. if exist(FilePath)
  52. disp('File already exists!');
  53. OverwritePrompt = input('Would you like to overwrite? (Y/N)','s');
  54. if strcmpi(OverwritePrompt,'y')
  55. Overwrite = 1;
  56. delete(FilePath);
  57. else
  58. return
  59. end
  60. end
  61. end
  62. clear Overwrite
  63. clear OverwritePrompt
  64. clear varargin
  65. %PausedFile?
  66. if iscell(NSx.Data)
  67. Paused = 1;
  68. NumberOfSegments = length(NSx.Data);
  69. else
  70. Paused = 0;
  71. end
  72. FileID = fopen(FilePath, 'w', 'ieee-le');
  73. %Basic header stuff
  74. BytesInBasicHeader = 8+2+4+16+256+4+4+16+4;
  75. BytesInExtendedHeader = 2+2+16+1+1+2+2+2+2+16+4+4+2+4+4+2;
  76. if Paused == 1
  77. for SegmentCount = 1:NumberOfSegments
  78. [NumberOfChannels,LengthOfData{SegmentCount}] = size(NSx.Data{SegmentCount});
  79. end
  80. elseif Paused == 0
  81. [NumberOfChannels,LengthOfData] = size(NSx.Data);
  82. end
  83. %Identify filespec
  84. fspec = NSx.MetaTags.FileTypeID(1:8);
  85. if strcmp(fspec,'BRSMPGRP')
  86. tspres = 'uint64';
  87. else
  88. tspres = 'uint32';
  89. end
  90. %File Type ID
  91. Before = 0;
  92. fwrite(FileID,fspec);
  93. After = ftell(FileID);
  94. if After-Before ~= 8 && Debug == 1
  95. disp('error FildID')
  96. end
  97. %File spec
  98. Before = ftell(FileID);
  99. fwrite(FileID, [str2double(NSx.MetaTags.FileSpec(1)) str2double(NSx.MetaTags.FileSpec(3))], 'uint8');
  100. After = ftell(FileID);
  101. if After-Before ~= 2 && Debug == 1
  102. disp('error File Spec')
  103. end
  104. %Bytes in Headers
  105. Before = ftell(FileID);
  106. fwrite(FileID, BytesInBasicHeader+NumberOfChannels*BytesInExtendedHeader,'uint32');
  107. After = ftell(FileID);
  108. if After-Before ~= 4 && Debug == 1
  109. disp('error BytesInHeaders')
  110. end
  111. %Label
  112. Before = ftell(FileID);
  113. fwrite(FileID, NSx.MetaTags.SamplingLabel);
  114. After = ftell(FileID);
  115. if After-Before ~= 16 && Debug == 1
  116. disp('error label')
  117. end
  118. %Comment
  119. Before = ftell(FileID);
  120. if ~isempty(NSx.MetaTags.Comment)
  121. fwrite(FileID, NSx.MetaTags.Comment);
  122. else
  123. fwrite(FileID, repmat(' ', 1, 256));
  124. end
  125. After = ftell(FileID);
  126. if After-Before ~= 256 && Debug == 1
  127. disp('error comment')
  128. end
  129. %Period
  130. Before = ftell(FileID);
  131. fwrite(FileID, (1/NSx.MetaTags.SamplingFreq)*30000, 'uint32');
  132. After = ftell(FileID);
  133. if After-Before ~= 4 && Debug == 1
  134. disp('error period')
  135. end
  136. %Time Resolution of time stamps
  137. Before = ftell(FileID);
  138. fwrite(FileID, NSx.MetaTags.TimeRes,'uint32');
  139. After = ftell(FileID);
  140. if After-Before ~= 4 && Debug == 1
  141. disp('error time resolution')
  142. end
  143. %Time Origin
  144. Before = ftell(FileID);
  145. if ~isempty(NSx.MetaTags.DateTimeRaw)
  146. fwrite(FileID, NSx.MetaTags.DateTimeRaw,'uint16');
  147. else
  148. fwrite(FileID, [1900 1 1 0 0 0 0 0],'uint16');
  149. end
  150. After = ftell(FileID);
  151. if After-Before ~= 16 && Debug == 1
  152. disp('error Time Origin')
  153. end
  154. %Channel Count
  155. Before = ftell(FileID);
  156. fwrite(FileID, NumberOfChannels,'uint32');
  157. After = ftell(FileID);
  158. if After-Before ~= 4 && Debug == 1
  159. disp('error Channel Count')
  160. end
  161. %Extended header stuff
  162. %Number of these equal to number of channels
  163. for i = 1:NumberOfChannels
  164. % Type
  165. Before = ftell(FileID);
  166. fwrite(FileID, 'CC');
  167. After = ftell(FileID);
  168. if After-Before ~= 2 && Debug == 1
  169. disp('error Type')
  170. end
  171. % ElectrodeID
  172. Before = ftell(FileID);
  173. try
  174. fwrite(FileID, NSx.ElectrodesInfo(i).ElectrodeID,'uint16');
  175. catch
  176. fwrite(FileID, i,'uint16');
  177. end
  178. After = ftell(FileID);
  179. if After-Before ~= 2 && Debug == 1
  180. disp('error ElectrodeID')
  181. end
  182. % Electrode label
  183. Before = ftell(FileID);
  184. try
  185. fwrite(FileID, NSx.ElectrodesInfo(i).Label);
  186. catch
  187. templabel = ['chan' num2str(i) ' '];
  188. templabel(17:end) = [];
  189. fwrite(FileID, templabel);
  190. end
  191. After = ftell(FileID);
  192. if After-Before ~= 16 && Debug == 1
  193. disp('error Electrode Label')
  194. end
  195. % Physical connector
  196. Before = ftell(FileID);
  197. try
  198. fwrite(FileID, NSx.ElectrodesInfo(i).ConnectorBank, 'uint8');
  199. catch
  200. if i > 0 && i <= 32
  201. fwrite(FileID, 1, 'uint8');
  202. elseif i > 32 && i <= 64
  203. fwrite(FileID, 2, 'uint8');
  204. elseif i > 64 && i <= 96
  205. fwrite(FileID, 3, 'uint8');
  206. elseif i > 96 && i <= 128
  207. fwrite(FileID, 4, 'uint8');
  208. end
  209. end
  210. After = ftell(FileID);
  211. if After-Before ~= 1 && Debug == 1
  212. disp('error Physical Connector')
  213. end
  214. %Physical pin
  215. Before = ftell(FileID);
  216. try
  217. fwrite(FileID, NSx.ElectrodesInfo(i).ConnectorPin, 'uint8');
  218. catch
  219. fwrite(FileID, int2str((i-floor(i/32)*32)), 'uint8');
  220. end
  221. After = ftell(FileID);
  222. if After-Before ~= 1 && Debug == 1
  223. disp('error Physical Pin')
  224. end
  225. %Min Digital Value
  226. Before = ftell(FileID);
  227. try
  228. fwrite(FileID, NSx.ElectrodesInfo(i).MinDigiValue,'int16');
  229. catch
  230. fwrite(FileID, -32764,'int16');
  231. end
  232. After = ftell(FileID);
  233. if After-Before ~= 2 && Debug == 1
  234. disp('error min Digital Value')
  235. end
  236. %Max Digital Value
  237. Before = ftell(FileID);
  238. try
  239. fwrite(FileID, NSx.ElectrodesInfo(i).MaxDigiValue,'int16');
  240. catch
  241. fwrite(FileID, 32764,'int16');
  242. end
  243. After = ftell(FileID);
  244. if After-Before ~= 2 && Debug == 1
  245. disp('error Max Digital value')
  246. end
  247. %Min Analog Value
  248. Before = ftell(FileID);
  249. try
  250. fwrite(FileID, NSx.ElectrodesInfo(i).MinAnalogValue,'int16');
  251. catch
  252. fwrite(FileID, -8191,'int16');
  253. end
  254. After = ftell(FileID);
  255. if After-Before ~= 2 && Debug == 1
  256. disp('error Min Analog Value')
  257. end
  258. %Max Analog Value
  259. Before = ftell(FileID);
  260. try
  261. fwrite(FileID, NSx.ElectrodesInfo(i).MaxAnalogValue,'int16');
  262. catch
  263. fwrite(FileID, 8191,'int16');
  264. end
  265. After = ftell(FileID);
  266. if After-Before ~= 2 && Debug == 1
  267. disp('error Max Aanalog value')
  268. end
  269. %Units
  270. Before = ftell(FileID);
  271. try
  272. fwrite(FileID, NSx.ElectrodesInfo(i).AnalogUnits,'char');
  273. catch
  274. fwrite(FileID, 'uv ');
  275. end
  276. After = ftell(FileID);
  277. if After-Before ~= 16 && Debug == 1
  278. disp('error Units')
  279. end
  280. %High Freq Corner (High frequency cutoff in mHz)
  281. Before = ftell(FileID);
  282. try
  283. fwrite(FileID, NSx.ElectrodesInfo(i).HighFreqCorner,'uint32');
  284. catch
  285. fwrite(FileID, 0,'uint32');
  286. end
  287. After = ftell(FileID);
  288. if After-Before ~= 4 && Debug == 1
  289. disp('error High Corner')
  290. end
  291. %High Freq Order (Order of the filter used)
  292. Before = ftell(FileID);
  293. try
  294. fwrite(FileID, NSx.ElectrodesInfo(i).HighFreqOrder,'uint32');
  295. catch
  296. fwrite(FileID, 0,'uint32');
  297. end
  298. After = ftell(FileID);
  299. if After-Before ~= 4 && Debug == 1
  300. disp('error high Order')
  301. end
  302. %High Filter Type (0 = none, 1 = butterworth)
  303. Before = ftell(FileID);
  304. try
  305. fwrite(FileID, NSx.ElectrodesInfo(i).HighFilterType,'uint16');
  306. catch
  307. fwrite(FileID, 0,'uint16');
  308. end
  309. After = ftell(FileID);
  310. if After-Before ~= 2 && Debug == 1
  311. disp('error High Type')
  312. end
  313. %Low Freq Corner (Low frequency cutoff in mHz)
  314. Before = ftell(FileID);
  315. try
  316. fwrite(FileID, NSx.ElectrodesInfo(i).LowFreqCorner,'uint32');
  317. catch
  318. fwrite(FileID, 0,'uint32');
  319. end
  320. After = ftell(FileID);
  321. if After-Before ~= 4 && Debug == 1
  322. disp('error Low Corner')
  323. end
  324. %Low Freq Order (0 = none)
  325. Before = ftell(FileID);
  326. try
  327. fwrite(FileID, NSx.ElectrodesInfo(i).LowFreqOrder,'uint32');
  328. catch
  329. fwrite(FileID, 0,'uint32');
  330. end
  331. After = ftell(FileID);
  332. if After-Before ~= 4 && Debug == 1
  333. disp('error Low Order')
  334. end
  335. %Low Filter Type (0 = none, 1 = butterworth)
  336. Before = ftell(FileID);
  337. try
  338. fwrite(FileID, NSx.ElectrodesInfo(i).LowFilterType,'uint16');
  339. catch
  340. fwrite(FileID, 0,'uint16');
  341. end
  342. After = ftell(FileID);
  343. if After-Before ~= 2 && Debug == 1
  344. disp('error Low Type')
  345. end
  346. end
  347. %DataPackets
  348. if Paused == 0
  349. %Header
  350. fwrite(FileID, NSx.RawData.DataHeader(1));
  351. %Timestamp
  352. fwrite(FileID, NSx.MetaTags.Timestamp,tspres);
  353. %Number of data points
  354. fwrite(FileID, LengthOfData, 'uint32');
  355. %for i = 1:TotalDataPoints
  356. %Data points
  357. %fwrite(FileID, NSx.Data(i),'int16');
  358. fwrite(FileID, NSx.Data,'int16');
  359. %end
  360. elseif Paused == 1
  361. for SegmentNumber = 1:NumberOfSegments
  362. %Header
  363. fwrite(FileID, 1, 'uint8');
  364. %Timestamp
  365. fwrite(FileID, NSx.MetaTags.Timestamp(SegmentNumber),tspres);
  366. %Number of data points
  367. fwrite(FileID, LengthOfData{SegmentNumber}, 'uint32');
  368. %for i = 1:TotalDataPoints
  369. %Data points
  370. %fwrite(FileID, NSx.Data(i),'int16');
  371. fwrite(FileID, NSx.Data{SegmentNumber},'int16');
  372. %end
  373. end
  374. end
  375. fclose(FileID);