当前位置:首页 > Software > Matlab > 正文内容

ADI ADC Simulink Model 在MatlabR2025a上适配修改,解决警告和报错的问题(以AD9268为例,其他的也可使用)

chanra1n8小时前Matlab7

Matlab R2025a对语法的要求更高,以前版本的无法直接工作,需要进行修改:

image.png

image.png

主要是修改2个文件:

AD9268_sysobj.m

% Copyright (c) 2014, Analog Devices Inc. 
% All rights reserved.
% 
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:
%
% 1. Redistributions of source code must retain the above copyright
% notice, this list of conditions and the following disclaimer.
%
% 2.Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% 3. Neither the name of the copyright holder nor the names of its
% contributors may be used to endorse or promote products derived from this
% software without specific prior written permission.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
% IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
% PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
% CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
% PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
classdef AD9268_sysobj < matlab.System
    % System Object behavioral model for Analog Devices' High-Speed ADCs
    % Notes:
    %   - The Resolution dropdown filters the ADC options
    %   - In the name of the ADC is the maximum sampling clock, be sure
    %     to adjust your sampling clock accordingly.
   
    properties
        % Specific Options
        SpecificOptions = '125 MSPS';
        % Sampling Clock Frequency (Hz)
        Fclk = 125e6;
        % Mean Frequency (Hz)
        Tessitura = 2.3e6;
        % RMS Clock Jitter (sec)
        ExtJitter = 6e-014;
        % Input Configuration
        InputConfig = 'Normalized';
    end
       
    properties (Access = private)
        pm;         % MOTIF Object
        poffset;    % ADC Offset
        prange;     % ADC Range
        pgeneric;   % Generic name
        pspecificOptionsMap;     % Specific Options map
    end
    
    properties(Constant, Hidden)
        SpecificOptionsSet = matlab.system.StringSet({'80 MSPS', '105 MSPS', '125 MSPS'});
        InputConfigSet = matlab.system.StringSet({'Normalized', 'Absolute'});
    end
    
    properties (DiscreteState)
    end
    
    methods
        % Constructor
        function obj = AD9268_sysobj(varargin)
            % Support name-value pair arguments when constructing the
            % object.
            
            % Assign generic
            obj.pgeneric = 'AD9268';
            
            % Build options maps (note: indexing SpecificOptionsSet is
            %   impossible)
            obj.pspecificOptionsMap = containers.Map;
            obj.pspecificOptionsMap('80 MSPS') = '80';
            obj.pspecificOptionsMap('105 MSPS') = '105';
            obj.pspecificOptionsMap('125 MSPS') = '125';
            
            % Add MOTIF path
            modelPath = get_param(gcs,'FileName');
            modelFolder = fileparts(modelPath);
            resourcesFolder = fullfile(modelFolder, 'MOTIF');
            addpath(resourcesFolder);
            
            setProperties(obj,nargin,varargin{:});
        end
    end
    methods (Static, Access = protected)
        function header = getHeaderImpl
            header = matlab.system.display.Header(mfilename('class'),...                
                'Title','System Object for an ADC',...
                'Text','This is a behavioral model of an ADC.',...
                'ShowSourceLink',false);
        end     
    end
    
    methods (Access = protected)
        %% Common functions
        function setupImpl(obj)
            % Implement tasks that need to be performed only once,
            % such as pre-computed constants.
            modelPath = obj.determineModelName();
            
            obj.pm = MOTIF_if(['MOTIF' filesep modelPath]);
            
            if (~obj.pm.isLoaded())
                error('Error: Could not open file!  Check to see if you have the model file downloaded in your path.');
            end
            
            % Get maximum sampling rate, and coerce if necessary
            clkmax = str2double(obj.pm.getProp('settings', 'clkmax'));
            if obj.Fclk > clkmax
                fclk = clkmax;
                warning('Sampling Rate was too high, coerced to maximum for this device');
            else
                fclk = obj.Fclk;
            end
            
            % Push simulation properties to MOTIF
            obj.pm.setProp('GLOBAL', 'fclk', num2str(fclk));
            obj.pm.setProp('GLOBAL', 'tessitura', num2str(obj.Tessitura));
            obj.pm.setProp('settings', 'extjitter', num2str(obj.ExtJitter));
            
            if strcmp(obj.InputConfig, 'Normalized')
               obj.poffset = str2double(obj.pm.getProp('settings', 'offset'));
               obj.prange = str2double(obj.pm.getProp('settings', 'range'));
            else
                obj.poffset = 0;
                obj.prange = 2;
            end
        end
        
        function modelPath = determineModelName(obj)
            % Determines the currently selected model name and saves to
            % pmodelPath
            modelPath = obj.pgeneric;
                        
            if ~strcmp(obj.SpecificOptions, '[empty]')
                specificOptions = obj.pspecificOptionsMap(obj.SpecificOptions);
                modelPath = [modelPath '_' specificOptions];    
            end
            
            modelPath = [modelPath '.adc'];
        end
        
        function y = stepImpl(obj, u)
            % Implement algorithm. Calculate y as a function of
            % input u and discrete states.
            y = obj.pm.runSamples(u * obj.prange / 2 + obj.poffset);
        end
        
        function releaseImpl(obj)
            % Initialize discrete-state properties.
            obj.pm.destroy();
        end
        
        % This method controls visibility of the object's properties
        function flag = isInactivePropertyImpl(obj, propertyName)
            flag = false;
            if strcmp(propertyName, 'SpecificOptions')
               if strcmp(obj.SpecificOptions, '[empty]')
                    flag = true;
               end
            end
        end        
        
        function icon = getIconImpl(obj)
            icon = obj.pgeneric;
        end     
             
        function dataout = getOutputDataTypeImpl(~)
            dataout = 'double';
        end
        function sizeout = getOutputSizeImpl(~)
            sizeout = [1 1];
        end
        function cplxout = isOutputComplexImpl(~)
            cplxout = false;
        end
        function fixedout = isOutputFixedSizeImpl(~)
            fixedout = true;
        end
        
        function num = getNumInputsImpl(~)
           num = 1; 
        end
        
        function varargout = getInputNamesImpl(obj)
            numInputs = getNumInputs(obj);
            varargout = cell(1,numInputs);
            varargout{1} = 'in (V)';
        end        
        
        function varargout = getOutputNamesImpl(~)
            varargout = cell(1,1);
            varargout{1} = 'out (Code)';
        end    
    end
end

MOTIF_if.m

% Copyright (c) 2014, Analog Devices Inc.
% All rights reserved.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:
%
% 1. Redistributions of source code must retain the above copyright
% notice, this list of conditions and the following disclaimer.
%
% 2.Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% 3. Neither the name of the copyright holder nor the names of its
% contributors may be used to endorse or promote products derived from this
% software without specific prior written permission.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
% IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
% PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
% CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
% PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
classdef MOTIF_if < handle
    %UNTITLED Summary of this class goes here
    %   Detailed explanation goes here
    properties (Access = protected)
        key = 0;
    end
    
    methods 
        function obj = MOTIF_if(filename)
            % OS specific code
            if ispc()
                prefix = '';
                suffix = '.dll';
            else
                prefix = 'lib';
                suffix = '.so';
            end
            
            library_name = [prefix 'MOTIF' suffix];
            % Check to see if the library is loaded already
            if (~libisloaded('MOTIF'))
                loadlibrary(library_name, 'MOTIF.h', 'alias', 'MOTIF');
            end
            % Try and resolve absolute path
            if ~exist(filename, 'file')
               tf = ['MOTIF' filesep filename];
               if exist(tf, 'file')
                  filename = tf;
               else
                   error_msg = sprintf('Cannot find model: %s', filename);
                   error(error_msg);
               end
            end
            
            % Load the PMF into memory
            obj.key = calllib('MOTIF', 'ImportPMF', filename);
        end
        
        function key = getKey(obj)
           key = obj.key; 
        end
        
        function isLoaded = isLoaded(obj)
           isLoaded = ~(obj.key == 0);
        end
        
        function interface = queryInterface(obj)
            direction = 0;  % Input
            in_count = obj.getPortCount(direction);
            % Added check for in_count to prevent negative indexing if in_count is 0.
            if in_count > 0
                interface.in = obj.queryPort(direction, in_count - 1);
            else
                % Handle case where no input port is found, e.g., assign default or throw error
                interface.in.f = 1;
                interface.in.is_complex = 0;
                interface.in.domain = '[unspecified]';
                interface.in.unit = '[unspecified]';
            end
            direction = 1;  % Output
            out_count = obj.getPortCount(direction);
            % Added check for out_count.
            if out_count > 0
                interface.out = obj.queryPort(direction, out_count - 1);
            else
                interface.out.f = 1;
                interface.out.is_complex = 0;
                interface.out.domain = '[unspecified]';
                interface.out.unit = '[unspecified]';
            end
            % Ensure interface.in.f is not zero to prevent division by zero
            if interface.in.f ~= 0
                interface.r = interface.out.f / interface.in.f;
            else
                interface.r = 1; % Default or error handling
            end
        end
        
        function [modeName, modeDisplayName] = getMode(obj)
            response = obj.processMessage('<getmode />'); 
            
            modeElements = MOTIF_if.getChildren(response);
            % Added check for empty modeElements
            if isempty(modeElements)
                modeName = '';
                modeDisplayName = '';
                return;
            end
            attributes = MOTIF_if.getAttributes(modeElements(1));
            
            % Added checks for key existence
            modeName = '';
            if isKey(attributes, 'mn')
                modeName = attributes('mn');
            end
            modeDisplayName = '';
            if isKey(attributes, 'mdn')
                modeDisplayName = attributes('mdn');
            end
        end
        
        function modes = queryModes(obj)
            % Returns a Maps that contain the mode display names
            
            response = obj.processMessage('<querymodes />');
            queryModesElements = MOTIF_if.getChildren(response);
            modes = containers.Map; % Initialize modes map
            
            % Added check for empty queryModesElements
            if isempty(queryModesElements)
                return; % Return empty map if no modes are found
            end
            
            modeElements = MOTIF_if.getChildren(queryModesElements(1));
            
            for i = 1:length(modeElements)
                attributes = MOTIF_if.getAttributes(modeElements(i));
                
                % Added check if 'mn' and 'mdn' attribute exists
                if isKey(attributes, 'mn') && isKey(attributes, 'mdn')
                    modes(attributes('mn')) = attributes('mdn');
                end
            end            
        end
        
        function printModes(obj)
            modes = obj.queryModes();
            
            ks = keys(modes);
            for k_idx = 1:length(ks)
                k = ks(k_idx);
                mode = modes(k{1});
                disp([k{1} ' : ' mode]);
            end            
        end
        
        function setMode(obj, mode)
            msg = ['<setmode>' mode '</setmode>'];
            obj.processMessage(msg);            
        end
        
        function [value, displayName, permission, limits, type, unit, toolTip] = getProp(obj, blockName, propName)
            response = obj.processMessage(['<getprop bn="' blockName '" pn="' propName '"/>']);
            getPropElements = MOTIF_if.getChildren(response);
            
            % Added check for empty getPropElements
            if isempty(getPropElements)
                value = ''; displayName = ''; permission = ''; limits = ''; type = ''; unit = ''; toolTip = '';
                return;
            end
            value = MOTIF_if.getText(getPropElements(1));
            attributes = MOTIF_if.getAttributes(getPropElements(1));
            
            % Added checks for key existence
            displayName = ''; if isKey(attributes, 'pdn'), displayName = attributes('pdn'); end
            permission = ''; if isKey(attributes, 'p'), permission = attributes('p'); end
            limits = ''; if isKey(attributes, 'l'), limits = attributes('l'); end
            type = ''; if isKey(attributes, 't'), type = attributes('t'); end
            unit = ''; if isKey(attributes, 'u'), unit = attributes('u'); end
            toolTip = ''; if isKey(attributes, 'tt'), toolTip = attributes('tt'); end
        end
        
        function props = queryProps(obj)
            % Returns a Map of Maps that contain the properties
            % Explanantion of keys -
            %   pn = property name
            %   pdn = property display name
            %   bn = block name
            %   bdn = block display name
            %   p = permissions
            %   l = limits
            %   t = type
            %   u = unit
            %   tt = tool tip
            
            response = obj.processMessage('<queryprops />');
            queryPropsElements = MOTIF_if.getChildren(response);
            props = containers.Map; % Initialize props map
            % Added check for empty queryPropsElements
            if isempty(queryPropsElements)
                return;
            end
            propElements = MOTIF_if.getChildren(queryPropsElements{1});
            
            for i = 1:length(propElements)
                value = MOTIF_if.getText(propElements{i});
                attributes = MOTIF_if.getAttributes(propElements{i});
                attributes('value') = value;
                
                % Added check if 'bn' and 'pn' attributes exist
                if isKey(attributes, 'bn') && isKey(attributes, 'pn')
                    k = [attributes('bn') '.' attributes('pn')];
                    props(k) = attributes;
                end
            end            
        end
        
        function props = queryPropValues(obj)
            % Returns a Map that values
            
            response = obj.processMessage('<queryprops />');
            queryPropsElements = MOTIF_if.getChildren(response);
            props = containers.Map; % Initialize props map
            % Added check for empty queryPropsElements
            if isempty(queryPropsElements)
                return;
            end
            propElements = MOTIF_if.getChildren(queryPropsElements{1});
            
            for i = 1:length(propElements)
                value = MOTIF_if.getText(propElements{i});
                attributes = MOTIF_if.getAttributes(propElements{i});
                
                % Added check if 'bn' and 'pn' attributes exist
                if isKey(attributes, 'bn') && isKey(attributes, 'pn')
                    k = [attributes('bn') '.' attributes('pn')];
                    props(k) = value;
                end
            end
        end
                
        function printProps(obj)
            props = obj.queryProps();
            
            k0s = keys(props);
            for k0_idx = 1:length(k0s)
                k0 = k0s(k0_idx);
                prop = props(k0{1});
                
                disp([k0{1} ' :']);
                
                k1s = keys(prop);
                for k1_idx = 1:length(k1s)
                    k1 = k1s(k1_idx);
                    attribute = prop(k1{1});
                    
                    disp(['  ' k1{1} ' : ' attribute]);
                end
            end
        end
                
        function setProp(obj, blockName, propName, value)
            msg = ['<setprop bn="' blockName '" pn="' propName '">' value '</setprop>'];
            obj.processMessage(msg);
        end
        
        function versionInfo = queryVersion(obj)
            % Returns a Map that contain the version information
            % Explanantion of keys -
            %   dllversion = version of MOTIF simulator
            %   pmfversion = version of Product Model File
            response = obj.processMessage('<queryversion />');
            queryVersionElements = MOTIF_if.getChildren(response);
            % Added check for empty queryVersionElements
            if isempty(queryVersionElements)
                versionInfo = containers.Map; % Return empty map
                return;
            end
            versionInfo = MOTIF_if.getAttributes(queryVersionElements(1));
        end
        
        function printVersion(obj)
            versionInfo = queryVersion(obj);
            if ~isempty(versionInfo) && isKey(versionInfo, 'dllversion') && isKey(versionInfo, 'pmfversion')
                disp(['Library Version: ', versionInfo('dllversion')]);
                disp(['PMF Version: ', versionInfo('pmfversion')]);
            else
                disp('Version information not available.');
            end
        end
                
        function [out, interface] = runSamples(obj, in)
            % Save input length
            len = length(in);
            interface = obj.queryInterface();
                        
            % Format input
            if (interface.in.is_complex)
                tin = zeros(1, len*2); % Pre-allocate for efficiency
                tin(1:2:len*2) = real(in);
                tin(2:2:len*2) = imag(in);
            else
                tin = real(in);
            end
            % Initialize the output code array
            if (interface.out.is_complex)
                out_len = ceil(len*2*interface.r);
            else
                out_len = ceil(len*interface.r);
            end
            
            % Ensure out_len is at least 0 and an integer
            out_len = max(0, floor(out_len)); 
            out = zeros(out_len, 1);
            % Handle case where obj.key might be 0 or if runSamples fails
            if obj.key == 0
                warning('MOTIF_if object not loaded, cannot run samples. Returning zeros.');
                out = zeros(size(in)); % Return zero-filled output of same size as input
                return;
            end
            % Check if tin is empty, calllib might error with empty arrays
            if isempty(tin) && len > 0
                 warning('Input array for RunSamples is empty but expected length > 0. Returning zeros.');
                 out = zeros(out_len, 1);
                 return;
            end
            % If out_len is 0, no need to calllib, just return empty or zeros based on requirement
            if out_len == 0
                out = zeros(0,1); % Return empty column vector if no output samples expected
                return;
            end
            % calllib can sometimes modify tin in place even if not explicitly defined as output.
            % Be aware if there are issues, a copy might be needed: tin_copy = tin;
            [~, ~, out] = calllib('MOTIF', 'RunSamples', tin, out, len, obj.key);
            if (interface.out.is_complex)
                % Ensure idx+1 does not exceed out_len
                % Adjusted to prevent out of bounds access if out_len is odd or too small
                idx = 1:2:(out_len - 1); 
                if ~isempty(idx) % Only proceed if idx is not empty
                    out = out(idx) + 1i*out(idx+1);
                else
                    out = zeros(0,1); % If no valid complex pairs, return empty column vector
                end
            end
        end
        
        function destroy(obj)
            if obj.key ~= 0 && libisloaded('MOTIF')
                calllib('MOTIF', 'Destroy', obj.key);
                obj.key = 0; % Clear key after destroying
            end
        end
    end
    
    methods (Access = protected)
        function count = getPortCount(obj, direction)
            count = 0;
            if obj.key ~= 0 && libisloaded('MOTIF')
                [~, count] = calllib('MOTIF', 'GetPortCount', count, direction, obj.key);
            else
                warning('MOTIF library not loaded or object key is invalid. Returning 0 port count.');
            end
        end
        
        function port = queryPort(obj, direction, index)
            % Initialize return variable with safe defaults
            port.f = 1;
            port.is_complex = 0;
            port.domain = '[unspecified]';
            port.unit = '[unspecified]';
            % Only proceed if index is valid and MOTIF is loaded
            if index < 0 
                warning('Invalid port index (negative). Returning default port info.');
                return;
            end
            if (obj.key == 0) || (~libisloaded('MOTIF'))
                warning('MOTIF library not loaded or object key is invalid. Returning default port info.');
                return
            end
            
            f_val = 1;
            is_complex_val = 0;
            domain_val = 0;
            unitPtr_for_calllib = libpointer('voidPtrPtr'); % 创建 libpointer 对象用于 calllib
            % 调用 calllib,并捕获第五个输出参数,它将是 C 函数写入到 unitPtr_for_calllib 中的实际指针地址。
            [~, f, is_complex, domain, actual_unit_ptr_value] = calllib('MOTIF', 'QueryPort', f_val, is_complex_val, domain_val, unitPtr_for_calllib, direction, index, obj.key);
            port.f = f;
            port.is_complex = is_complex;
            if domain == 1
                port.domain = 'analog';
            elseif domain == 2
                port.domain = 'digital';
            else
                port.domain = '[unspecified]';
            end
            % 检查返回的指针地址是否为 NULL (0)
            if actual_unit_ptr_value ~= 0 
                % 如果不是 NULL,则使用该地址创建一个新的 libpointer,并指定其为字符串指针
                unit_str_ptr = libpointer('stringPtr', actual_unit_ptr_value);
                port.unit = unit_str_ptr.Value; % 安全地检索字符串值
            else
                port.unit = '[unspecified]'; % 如果是 NULL 指针,使用默认值
            end
        end
        
        function response = processMessage(obj, msg)
            response = ''; % Initialize response as empty string
            msg = ['<motif>' msg '</motif>'];
            if (obj.key == 0) || (~libisloaded('MOTIF'))
                warning('MOTIF library not loaded or object key is invalid. Cannot process message.');
                return;
            end
            
            responsePtr = libpointer('voidPtrPtr'); % 创建 libpointer 对象
            % 调用 calllib,并捕获第三个输出参数,它将是 C 函数写入到 responsePtr 中的实际指针地址。
            [~, ~, actual_response_ptr_value] = calllib('MOTIF', 'ProcessMessage', msg, responsePtr, obj.key);
            % 检查返回的指针地址是否为 NULL (0)
            if actual_response_ptr_value ~= 0 
                % 如果不是 NULL,则使用该地址创建一个新的 libpointer,并指定其为字符串指针
                string_ptr = libpointer('stringPtr', actual_response_ptr_value);
                response = string_ptr.Value; % 安全地检索字符串值
            else
                warning('Received NULL response pointer from MOTIF ProcessMessage.');
                % response 已经初始化为空字符串,无需额外处理
            end
        end
    end
    
    methods (Static, Access = public)
        function destroyAll()
           if (libisloaded('MOTIF')) % only call if loaded
               calllib('MOTIF', 'DestroyAll');
               unloadlibrary('MOTIF')
           end 
        end
        
        function str = bool2str(boolVal)
           if (boolVal)
                str = 'true';
            else
                str = 'false';
            end 
        end
    end
    
    methods (Static, Access = protected)
        function childrenStrings = getChildren(xmlString)
            xmlString = char(xmlString);
            childrenStrings = {}; % 初始值为空,以便在解析失败时直接返回
            % 1. 检查输入的 XML 字符串是否为空
            if isempty(xmlString)
                return;
            end
            % 查找当前元素的起始标签 '>'
            gt_indices = strfind(xmlString, '>');
            if isempty(gt_indices)
                % 如果没有找到 '>', 说明 XML 格式不完整或错误
                return;
            end
            firstChildIdx = gt_indices(1) + 1; % 第一个 '>' 字符的下一个位置
            % 2. 检查提取元素名称的索引范围是否有效
            elementEndIdx = firstChildIdx - 2;
            if elementEndIdx < 1 || elementEndIdx > length(xmlString)
                % 尝试处理 <element/> 这种情况
                if ~isempty(strfind(xmlString, '/>')) && (firstChildIdx - 2 == strfind(xmlString, '/>'))
                    return; % 这是一个自闭合标签,没有子节点
                end
                return; % 否则,无法解析
            end
            element = xmlString(2:elementEndIdx); % 提取元素名
            idx_space = strfind(element, ' ');
            if ~isempty(idx_space)
               element = element(1:idx_space(1)-1);
            end
            
            % 如果 element 是空字符串,也无法继续解析
            if isempty(element)
                return;
            end
            % 查找对应的结束标签
            lastChildIdx_candidate = strfind(xmlString, ['</' element '>']);
            % 3. 处理自闭合标签(如 <tag />)和常规标签
            if isempty(lastChildIdx_candidate)
                % 如果没有找到显式的结束标签,检查是否为自闭合标签
                selfClosingIdx = strfind(xmlString, '/>');
                if ~isempty(selfClosingIdx) && selfClosingIdx(1) < firstChildIdx
                    return; % 自闭合元素,没有子节点
                end
                return; % 否则,既不是常规结束标签也不是自闭合,无法解析子节点
            end
            lastChildIdx = lastChildIdx_candidate(1) - 1; % 结束标签开始前的位置
            % 4. 确保冒号操作符的范围有效 (lastChildIdx 必须大于或等于 firstChildIdx)
            if lastChildIdx < firstChildIdx
                return; % 范围无效(例如,结束标签在内容之前),或者没有内容
            end
            rest = xmlString(firstChildIdx:lastChildIdx);
            % 分割子字符串
            while ~isempty(rest)
                % 查找当前内部元素的起始标签 '>'
                iStart_candidates = strfind(rest, '>');
                if isempty(iStart_candidates)
                    break; % 'rest' 字符串格式错误,没有更多元素
                end
                iStart = iStart_candidates(1) + 1;
                % 5. 对内部元素重复索引范围检查
                innerElementEndIdx = iStart - 2;
                if innerElementEndIdx < 1 || innerElementEndIdx > length(rest)
                    % 尝试处理 <element/> 这种情况
                    if ~isempty(strfind(rest, '/>'))
                        currentElementSelfClosingEnd = strfind(rest(1:min(length(rest), iStart-1)), '/>');
                        if ~isempty(currentElementSelfClosingEnd)
                            childrenStrings = [childrenStrings; {rest(1:currentElementSelfClosingEnd(1)+1)}];
                            rest = rest(currentElementSelfClosingEnd(1)+2:end);
                            continue;
                        end
                    end
                    break; % 内部元素起始位置错误,停止解析
                end
                element = rest(2:innerElementEndIdx); % 提取内部元素名
                idx_space_inner = strfind(element, ' ');
                if ~isempty(idx_space_inner)
                   element = element(1:idx_space_inner(1)-1);
                end
                
                % 如果 element 是空字符串,也无法继续解析
                if isempty(element)
                    break;
                end
                % 查找内部元素的结束标签
                iStop_candidates = strfind(rest, ['</' element '>']);
                if ~isempty(iStop_candidates)
                    iStop_val = iStop_candidates(1) + 3 + length(element) - 1; % 结束标签的结束位置
                    if iStop_val > length(rest)
                        break; % 结束索引超出范围
                    end
                    childrenStrings = [childrenStrings; {rest(1:iStop_val)}];
                    rest = rest(iStop_val+1:end);
                else
                    % 检查是否为内部的自闭合标签
                    iStop_selfClosing_candidates = strfind(rest, '/>');
                    if ~isempty(iStop_selfClosing_candidates) && iStop_selfClosing_candidates(1) < iStart 
                        iStop_val = iStop_selfClosing_candidates(1) + 1; % '/>' 的结束位置
                        if iStop_val > length(rest)
                            break; % 结束索引超出范围
                        end
                        childrenStrings = [childrenStrings; {rest(1:iStop_val)}];
                        rest = rest(iStop_val+1:end);
                    else
                        break; % 没有找到有效的结束或自闭合标签,停止解析
                    end
                end
            end
        end
        
        function attributes = getAttributes(elementString)
            elementString = char(elementString);
            attributes = containers.Map;
            
            idx_gt = strfind(elementString, '>');
            if isempty(idx_gt)
                return; % Invalid XML fragment, no opening tag found
            end
            end_of_opening_tag = idx_gt(1); 
            
            idx_first_space = strfind(elementString(1:end_of_opening_tag), ' ');
            
            if isempty(idx_first_space)
                return; % No attributes
            end
            
            attr_start_idx = idx_first_space(1) + 1;
            attr_end_idx = end_of_opening_tag - 1;
            idx_self_closing = strfind(elementString(1:end_of_opening_tag), '/>');
            if ~isempty(idx_self_closing)
                 attr_end_idx = idx_self_closing(1) - 1;
                 if attr_end_idx < attr_start_idx
                     return; % No attributes
                 end
            end
            
            if attr_end_idx < attr_start_idx
                return; % No attributes found or malformed
            end
            attr_string = elementString(attr_start_idx : attr_end_idx);
            
            current_pos = 1;
            while current_pos <= length(attr_string)
                % Skip leading spaces
                while current_pos <= length(attr_string) && isspace(attr_string(current_pos))
                    current_pos = current_pos + 1;
                end
                if current_pos > length(attr_string)
                    break; % Reached end of string
                end
                
                % Find the '=' for the attribute name
                idx_eq_relative = strfind(attr_string(current_pos:end), '=');
                if isempty(idx_eq_relative)
                    break; % Malformed attribute (no = sign)
                end
                idx_eq_abs = current_pos + idx_eq_relative(1) - 1; 
                
                % Extract attribute name (key)
                k = strtrim(attr_string(current_pos : idx_eq_abs - 1));
                
                % Move past '='
                current_pos = idx_eq_abs + 1;
                
                % Check for opening quote
                if current_pos > length(attr_string) || attr_string(current_pos) ~= '"'
                    break; % Malformed attribute (no opening quote or empty string)
                end
                
                % Move past opening quote
                current_pos = current_pos + 1;
                
                % Find closing quote
                idx_quote_relative = strfind(attr_string(current_pos:end), '"');
                if isempty(idx_quote_relative)
                    break; % Malformed attribute (no closing quote)
                end
                idx_quote_abs = current_pos + idx_quote_relative(1) - 1; 
                
                % Extract value
                if (idx_quote_abs - 1) < current_pos
                    value = ''; % Handle empty value like attr=""
                else
                    value = attr_string(current_pos : idx_quote_abs - 1);
                end
                
                attributes(k) = value;
                
                % Move past closing quote
                current_pos = idx_quote_abs + 1;
            end
        end
        
        function text = getText(elementString)
            elementString = char(elementString);
            
            text = '';
            idx_self_closing = strfind(elementString, '/>');
            if ~isempty(idx_self_closing)
                return
            end    
            
            iStart_candidates = strfind(elementString, '>');
            iStop_candidates = strfind(elementString, '<');
            if isempty(iStart_candidates) || isempty(iStop_candidates)
                return; % Invalid XML fragment
            end
            iStart = iStart_candidates(1) + 1;
            iStop_after_start = iStop_candidates(iStop_candidates > iStart_candidates(1));
            if isempty(iStop_after_start)
                return; % No closing tag found after opening tag
            end
            
            if iStart <= length(elementString) && iStop_after_start(1) >= iStart
                 text = elementString(iStart:iStop_after_start(1)-1); 
            else
                 text = ''; % No valid text found or invalid range
            end
        end
    end
end




扫描二维码推送至手机访问。

版权声明:本文由我的FPGA发布,如需转载请注明出处。

本文链接:http://myfpga.cn/index.php/post/464.html

分享给朋友:

“ADI ADC Simulink Model 在MatlabR2025a上适配修改,解决警告和报错的问题(以AD9268为例,其他的也可使用)” 的相关文章

普源示波器csv文件读取程序 Matlab 计算FFT 去除直流偏执

普源示波器csv文件读取程序 Matlab 计算FFT 去除直流偏执

%% 清空缓存 clc; clear; close all; %% 参数定义 % 通道选择 (1: 启用, 0: 禁用) enable_CH1 = 1; %&nb...