From 5aaeaf20e5cb91218a17e65b1cf0b80904e8face Mon Sep 17 00:00:00 2001 From: Spencer Kellis <44041997+sskellis@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:20:20 -0700 Subject: [PATCH 1/8] Update openNSx Check for existence of Time field before reference --- NPMK/openNSx.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NPMK/openNSx.m b/NPMK/openNSx.m index ec00a54..177f443 100644 --- a/NPMK/openNSx.m +++ b/NPMK/openNSx.m @@ -1444,7 +1444,9 @@ % reduce to array if only one cell if flagReadData && iscell(NSx.Data) && length(NSx.Data)==1 NSx.Data = NSx.Data{1}; - NSx.Time = NSx.Time{1}; + if isfield(NSx,'Time') + NSx.Time = NSx.Time{1}; + end end % Display a report of basic file information and the Basic Header. From 3410ad76e38af29a31a75fe36679bdc295147a37 Mon Sep 17 00:00:00 2001 From: dkluger Date: Tue, 20 Aug 2024 11:12:00 -0600 Subject: [PATCH 2/8] Cleaned file and path creating lines. Added erase statement for .sif prefixes --- NPMK/openNEV.m | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/NPMK/openNEV.m b/NPMK/openNEV.m index 8a62721..41fd042 100644 --- a/NPMK/openNEV.m +++ b/NPMK/openNEV.m @@ -236,13 +236,12 @@ %% Defining structures NEV = struct('MetaTags',[], 'ElectrodesInfo', [], 'Data', []); -NEV.MetaTags.openNEVver = '6.2.3.0'; NEV.MetaTags = struct('Subject', [], 'Experimenter', [], 'DateTime', [],... 'SampleRes',[],'Comment',[],'FileTypeID',[],'Flags',[], 'openNEVver', [], ... 'DateTimeRaw', [], 'FileSpec', [], 'PacketBytes', [], 'HeaderOffset', [], ... 'PacketCount', [], 'TimeRes', [], 'Application', [], 'Filename', [], 'FilePath', []); % 'DataDuration', [], 'DataDurationSec', [], - +NEV.MetaTags.openNEVver = '6.2.3.0'; NEV.Data = struct('SerialDigitalIO', [], 'Spikes', [], 'Comments', [], 'VideoSync', [], ... 'Tracking', [], 'TrackingEvents', [], 'PatientTrigger', [], 'Reconfig', []); NEV.Data.Spikes = struct('TimeStamp', [],'Electrode', [],... @@ -300,6 +299,7 @@ strcmpi(tempst(1:2), '\\') || ... strcmpi(tempst(end-3), '.')) fileFullPath = varargin{i}; + [path, fileName, fileExt] = fileparts(fileFullPath); if exist(fileFullPath, 'file') ~= 2 disp('The file does not exist.'); varargout{1} = []; @@ -338,11 +338,12 @@ %% Defining and validating variables if ~exist('fileFullPath', 'var') if exist('getFile.m', 'file') == 2 - [fileName pathName] = getFile('*.nev*', 'Choose a NEV file...'); + [fileName, pathName] = getFile('*.nev*', 'Choose a NEV file...'); else - [fileName pathName] = uigetfile; + [fileName, pathName] = uigetfile; end fileFullPath = [pathName fileName]; + [path, fileName, fileExt] = fileparts(fileFullPath); if fileFullPath==0; clear variables; if nargout @@ -353,8 +354,6 @@ end end -[~, ~, fileExt] = fileparts(fileFullPath); - %% Loading .x files for multiNSP configuration if strcmpi(fileExt(2:4), 'nev') && length(fileExt) == 5 fileFullPath(1) = fileFullPath(end); @@ -447,10 +446,16 @@ clear BasicHeader; if or(strcmpi(NEV.MetaTags.FileTypeID, 'NEURALEV'), strcmpi(NEV.MetaTags.FileTypeID, 'BREVENTS')) - if exist([fileFullPath(1:end-8) '.sif'], 'file') == 2 - METATAGS = textread([fileFullPath(1:end-8) '.sif'], '%s'); + prefixes = {'Hub1-', 'Hub2-','NSP-'}; + fileNameBase = fileName(1:end-4); + sifName = [path '\' erase(fileNameBase,prefixes) '.sif']; + if exist(sifName, 'file') == 2 + METATAGS = textread(sifName, '%s'); NEV.MetaTags.Subject = METATAGS{3}(5:end-5); NEV.MetaTags.Experimenter = [METATAGS{5}(8:end-8) ' ' METATAGS{6}(7:end-7)]; + else + warning(['No .sif file found corresponding to ' fullFilePath... + '. Subject and Experimenter data skipped in MetaTags']); end end if ~any(strcmpi(NEV.MetaTags.FileSpec, {'2.1', '2.2', '2.3', '3.0'})) From 130b5ef32ae9e58d5659126f4506e16fdb826861 Mon Sep 17 00:00:00 2001 From: dkluger Date: Tue, 20 Aug 2024 11:24:21 -0600 Subject: [PATCH 3/8] Fixed typo --- NPMK/openNEV.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NPMK/openNEV.m b/NPMK/openNEV.m index 41fd042..4eb8913 100644 --- a/NPMK/openNEV.m +++ b/NPMK/openNEV.m @@ -454,7 +454,7 @@ NEV.MetaTags.Subject = METATAGS{3}(5:end-5); NEV.MetaTags.Experimenter = [METATAGS{5}(8:end-8) ' ' METATAGS{6}(7:end-7)]; else - warning(['No .sif file found corresponding to ' fullFilePath... + warning(['No .sif file found corresponding to ' fileFullPath... '. Subject and Experimenter data skipped in MetaTags']); end end From c65fd1532d8a69e9f72ee32c3ff4b2238f1c052b Mon Sep 17 00:00:00 2001 From: dkluger Date: Mon, 30 Sep 2024 11:41:30 -0600 Subject: [PATCH 4/8] Fixed NPMK color/timestamp start behavior --- NPMK/Versions.txt | 6 +++++- NPMK/openNEV.m | 42 +++++++++++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/NPMK/Versions.txt b/NPMK/Versions.txt index da70824..698f62b 100644 --- a/NPMK/Versions.txt +++ b/NPMK/Versions.txt @@ -536,4 +536,8 @@ NPMK Version 2.8.2.0: 5 May 2014 % 6.2.3.0: openNEV: June 13, 2024 % - Removed DataDuration and DataDurationSec from output % -LATEST:5.5.4.0 +***** NPMK Version 5.5.5.0 :June 5, 2024 ***** +% 6.2.4.0: September 30, 2024 +% - Fixed timestamp reporting for comments in filespec 3.0 (David Kluger) +% +LATEST:5.5.5.0 diff --git a/NPMK/openNEV.m b/NPMK/openNEV.m index 4eb8913..7687c0e 100644 --- a/NPMK/openNEV.m +++ b/NPMK/openNEV.m @@ -229,6 +229,9 @@ % spike data. (Spencer Kellis) % 6.2.3.0: June 13, 2024 % - Removed DataDuration and DataDurationSec from output +% +% 6.2.4.0: September 30, 2024 +% - Fixed timestamp reporting for comments in filespec 3.0 (David Kluger) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Check for the latest version fo NPMK @@ -241,7 +244,7 @@ 'DateTimeRaw', [], 'FileSpec', [], 'PacketBytes', [], 'HeaderOffset', [], ... 'PacketCount', [], 'TimeRes', [], 'Application', [], 'Filename', [], 'FilePath', []); % 'DataDuration', [], 'DataDurationSec', [], -NEV.MetaTags.openNEVver = '6.2.3.0'; +NEV.MetaTags.openNEVver = '6.2.4.0'; NEV.Data = struct('SerialDigitalIO', [], 'Spikes', [], 'Comments', [], 'VideoSync', [], ... 'Tracking', [], 'TrackingEvents', [], 'PatientTrigger', [], 'Reconfig', []); NEV.Data.Spikes = struct('TimeStamp', [],'Electrode', [],... @@ -362,17 +365,18 @@ if ~isfield(Flags, 'Report'); Flags.Report = 'noreport'; end -if ~isfield(Flags, 'WarningStat'); Flags.WarningStat = 'warning'; end; +if ~isfield(Flags, 'WarningStat'); Flags.WarningStat = 'warning'; end if ~isfield(Flags, 'ReadData'); Flags.ReadData = 'read'; end if ~isfield(Flags, 'ParseData'); Flags.ParseData = 'noparse'; end -if ~isfield(Flags, 'SaveFile'); Flags.SaveFile = 'save'; end; -if ~isfield(Flags, 'NoMAT'); Flags.NoMAT = 'yesmat'; end; -if ~isfield(Flags, 'waveformUnits'); Flags.waveformUnits = 'raw'; end; -if ~isfield(Flags, 'digIOBits'); Flags.digIOBits = '16bits'; end; -if ~isfield(Flags, 'Overwrite'); Flags.Overwrite = 'nooverwrite'; end; -if ~isfield(Flags, 'MultiNSP'); Flags.MultiNSP = 'multinsp'; end; -if ~isfield(Flags, 'selChannels'); Flags.selChannels = 'all'; end; -if ~isfield(Flags, 'Direct'); Flags.Direct = 'nodirect'; end; +if ~isfield(Flags, 'SaveFile'); Flags.SaveFile = 'save'; end +if ~isfield(Flags, 'NoMAT'); Flags.NoMAT = 'yesmat'; end +if ~isfield(Flags, 'waveformUnits'); Flags.waveformUnits = 'raw'; end +if ~isfield(Flags, 'digIOBits'); Flags.digIOBits = '16bits'; end +if ~isfield(Flags, 'Overwrite'); Flags.Overwrite = 'nooverwrite'; end +if ~isfield(Flags, 'MultiNSP'); Flags.MultiNSP = 'multinsp'; end +if ~isfield(Flags, 'selChannels'); Flags.selChannels = 'all'; end +if ~isfield(Flags, 'Direct'); Flags.Direct = 'nodirect'; end +if ~isfield(Flags, 'PTP'); Flags.PTP = 'noPTP'; end if strcmpi(Flags.Report, 'report') disp(['openNEV ' NEV.MetaTags.openNEVver]); @@ -447,6 +451,9 @@ if or(strcmpi(NEV.MetaTags.FileTypeID, 'NEURALEV'), strcmpi(NEV.MetaTags.FileTypeID, 'BREVENTS')) prefixes = {'Hub1-', 'Hub2-','NSP-'}; + if NEV.MetaTags.TimeRes == 1e9 + Flags.PTP = 'PTP'; + end fileNameBase = fileName(1:end-4); sifName = [path '\' erase(fileNameBase,prefixes) '.sif']; if exist(sifName, 'file') == 2 @@ -720,8 +727,18 @@ NEV.Data.Comments.CharSet = tempCharSet(orderOfTS); clear tempCharSet; colorFlag = tRawData(timeStampBytes+4, commentIndices); NEV.Data.Comments.TimeStampStarted = tRawData(timeStampBytes+5:timeStampBytes+8, commentIndices); + NEV.Data.Comments.Color = NEV.Data.Comments.TimeStampStarted; tempTimeStampStarted = typecast(NEV.Data.Comments.TimeStampStarted(:), 'uint32').'; + if strcmp(Flags.PTP, 'PTP') + diffFactor = 1000; % ns -> µs conversion + else + diffFactor = 1; % sample count + end + tempTimeStampStarted = NEV.Data.Comments.TimeStamp-uint64(tempTimeStampStarted)*diffFactor; NEV.Data.Comments.TimeStampStarted = tempTimeStampStarted(orderOfTS); clear tempTimeStampStarted; + NEV.Data.Comments.TimeStampStarted(colorFlag == 0) = 0; + NEV.Data.Comments.Color(:,colorFlag == 1) = 0; + tempText = char(tRawData(timeStampBytes+9:Trackers.countPacketBytes, commentIndices).'); NEV.Data.Comments.Text = tempText(orderOfTS,:); clear tempText; @@ -747,11 +764,6 @@ NEV.Data.Comments.Text(neuroMotiveEvents,:) = []; colorFlag(neuroMotiveEvents) = []; - % Figuring out the text color of the comments that had color - NEV.Data.Comments.Color = dec2hex(NEV.Data.Comments.TimeStampStarted); - NEV.Data.Comments.Color(colorFlag == 1,:) = repmat('0', size(NEV.Data.Comments.Color(colorFlag == 1,:))); - NEV.Data.Comments.TimeStampStarted(colorFlag == 0) = NEV.Data.Comments.TimeStamp(colorFlag == 0); - clear commentIndices; end if ~isempty(videoSyncPacketIDIndices) From 3ba7164ac815b31150c8d5ff144900a9ba6e5f63 Mon Sep 17 00:00:00 2001 From: dkluger Date: Mon, 30 Sep 2024 15:40:45 -0600 Subject: [PATCH 5/8] removed duplicated comments from output --- NPMK/openNEV.m | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/NPMK/openNEV.m b/NPMK/openNEV.m index 7687c0e..f156fa3 100644 --- a/NPMK/openNEV.m +++ b/NPMK/openNEV.m @@ -727,7 +727,7 @@ NEV.Data.Comments.CharSet = tempCharSet(orderOfTS); clear tempCharSet; colorFlag = tRawData(timeStampBytes+4, commentIndices); NEV.Data.Comments.TimeStampStarted = tRawData(timeStampBytes+5:timeStampBytes+8, commentIndices); - NEV.Data.Comments.Color = NEV.Data.Comments.TimeStampStarted; + tempColor = NEV.Data.Comments.TimeStampStarted; tempTimeStampStarted = typecast(NEV.Data.Comments.TimeStampStarted(:), 'uint32').'; if strcmp(Flags.PTP, 'PTP') diffFactor = 1000; % ns -> µs conversion @@ -736,8 +736,7 @@ end tempTimeStampStarted = NEV.Data.Comments.TimeStamp-uint64(tempTimeStampStarted)*diffFactor; NEV.Data.Comments.TimeStampStarted = tempTimeStampStarted(orderOfTS); clear tempTimeStampStarted; - NEV.Data.Comments.TimeStampStarted(colorFlag == 0) = 0; - NEV.Data.Comments.Color(:,colorFlag == 1) = 0; + NEV.Data.Comments.Color(:,colorFlag == 1) = tempColor(:,colorFlag == 0); clear tempColor tempText = char(tRawData(timeStampBytes+9:Trackers.countPacketBytes, commentIndices).'); NEV.Data.Comments.Text = tempText(orderOfTS,:); clear tempText; @@ -762,7 +761,15 @@ NEV.Data.Comments.TimeStampStarted(neuroMotiveEvents) = []; NEV.Data.Comments.TimeStampStartedSec = double(NEV.Data.Comments.TimeStampStarted)/double(NEV.MetaTags.TimeRes); NEV.Data.Comments.Text(neuroMotiveEvents,:) = []; - colorFlag(neuroMotiveEvents) = []; + + % remove duplicated packets for color and time stamp start + NEV.Data.Comments.TimeStampStarted = NEV.Data.Comments.TimeStampStarted(colorFlag == 1); + NEV.Data.Comments.TimeStampStartedSec = NEV.Data.Comments.TimeStampStartedSec(colorFlag == 1); + NEV.Data.Comments.TimeStamp = NEV.Data.Comments.TimeStamp(colorFlag == 1); + NEV.Data.Comments.TimeStampSec = NEV.Data.Comments.TimeStampSec(colorFlag == 1); + NEV.Data.Comments.CharSet = NEV.Data.Comments.CharSet(colorFlag == 1); + NEV.Data.Comments.Text = NEV.Data.Comments.Text(colorFlag == 1,:); + NEV.Data.Comments.Color = NEV.Data.Comments.Color(:,colorFlag == 1); clear commentIndices; end From d11bb91b96803cbbc29950d446dbcd9996cc72da Mon Sep 17 00:00:00 2001 From: dkluger Date: Tue, 1 Oct 2024 08:56:01 -0600 Subject: [PATCH 6/8] added comment cleaning logic for 3.0 files only --- NPMK/openNEV.m | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/NPMK/openNEV.m b/NPMK/openNEV.m index f156fa3..a9d5fae 100644 --- a/NPMK/openNEV.m +++ b/NPMK/openNEV.m @@ -727,7 +727,7 @@ NEV.Data.Comments.CharSet = tempCharSet(orderOfTS); clear tempCharSet; colorFlag = tRawData(timeStampBytes+4, commentIndices); NEV.Data.Comments.TimeStampStarted = tRawData(timeStampBytes+5:timeStampBytes+8, commentIndices); - tempColor = NEV.Data.Comments.TimeStampStarted; + tempColor = NEV.Data.Comments.TimeStampStarted; % RGBA and starting timestamp data fields shared tempTimeStampStarted = typecast(NEV.Data.Comments.TimeStampStarted(:), 'uint32').'; if strcmp(Flags.PTP, 'PTP') diffFactor = 1000; % ns -> µs conversion @@ -762,14 +762,17 @@ NEV.Data.Comments.TimeStampStartedSec = double(NEV.Data.Comments.TimeStampStarted)/double(NEV.MetaTags.TimeRes); NEV.Data.Comments.Text(neuroMotiveEvents,:) = []; - % remove duplicated packets for color and time stamp start - NEV.Data.Comments.TimeStampStarted = NEV.Data.Comments.TimeStampStarted(colorFlag == 1); - NEV.Data.Comments.TimeStampStartedSec = NEV.Data.Comments.TimeStampStartedSec(colorFlag == 1); - NEV.Data.Comments.TimeStamp = NEV.Data.Comments.TimeStamp(colorFlag == 1); - NEV.Data.Comments.TimeStampSec = NEV.Data.Comments.TimeStampSec(colorFlag == 1); - NEV.Data.Comments.CharSet = NEV.Data.Comments.CharSet(colorFlag == 1); - NEV.Data.Comments.Text = NEV.Data.Comments.Text(colorFlag == 1,:); - NEV.Data.Comments.Color = NEV.Data.Comments.Color(:,colorFlag == 1); + % remove duplicated comment packets for color and time stamp + % start in filespec 3.0 + if strcmp(NEV.MetaTags.FileSpec, '3.0') + NEV.Data.Comments.TimeStampStarted = NEV.Data.Comments.TimeStampStarted(colorFlag == 1); + NEV.Data.Comments.TimeStampStartedSec = NEV.Data.Comments.TimeStampStartedSec(colorFlag == 1); + NEV.Data.Comments.TimeStamp = NEV.Data.Comments.TimeStamp(colorFlag == 1); + NEV.Data.Comments.TimeStampSec = NEV.Data.Comments.TimeStampSec(colorFlag == 1); + NEV.Data.Comments.CharSet = NEV.Data.Comments.CharSet(colorFlag == 1); + NEV.Data.Comments.Text = NEV.Data.Comments.Text(colorFlag == 1,:); + NEV.Data.Comments.Color = NEV.Data.Comments.Color(:,colorFlag == 1); + end clear commentIndices; end From a391a6ac407bd79bc0e17a1a1186eb0bf9964ca3 Mon Sep 17 00:00:00 2001 From: dkluger Date: Wed, 2 Oct 2024 15:57:18 -0600 Subject: [PATCH 7/8] Revived color in hex output. Removed a memcopy --- NPMK/openNEV.m | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/NPMK/openNEV.m b/NPMK/openNEV.m index a9d5fae..2e66086 100644 --- a/NPMK/openNEV.m +++ b/NPMK/openNEV.m @@ -726,17 +726,16 @@ tempCharSet = tRawData(timeStampBytes+3, commentIndices); NEV.Data.Comments.CharSet = tempCharSet(orderOfTS); clear tempCharSet; colorFlag = tRawData(timeStampBytes+4, commentIndices); - NEV.Data.Comments.TimeStampStarted = tRawData(timeStampBytes+5:timeStampBytes+8, commentIndices); - tempColor = NEV.Data.Comments.TimeStampStarted; % RGBA and starting timestamp data fields shared - tempTimeStampStarted = typecast(NEV.Data.Comments.TimeStampStarted(:), 'uint32').'; + tempPayload = tRawData(timeStampBytes+5:timeStampBytes+8, commentIndices); + diffTimeStampStarted = typecast(tempPayload(:), 'uint32').'; if strcmp(Flags.PTP, 'PTP') diffFactor = 1000; % ns -> µs conversion else diffFactor = 1; % sample count end - tempTimeStampStarted = NEV.Data.Comments.TimeStamp-uint64(tempTimeStampStarted)*diffFactor; - NEV.Data.Comments.TimeStampStarted = tempTimeStampStarted(orderOfTS); clear tempTimeStampStarted; - NEV.Data.Comments.Color(:,colorFlag == 1) = tempColor(:,colorFlag == 0); clear tempColor + tempTimeStampStarted = NEV.Data.Comments.TimeStamp-uint64(diffTimeStampStarted)*diffFactor; + NEV.Data.Comments.TimeStampStarted = tempTimeStampStarted(orderOfTS); clear diffTimeStampStarted tempTimeStampStarted; + NEV.Data.Comments.Color = dec2hex(typecast(tempPayload(:),'uint32')); clear tempPayload tempText = char(tRawData(timeStampBytes+9:Trackers.countPacketBytes, commentIndices).'); NEV.Data.Comments.Text = tempText(orderOfTS,:); clear tempText; @@ -771,10 +770,10 @@ NEV.Data.Comments.TimeStampSec = NEV.Data.Comments.TimeStampSec(colorFlag == 1); NEV.Data.Comments.CharSet = NEV.Data.Comments.CharSet(colorFlag == 1); NEV.Data.Comments.Text = NEV.Data.Comments.Text(colorFlag == 1,:); - NEV.Data.Comments.Color = NEV.Data.Comments.Color(:,colorFlag == 1); + NEV.Data.Comments.Color = NEV.Data.Comments.Color(colorFlag == 0,:); end - clear commentIndices; + clear commentIndices colorFlag; end if ~isempty(videoSyncPacketIDIndices) NEV.Data.VideoSync.TimeStamp = Timestamp(videoSyncPacketIDIndices); From 6f9ec9a1d1127ee043822d92f999adf28b6aae48 Mon Sep 17 00:00:00 2001 From: dkluger Date: Wed, 2 Oct 2024 16:07:44 -0600 Subject: [PATCH 8/8] Replaced NeuroMotive behavior --- NPMK/openNEV.m | 1 + 1 file changed, 1 insertion(+) diff --git a/NPMK/openNEV.m b/NPMK/openNEV.m index 2e66086..08ae72a 100644 --- a/NPMK/openNEV.m +++ b/NPMK/openNEV.m @@ -760,6 +760,7 @@ NEV.Data.Comments.TimeStampStarted(neuroMotiveEvents) = []; NEV.Data.Comments.TimeStampStartedSec = double(NEV.Data.Comments.TimeStampStarted)/double(NEV.MetaTags.TimeRes); NEV.Data.Comments.Text(neuroMotiveEvents,:) = []; + colorFlag(neuroMotiveEvents) = []; % remove duplicated comment packets for color and time stamp % start in filespec 3.0