123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- function saveNEVSpikes(spikeStruct, newFileName)
- % saveNEVSpikes
- %
- % Allows the user to save a modified version of the spike waveforms into a
- % NEV file. This can be very useful for those who want to save MATLAB
- % sorted or rethresholded NEV data back into the NEV file. It also re-saves
- % the other data in the original NEV file into the new NEV. A
- %
- % Use saveNEVSpikes(spikeStruct, newFileName)
- %
- % spikeStruct: The structure containing the spike data needed to be
- % saved. The structure format must match the one that
- % openNEV outputs.
- % spikeStruct.TimeStamp: contains all the timestamps
- % spikeStruct.Electrode: contains all the electrode #s
- % spikeStruct.Unit: contains all the sorted unit #s
- % spikeStruct.Waveform: Spike waveforms, containing 48 data
- % points
- %
- % newFileName: The file name of the new NEV file.
- % DEFAULT: User will be prmpted for a file name.
- %
- % Example 1:
- % saveNEVSpikes(spikeStruct, 'sortedNEV';
- %
- % In the example above, the user will be prompted to select a NEV file.
- % The data stored in spikeStruct will be saved into sortedNEV alongside
- % the data in the user-selected NEV file. The new NEV will be saved as
- % sortedNEV.nev
- %
- % Kian Torab
- % ktorab@blackrockmicro.com
- % Blackrock Microsystems
- % Version 1.2.1.0
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Version History
- %
- % 1.0.0.0: Initial Release.
- %
- % 1.2.0.0:
- % - Fixed a bug where the data saved incorrectly under the Windows OS.
- % - Sped up the processing significantly.
- %
- % 1.2.1.0
- % - Fixed a bug introduced in 1.2.0.0.
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% Validating the input argument
- if ~exist('spikeStruct', 'var')
- disp('spikeStruct is a required input argument.');
- return;
- end
- % if isfield(spikeStruct, 'Data') && isfield(spikeStruct, 'MetaTags')
- % newFileName = fullfile(NEV.MetaTags.FilePath, [NEV.MetaTags.Filename, '.nev']);
- % spikeStruct = NEV.Data.Spikes;
- % end
- if ~exist('newFileName', 'var')
- newFileName = input('What file name would you like to use to save the new NEV? ', 's');
- if isempty(newFileName)
- disp('A filename is required.');
- return;
- end
- end
- %% Opening the file and reading header
- [dataFilename dataFolder] = getFile('*.nev', 'Choose a NEV that you would like to modify.');
- fileFullPath = [dataFolder dataFilename];
- FID = fopen(fileFullPath, 'r', 'ieee-le');
- %% Calculating the header bytes
- BasicHeader = fread(FID, 20, '*uint8');
- headerBytes = double(typecast(BasicHeader(13:16), 'uint32'));
- dataPacketByteLength = double(typecast(BasicHeader(17:20), 'uint32'));
- %% Calculating the data file length and eeking to the beginning of the file
- fseek(FID, 0, 'eof');
- endOfDataByte = ftell(FID);
- dataByteLength = endOfDataByte - headerBytes;
- numberOfPackets = double(dataByteLength) / double(dataPacketByteLength);
- %% Reading the header binaries and saving it for future
- fseek(FID, 0, 'bof');
- headerBinaries = fread(FID, headerBytes, '*uint8');
- %% Reading the data binaries
- dataBinaries = fread(FID, [dataPacketByteLength numberOfPackets], '*uint8', 0);
- %% Finding what PacketIDs have the desired channels
- PacketIDs = zeros(1,size(dataBinaries,2));
- for IDX = 1:size(dataBinaries,2)
- PacketIDs(IDX) = typecast(dataBinaries(5:6, IDX), 'uint16');
- end
- %% Only capturing all the binary lines that contain non-spike events, such
- % as comments, tracking, patient trigger, etc.
- newDataBinaries = dataBinaries(:, PacketIDs > 256); clear dataBinaries;
- %% Extracting the timestamps of all the above non-spike events
- dataTimestamps = zeros(1,size(newDataBinaries,2));
- for IDX = 1:size(newDataBinaries,2)
- dataTimestamps(IDX) = typecast(newDataBinaries(1:4, IDX), 'uint32');
- end
- %% Converting all the user supplied data into binaries for saving into the
- % new structure
- newSpikesBinary = zeros(size([typecast(uint32(spikeStruct.TimeStamp(1)), 'uint8'),...
- typecast(uint16(spikeStruct.Electrode(1)), 'uint8'),...
- typecast(uint8(spikeStruct.Unit(1)), 'uint8'),...
- 1,...
- typecast(int16(spikeStruct.Waveform(:,1))', 'uint8')]',1), size(spikeStruct.Electrode,2));
- for idx = 1:size(spikeStruct.Electrode,2)
- newSpikesBinary(:,idx) = [typecast(uint32(spikeStruct.TimeStamp(idx)), 'uint8'),...
- typecast(uint16(spikeStruct.Electrode(idx)), 'uint8'),...
- typecast(uint8(spikeStruct.Unit(idx)), 'uint8'),...
- 1,...
- typecast(int16(spikeStruct.Waveform(:,idx))', 'uint8')]';
- end
- %% Processing data
- % Concatinating the user supplied data (non-spike) and the user supplied data
- newDataBinaries = [newDataBinaries, newSpikesBinary];
- % Ranking the spike and re-ranking the data for saving (timestamp descending)
- allTimestamps = [dataTimestamps, spikeStruct.TimeStamp];
- [~, ranking] = sort(allTimestamps);
- newDataBinaries = newDataBinaries(:,ranking);
- %% Saving the new NEV containig the desired channels
- FIDw = fopen([dataFolder newFileName '.nev'], 'w+', 'ieee-le');
- fwrite(FIDw, headerBinaries, 'uint8');
- fwrite(FIDw, newDataBinaries, 'uint8');
- fclose(FID);
- fclose(FIDw);
|