diff --git a/+ndr/+reader/intan_rhd.m b/+ndr/+reader/intan_rhd.m index e974b1e..fa2d1a1 100755 --- a/+ndr/+reader/intan_rhd.m +++ b/+ndr/+reader/intan_rhd.m @@ -204,7 +204,7 @@ newchannel.name = intan_rhd_obj.intanname2mfdaqname(... intan_rhd_obj,... channel_type_entry,... - channel(p).native_channel_name); + channel(p)); channels(end+1) = newchannel; end end @@ -453,19 +453,62 @@ end; end; % ndr.reader.intan_rhd.intanchanneltype2mfdaqchanneltype() - function [channame] = intanname2mfdaqname(intan_rhd_obj, type, name) + function [channame] = intanname2mfdaqname(intan_rhd_obj, type, name_or_struct) % INTANNAME2MFDAQNAME - Converts a channel name from Intan native format to ndr.ndr.reader.mfdaq format % - % [CHANNAME] = INTANNAME2MFDAQNAME(NDR_NDRREADER_INTANREADER_OBJ, TYPE, NAME) + % [CHANNAME] = INTANNAME2MFDAQNAME(NDR_NDRREADER_INTANREADER_OBJ, TYPE, NAME_OR_STRUCT) % % Given an Intan native channel name (e.g., 'A-000') in NAME and an % ndr.ndr.reader.mfdaq channel type string (see NDI_DEVICE_MFDAQ), this function % produces an ndr.ndr.reader.mfdaq channel name (e.g., 'ai1'). % + % NAME_OR_STRUCT can also be the Intan channel structure (with fields 'native_channel_name', 'chip_channel', etc). + % + + if isstruct(name_or_struct), + name = name_or_struct.native_channel_name; + if isfield(name_or_struct, 'chip_channel'), + chip_channel = name_or_struct.chip_channel; + else + chip_channel = []; + end + else, + name = name_or_struct; + chip_channel = []; + end; + sep = find(name=='-'); - chan_intan = str2num(name(sep+1:end)); - chan = chan_intan + 1; % Intan numbers from 0 - channame = [ndr.reader.base.mfdaq_prefix(type) int2str(chan)]; + if ~isempty(sep), + chan_intan = str2num(name(sep(end)+1:end)); + chan = chan_intan + 1; % Intan numbers from 0 + else, + % try to find a number at the end + [s,e] = regexp(name,'\d+$'); + if ~isempty(s), + chan_intan = str2num(name(s:e)); + if strncmpi(type,'aux',3) | strncmpi(type,'ax',2), + % Intan aux channels are named AUX1, AUX2, etc, so they are 1-based + chan = chan_intan; + else, + chan = chan_intan + 1; % assume 0-based + end; + else, + chan = []; + end; + end; + + if isempty(chan), + % if we couldn't parse the name, try to use the chip_channel if available + if ~isempty(chip_channel), + chan = chip_channel + 1; % assume 0-based chip channel + end; + end; + + if isempty(chan), + channame = [ndr.reader.base.mfdaq_prefix(type)]; % fallback + else, + channame = [ndr.reader.base.mfdaq_prefix(type) int2str(chan)]; + end; end; % ndr.reader.intan_rhd.intanname2mfdaqname function headername = mfdaqchanneltype2intanfreqheader(channeltype) @@ -482,7 +525,7 @@ headername = 'board_dig_in_sample_rate'; case {'time','timestamp'}, headername = 'amplifier_sample_rate'; - case{'auxiliary','aux'}, + case{'auxiliary','aux','auxiliary_in'}, headername = 'aux_input_sample_rate'; otherwise, error(['Do not know frequency header for channel type ' channeltype '.']); diff --git a/.github/badges/code_issues.svg b/.github/badges/code_issues.svg index eb8f181..805a27b 100644 --- a/.github/badges/code_issues.svg +++ b/.github/badges/code_issues.svg @@ -1 +1 @@ -code issuescode issues12481248 \ No newline at end of file +code issuescode issues12701270 \ No newline at end of file diff --git a/.github/badges/tests.svg b/.github/badges/tests.svg index 7615503..dff726f 100644 --- a/.github/badges/tests.svg +++ b/.github/badges/tests.svg @@ -1 +1 @@ -teststests41 passed41 passed \ No newline at end of file +teststests44 passed44 passed \ No newline at end of file diff --git a/example_data/example.abf b/example_data/example.abf new file mode 100644 index 0000000..c934a07 Binary files /dev/null and b/example_data/example.abf differ diff --git a/lib/abfload/abfload2.m b/lib/abfload/abfload2.m index 138aba7..bd1a136 100644 --- a/lib/abfload/abfload2.m +++ b/lib/abfload/abfload2.m @@ -179,7 +179,7 @@ % ************************ % abf version >= 2.0 % ************************ - otherwise + otherwise error(['unknown or incompatible file signature: ' fFileSignature]); end @@ -428,7 +428,7 @@ % ------------------------------------------------------------------------- if h.lActualAcqLength 'ax1' + channel_struct.native_channel_name = 'AUX'; + channel_struct.chip_channel = 0; + type = 'auxiliary_in'; + + result = ndr.reader.intan_rhd.intanname2mfdaqname([], type, channel_struct); + testCase.verifyEqual(result, 'ax1', 'Failed fallback to chip_channel for AUX'); + + % Case 2: Name parsing works, ignore chip_channel (or ensure consistency) + channel_struct.native_channel_name = 'AUX2'; + channel_struct.chip_channel = 99; % Should be ignored if name parses? + % My logic uses name first. + + result = ndr.reader.intan_rhd.intanname2mfdaqname([], type, channel_struct); + testCase.verifyEqual(result, 'ax2', 'Should use name if parseable'); + + % Case 3: Struct without chip_channel + channel_struct2.native_channel_name = 'A-000'; + % no chip_channel field + result = ndr.reader.intan_rhd.intanname2mfdaqname([], 'analog_in', channel_struct2); + testCase.verifyEqual(result, 'ai1', 'Should work without chip_channel field'); + end + + function testAuxSampleRate(testCase) + % Test that samplerate works for auxiliary_in + reader = ndr.reader.intan_rhd(); + ndr_path = ndr.fun.ndrpath(); + rhd_file = fullfile(ndr_path, 'example_data', 'example.rhd'); + epochstreams = {rhd_file}; + epoch_select = 1; + + % This should not error now + sr = reader.samplerate(epochstreams, epoch_select, 'auxiliary_in', 1); + + % Check if it returns a valid number (header frequency_parameters are usually populated) + testCase.verifyNotEmpty(sr); + testCase.verifyTrue(isnumeric(sr)); + end end end