www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/@mdevtestplan/pAssessDataChanges.m
function [out,questMsg] = pAssessDataChanges(T, newData) %PASSESSDATACHANGES work out what has changed in the test plan data % % PASSESSDATACHANGES(T, NEWTSSF, OLDTSSF) % % Copyright 2000-2015 The MathWorks, Inc. and Ford Global Technologies, Inc. % Create the output structure to indicate the changes out = struct(... 'INPUT_SIGNAL_REMOVED', false,... 'RESPONSE_SIGNAL_REMOVED', false,... 'MONITOR_SIGNAL_REMOVED', false,... 'ACTUAL_DESIGN_CHANGED', false,... 'INPUT_DATA_CHANGED', false,... 'RESPONSE_DATA_CHANGED', false,... 'DATA_CHANGED', false,... 'KeepValidationData',false,... 'InputSignalsFound', [],... 'InputSignalsMissing', {cell(0,1)},... 'InputSignalsChanged', {cell(0,1)},... 'InputSignalsUnchanged', {cell(0,1)},... 'ResponseSignalsFound', [],... 'ResponseHasValidDatum', [],... 'ResponseSignalsMissing', {cell(1,0)},... 'ResponseDatumMissing', {cell(1,0)},... 'ResponseSignalsChanged', {cell(1,0)},... 'ResponseSignalsUnchanged', {cell(1,0)},... 'MonitorSignalsMissing', {{}},... 'OldData', [],... 'ResponsesToKeep',false); % Some definitions ... % nI is the number of inputs to the testplan % nR is the number of current or pending responses in the testplan % INPUT_SIGNAL_REMOVED - logical : An input signal is missing or of zero length % RESPONSE_SIGNAL_REMOVED - logical : A response signal is missing or of zero length % MONITOR_SIGNAL_REMOVED - logical : A monitor signal is missing or of zero length % ACTUAL_DESIGN_CHANGED - logical : The ActualDesign has changed % INPUT_DATA_CHANGED - logical : An input signal is different (value or test) % RESPONSE_DATA_CHANGED - logical : A response signal is different (value or test) % DATA_CHANGED - logical : The data is different % KeepValidationData - logical : keep validation data (input signals % must be in validation data set). % InputSignalsFound - Logical array (1xnI) : Input signals that exist. % InputSignalsMissing - Cell array of string : Signals missing % InputSignalsChanged - Cell array of string : Signals changed % InputSignalsUnchanged - Cell array of string : Signals that are the same % ResponseSignalsFound - Logical array (1xnR) : Response signals that exist. % ResponseHasValidDatum - Logical array (1xnR) : Response signals that have a valid datum % ResponseSignalsMissing - Cell array of string : Signals missing % ResponseDatumMissing - Cell array of string : Datum missing % ResponseSignalsChanged - Cell array of string : Signals changed % ResponseSignalsUnchanged - Cell array of string : Signals that are the same % MonitorSignalsMissing - Cell array of string : Signals missing % ResponsesToKeep - Logical array of responses to keep in tree % Get the old and new data - need to deal carefully with the case where the % testplan is unmatched as oldData isn't what was previously in the testplan if IsMatched(T) out.OldData = T.DataLink.info; else out.OldData = testplansweepsetfilter; end % Convert to sweepsets as we aren't actually interesed in much from % the tssf itself - will look at the ActualDesign in a minute newSS = sweepset(newData); oldSS = sweepset(out.OldData); % Get the new siganl names newNames = get(newSS, 'Name'); % Get the important signals for this testplan inputSignalNames = factorNames(designdev(T)); [responseSignalNames,responsesToKeep] = iGetResponseNames(T); % Remember monitor isn't always a structure and T.Monitor.values might be % empty if ~isempty(T.Monitor) && ~isempty(T.Monitor.values) monitorSignalNames = unique([T.Monitor.values ; T.Monitor.Xdata]); else monitorSignalNames = {}; end SIGNALS_FOUND = size(newSS, 1) > 0; % Which signals still exist - no data in an input signal is as bad as the % signal itself being missing inputSignalsFound = ismember(inputSignalNames, newNames) & SIGNALS_FOUND; responseSignalsFound = ismember(responseSignalNames, newNames) & SIGNALS_FOUND; monitorSignalsFound = ismember(monitorSignalNames, newNames) & SIGNALS_FOUND; out.INPUT_SIGNAL_REMOVED = ~all(inputSignalsFound); out.RESPONSE_SIGNAL_REMOVED = ~all(responseSignalsFound); out.MONITOR_SIGNAL_REMOVED = ~all(monitorSignalsFound); out.InputSignalsMissing = inputSignalNames(~inputSignalsFound,1); out.ResponseSignalsMissing = responseSignalNames(1,~responseSignalsFound); out.MonitorSignalsMissing = monitorSignalNames(~monitorSignalsFound); % all input signals must be in validation data set valssf = valdata(T); if ~isempty(valssf) ValSignals = get(valssf,'Name'); out.KeepValidationData = all( ismember(inputSignalNames,ValSignals) ); end responseHasValidDatum = responseSignalsFound; % Which responses will need to be removed because a datum response is being % deleted - NOTE that the datum response is ALWAYS the first response if ~isempty(responseSignalsFound) && ~responseSignalsFound(1) % Which other responses need to be removed linkedIndex = getDatumLinkedResponseIndex(T); responseHasValidDatum(linkedIndex) = false; out.ResponseDatumMissing = responseSignalNames(1,linkedIndex); end out.InputSignalsFound = inputSignalsFound; out.ResponseSignalsFound = responseSignalsFound; out.ResponseHasValidDatum = responseHasValidDatum; % find responses to Keep - these might be changed by the responses to % remove responsesToRemove = ~(out.ResponseSignalsFound & out.ResponseHasValidDatum); for i= find(responsesToKeep) responsesToKeep(i) = ~responsesToRemove(i); end out.ResponsesToKeep = responsesToKeep; % Check for tests changing - this constitutes a change to the data that % will not be picked up by an isequal(double, double) test and which does % represent a very real modification TESTS_CHANGED = ~isequal(getGuids(oldSS), getGuids(newSS)) || ... ~isequal(getSweepGuids(oldSS), getSweepGuids(newSS)); out.DATA_CHANGED = TESTS_CHANGED || ... ~isequaln(double(oldSS), double(newSS)) ; % Has the actual design changed newDesign = get(newData, 'codeddesign'); oldDesign = ActualDesign(T); out.ACTUAL_DESIGN_CHANGED = ~isequal(factorsettings(oldDesign), factorsettings(newDesign)); % A base assumption for the rest of this code is that all named signals % exist in the oldSS - this is not the case when oldSS is empty, as in the % initialisation of the test plan. If this is the case then we need to fill % in the extra fields appropriately. NOTE the initialisation will occur % when T is not matched if ~IsMatched(T) out.INPUT_DATA_CHANGED = true; out.RESPONSE_DATA_CHANGED = true; out.InputSignalsChanged = inputSignalNames(inputSignalsFound); out.ResponseSignalsChanged = responseSignalNames(responseSignalsFound & responseHasValidDatum); else % Check the input data for consistency dblInOld = double(oldSS(:, inputSignalNames(inputSignalsFound))); dblInNew = double(newSS(:, inputSignalNames(inputSignalsFound))); out.INPUT_DATA_CHANGED = out.INPUT_SIGNAL_REMOVED || ... TESTS_CHANGED || ... ~isequaln(dblInOld, dblInNew); if ~out.INPUT_DATA_CHANGED && numChildren(T) > 0 out.RESPONSE_DATA_CHANGED = ~all(out.ResponsesToKeep) || ... length(T.Responses)>length(out.ResponsesToKeep); % check whether input signal definition (range, symbols) has changed models = children(T, @model); baseModel = HSModel(T.DesignDev); if isa(models{1},'localmulti') % Point-by-point model baseModel = get(baseModel,'Local'); end out.INPUT_DATA_CHANGED = ~hasSameInputs(baseModel,models{1}); out.DATA_CHANGED= out.DATA_CHANGED || out.INPUT_DATA_CHANGED || ... out.RESPONSE_DATA_CHANGED; else out.RESPONSE_DATA_CHANGED = false; end if out.INPUT_DATA_CHANGED % Which inputs have been changed out = iInputSignals(out,inputSignalNames,TESTS_CHANGED,dblInOld,dblInNew); else % No changes to the input signals mean that they must all be unchanged out.InputSignalsUnchanged = inputSignalNames; end % Implicit change to a response if the input data has changed dblRespOld = double(oldSS(:, responseSignalNames(responseSignalsFound))); dblRespNew = double(newSS(:, responseSignalNames(responseSignalsFound))); out.RESPONSE_DATA_CHANGED = out.RESPONSE_DATA_CHANGED || ... out.RESPONSE_SIGNAL_REMOVED || ... out.INPUT_DATA_CHANGED || ... ~isequaln(dblRespOld, dblRespNew); if out.RESPONSE_DATA_CHANGED % Which responses have been changed out = iResponseSignals(out,responseSignalNames,dblRespOld,dblRespNew); else % No changes to the response signals mean that they must all be unchanged out.ResponseSignalsUnchanged = responseSignalNames; end end if nargout>1 questMsg = iCreateMessages(T, out); end % iGetResponseNames function [responseNames, responsesToKeep] = iGetResponseNames(T) % Default is no responses % Responses are either the children of a testplan or they have yet to be % built and reside in the Response field of the testplan if numChildren(T) > 0 responseNames = children(T, @varname); models = children(T, @model); responsesToKeep = false(1,length(models)); for i=1:min(length(models),length(T.Responses)) % check that model is the same % cleanup is called to remove any non persistent data such as % xreglinear.Store from the object before comparison responsesToKeep(i) = isequal(cleanup(models{i}),cleanup(T.Responses{i})); if ~responsesToKeep(i) % once a response which cannot be kept is found, all subsequent % responses will be rebuilt. This is so the order of the % responses remains as it was in the wizard and the Model % Browser tree. break end end for j = i:length(T.Responses) % new responses responseNames{j} = varname(T.Responses{j}); end responseNames = responseNames(1,1:length(T.Responses)); else responseNames = cell(1,length(T.Responses)); for i = 1:length(T.Responses) responseNames{i}= varname(T.Responses{i}); end responsesToKeep = false(0,1); end % iInputSignals function out = iInputSignals(out,inputSignalNames,TESTS_CHANGED,dblInOld,dblInNew) % Which inputs have been changed for i = 1:length(inputSignalNames) % Only check inputs that have been found if out.InputSignalsFound(i) % Calculate index into the available input data thisIndex = sum(out.InputSignalsFound(1:i)); % Are the values different if TESTS_CHANGED || ... ~isequaln(dblInOld(:, thisIndex), dblInNew(:, thisIndex)) out.InputSignalsChanged(end+1,1) = inputSignalNames(i); else out.InputSignalsUnchanged(end+1,1) = inputSignalNames(i); end end end % iResponseSignals function out = iResponseSignals(out,responseSignalNames,dblRespOld,dblRespNew) for i = 1:length(responseSignalNames) % Only check responses that have been found and have valid DATUM's if out.ResponseSignalsFound(i) && out.ResponseHasValidDatum(i) % Calculate index into the available input data thisIndex = sum(out.ResponseSignalsFound(1:i)); % Is their data different - note implicit change if INPUT_DATA_CHANGED if out.INPUT_DATA_CHANGED || ... ~isequaln(dblRespOld(:, thisIndex), dblRespNew(:, thisIndex)) out.ResponseSignalsChanged{end+1} = responseSignalNames{i}; elseif i<=length(out.ResponsesToKeep) if out.ResponsesToKeep(i) out.ResponseSignalsUnchanged{end+1} = responseSignalNames{i}; else out.ResponseSignalsChanged{end+1} = responseSignalNames{i}; end else out.ResponseSignalsChanged{end+1} = responseSignalNames{i}; end end end % iCreateMessages function questMsg = iCreateMessages(T, changes) % We have 2 messages to set up - one that relates to the actual re-fit % process and what is happening and one that is the question we ask the % user to tell them what is going to happen % OK - What has happened to the data and how do we form the correct % messages to the user? Need to take account of the current state of the % testplan - it might not have any models yet if changes.INPUT_SIGNAL_REMOVED % Worst case - An input signal has been removed and the user must % revert to the original testplan questMsg{1} = i_selectMessagePlurality( ... ['The model input signal %s is missing from the new data. ', ... 'This signal cannot be removed while it is being used in a model.'], ... ['The model input signals %s are missing from the new data. ', ... 'These signals cannot be removed while they are being used in a model.'], ... changes.InputSignalsMissing); questMsg{2} = ''; questMsg{3} = 'Your changes will be discarded and the testplan will revert to using its previous data.'; questMsg{4} = ''; elseif changes.RESPONSE_SIGNAL_REMOVED questMsg{1} = i_selectMessagePlurality( ... ['Missing response model %s: the response signal is missing.', ... 'This signal cannot be removed while it is being used in a model.'],... ['Missing response models %s: the response signals are missing.', ... 'These signals cannot be removed while it is being used in a model.'],... changes.ResponseSignalsMissing); questMsg{2} = ''; questMsg{3} = 'Your changes will be discarded and the testplan will revert to using its previous data.'; questMsg{4} = ''; else questMsg = {}; if IsMatched(T) || numChildren(T)>0 % Do any responses have missing datum's if ~isempty(changes.ResponseDatumMissing) questMsg{end+1} = i_selectMessagePlurality( ... 'Missing response model %s: the datum model has been deleted.', ... 'Missing response models %s: the datum model has been deleted.', ... changes.ResponseDatumMissing); end % We know that there are some responses left - what will the data % changes do to them if ~isempty(changes.ResponseSignalsChanged) if changes.INPUT_DATA_CHANGED questMsg{end+1} = 'Refit all response models: the input data has changed.'; else RespNames= children(T,@varname); if ~isempty(T.Responses) NewRespNames= cellfun(@varname,T.Responses,'UniformOutput',false); else NewRespNames = {}; end % responses to delete OKdelete = ~ismember(RespNames,NewRespNames); RespDelete = RespNames(OKdelete); if ~isempty(RespDelete) questMsg{end+1} = i_selectMessagePlurality( ... 'Delete response model %s.', ... 'Delete response models %s.', ... RespDelete); end % Responses to refit OKrefit = ismember(changes.ResponseSignalsChanged,RespNames(changes.ResponsesToKeep)); RespToRefit = changes.ResponseSignalsChanged(OKrefit); if ~isempty(RespToRefit) questMsg{end+1} = i_selectMessagePlurality( ... 'Refit response model %s: the response data has changed.', ... 'Refit response models %s: the response data has changed.', ... RespToRefit); end % models to rebuild OKrebuild = ismember(changes.ResponseSignalsChanged,RespNames(~changes.ResponsesToKeep)); RespToRebuild = setdiff(changes.ResponseSignalsChanged(OKrebuild),RespDelete); if ~isempty(RespToRebuild) questMsg{end+1} = i_selectMessagePlurality( ... 'Rebuild response model %s: the model has changed.', ... 'Rebuild response models %s: the models have changed.', ... RespToRebuild); end % new responses AllRespProcessed = [RespToRebuild,RespToRefit RespDelete]; NewResponses = setdiff(changes.ResponseSignalsChanged,AllRespProcessed); if ~isempty(NewResponses) questMsg{end+1} = i_selectMessagePlurality( ... 'Build new response model for %s.', ... 'Build new response models for %s.', ... NewResponses); end end elseif ~all(changes.ResponsesToKeep) RespDelete = children(T,~changes.ResponsesToKeep,@varname); questMsg{end+1} = i_selectMessagePlurality( ... 'Delete response model %s.', ... 'Delete response models %s.', ... RespDelete); end else % Do any responses have missing datum's if ~isempty(changes.ResponseDatumMissing) questMsg{end+1} = i_selectMessagePlurality( ... 'Missing response model %s: the datum model has been deleted.', ... 'Missing response models %s: the datum model has been deleted.', ... changes.ResponseDatumMissing); end if ~isempty([changes.ResponseSignalsChanged changes.ResponseSignalsUnchanged]); questMsg{end+1} = i_selectMessagePlurality( ... 'Build response model %s.', ... 'Build response models %s.', ... [changes.ResponseSignalsChanged changes.ResponseSignalsUnchanged]); end end % Are we going to update the actual design if changes.ACTUAL_DESIGN_CHANGED questMsg{end+1} = 'Update the experimental design "Actual Design".'; end if changes.INPUT_DATA_CHANGED && ~isnull(T.ConstraintData) if isequal(factors(T),get(T.ConstraintData.getdata,'Name')) questMsg{end+1} = 'Refit all boundary models.'; else questMsg{end+1} = 'Delete all boundary models.'; end end valssf = valdata(T); if ~isempty(valssf) && ~changes.KeepValidationData questMsg{end+1} = 'Remove validation data.'; end % If anything has changed with the data or design then ask the user if they % want to accept the changes if ~isempty(questMsg) % Add a bullet point to all messages for n = 1:length(questMsg) questMsg{n} = ['\bullet ', questMsg{n}]; end % Tag on a prefix intro and postfix question questMsg = [{'The following changes need to be made to the project:'}, ... {''}, ... questMsg, ... {''}, ... {'Do you want to make these changes?'}, ... {''}]; end end % i_commaDelimit function str = i_commaDelimit(strings) % Escape any tex characters strings = detex(strings); if isscalar(strings) str = strings{1}; else str = sprintf('%s, ', strings{1:end-1}); str = sprintf('%s and %s', str(1:end-2), strings{end}); end % i_selectMessagePlurality function str = i_selectMessagePlurality(singularMsg, pluralMsg, strings) if isscalar(strings) str = sprintf(singularMsg, i_commaDelimit(strings)); else str = sprintf(pluralMsg, i_commaDelimit(strings)); end