LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
derivest.m
1function [der,errest,finaldelta] = derivest(fun,x0,varargin)
2% DERIVEST: estimate the n'th derivative of fun at x0, provide an error estimate
3% usage: [der,errest] = DERIVEST(fun,x0) % first derivative
4% usage: [der,errest] = DERIVEST(fun,x0,prop1,val1,prop2,val2,...)
5%
6% Derivest will perform numerical differentiation of an
7% analytical function provided in fun. It will not
8% differentiate a function provided as data. Use gradient
9% for that purpose, or differentiate a spline model.
10%
11% The methods used by DERIVEST are finite difference
12% approximations of various orders, coupled with a generalized
13% (multiple term) Romberg extrapolation. This also yields
14% the error estimate provided. DERIVEST uses a semi-adaptive
15% scheme to provide the best estimate that it can by its
16% automatic choice of a differencing interval.
17%
18% Finally, While I have not written this function for the
19% absolute maximum speed, speed was a major consideration
20% in the algorithmic design. Maximum accuracy was my main goal.
21%
22%
23% Arguments (input)
24% fun - function to differentiate. May be an inline function,
25% anonymous, or an m-file. fun will be sampled at a set
26% of distinct points for each element of x0. If there are
27% additional parameters to be passed into fun, then use of
28% an anonymous function is recommended.
29%
30% fun should be vectorized to allow evaluation at multiple
31% locations at once. This will provide the best possible
32% speed. IF fun is not so vectorized, then you MUST set
33% 'vectorized' property to 'no', so that derivest will
34% then call your function sequentially instead.
35%
36% Fun is assumed to return a result of the same
37% shape as its input x0.
38%
39% x0 - scalar, vector, or array of points at which to
40% differentiate fun.
41%
42% Additional inputs must be in the form of property/value pairs.
43% Properties are character strings. They may be shortened
44% to the extent that they are unambiguous. Properties are
45% not case sensitive. Valid property names are:
46%
47% 'DerivativeOrder', 'MethodOrder', 'Style', 'RombergTerms'
48% 'FixedStep', 'MaxStep'
49%
50% All properties have default values, chosen as intelligently
51% as I could manage. Values that are character strings may
52% also be unambiguously shortened. The legal values for each
53% property are:
54%
55% 'DerivativeOrder' - specifies the derivative order estimated.
56% Must be a positive integer from the set [1,2,3,4].
57%
58% DEFAULT: 1 (first derivative of fun)
59%
60% 'MethodOrder' - specifies the order of the basic method
61% used for the estimation.
62%
63% For 'central' methods, must be a positive integer
64% from the set [2,4].
65%
66% For 'forward' or 'backward' difference methods,
67% must be a positive integer from the set [1,2,3,4].
68%
69% DEFAULT: 4 (a second order method)
70%
71% Note: higher order methods will generally be more
72% accurate, but may also suffere more from numerical
73% problems.
74%
75% Note: First order methods would usually not be
76% recommended.
77%
78% 'Style' - specifies the style of the basic method
79% used for the estimation. 'central', 'forward',
80% or 'backwards' difference methods are used.
81%
82% Must be one of 'Central', 'forward', 'backward'.
83%
84% DEFAULT: 'Central'
85%
86% Note: Central difference methods are usually the
87% most accurate, but sometiems one must not allow
88% evaluation in one direction or the other.
89%
90% 'RombergTerms' - Allows the user to specify the generalized
91% Romberg extrapolation method used, or turn it off
92% completely.
93%
94% Must be a positive integer from the set [0,1,2,3].
95%
96% DEFAULT: 2 (Two Romberg terms)
97%
98% Note: 0 disables the Romberg step completely.
99%
100% 'FixedStep' - Allows the specification of a fixed step
101% size, preventing the adaptive logic from working.
102% This will be considerably faster, but not necessarily
103% as accurate as allowing the adaptive logic to run.
104%
105% DEFAULT: []
106%
107% Note: If specified, 'FixedStep' will define the
108% maximum excursion from x0 that will be used.
109%
110% 'Vectorized' - Derivest will normally assume that your
111% function can be safely evaluated at multiple locations
112% in a single call. This would minimize the overhead of
113% a loop and additional function call overhead. Some
114% functions are not easily vectorizable, but you may
115% (if your matlab release is new enough) be able to use
116% arrayfun to accomplish the vectorization.
117%
118% When all else fails, set the 'vectorized' property
119% to 'no'. This will cause derivest to loop over the
120% successive function calls.
121%
122% DEFAULT: 'yes'
123%
124%
125% 'MaxStep' - Specifies the maximum excursion from x0 that
126% will be allowed, as a multiple of x0.
127%
128% DEFAULT: 100
129%
130% 'StepRatio' - Derivest uses a proportionally cascaded
131% series of function evaluations, moving away from your
132% point of evaluation. The StepRatio is the ratio used
133% between sequential steps.
134%
135% DEFAULT: 2.0000001
136%
137% Note: use of a non-integer stepratio is intentional,
138% to avoid integer multiples of the period of a periodic
139% function under some circumstances.
140%
141%
142% See the document DERIVEST.pdf for more explanation of the
143% algorithms behind the parameters of DERIVEST. In most cases,
144% I have chosen good values for these parameters, so the user
145% should never need to specify anything other than possibly
146% the DerivativeOrder. I've also tried to make my code robust
147% enough that it will not need much. But complete flexibility
148% is in there for your use.
149%
150%
151% Arguments: (output)
152% der - derivative estimate for each element of x0
153% der will have the same shape as x0.
154%
155% errest - 95% uncertainty estimate of the derivative, such that
156%
157% abs(der(j) - f'(x0(j))) < erest(j)
158%
159% finaldelta - The final overall stepsize chosen by DERIVEST
160%
161%
162% Example usage:
163% First derivative of exp(x), at x == 1
164% [d,e]=derivest(@(x) exp(x),1)
165% d =
166% 2.71828182845904
167%
168% e =
169% 1.02015503167879e-14
170%
171% True derivative
172% exp(1)
173% ans =
174% 2.71828182845905
175%
176% Example usage:
177% Third derivative of x.^3+x.^4, at x = [0,1]
178% derivest(@(x) x.^3 + x.^4,[0 1],'deriv',3)
179% ans =
180% 6 30
181%
182% True derivatives: [6,30]
183%
184%
185% See also: gradient
186%
187%
188% Author: John D'Errico
189% e-mail: woodchips@rochester.rr.com
190% Release: 1.0
191% Release date: 12/27/2006
192
193par.DerivativeOrder = 1;
194par.MethodOrder = 4;
195par.Style = 'central';
196par.RombergTerms = 2;
197par.FixedStep = [];
198par.MaxStep = 100;
199% setting a default stepratio as a non-integer prevents
200% integer multiples of the initial point from being used.
201% In turn that avoids some problems for periodic functions.
202par.StepRatio = 2.0000001;
203par.NominalStep = [];
204par.Vectorized = 'yes';
205
206na = length(varargin);
207if (rem(na,2)==1)
208 error 'Property/value pairs must come as PAIRS of arguments.'
209elseif na>0
210 par = parse_pv_pairs(par,varargin);
211end
212par = check_params(par);
213
214% Was fun a string, or an inline/anonymous function?
215if (nargin<1)
216 help derivest
217 return
218elseif isempty(fun)
219 error 'fun was not supplied.'
220elseif ischar(fun)
221 % a character function name
222 fun = str2func(fun);
223end
224
225% no default for x0
226if (nargin<2) || isempty(x0)
227 error 'x0 was not supplied'
228end
229par.NominalStep = max(x0,0.02);
230
231% was a single point supplied?
232nx0 = size(x0);
233n = prod(nx0);
234
235% Set the steps to use.
236if isempty(par.FixedStep)
237 % Basic sequence of steps, relative to a stepsize of 1.
238 delta = par.MaxStep*par.StepRatio .^(0:-1:-25)';
239 ndel = length(delta);
240else
241 % Fixed, user supplied absolute sequence of steps.
242 ndel = 3 + ceil(par.DerivativeOrder/2) + ...
243 par.MethodOrder + par.RombergTerms;
244 if par.Style(1) == 'c'
245 ndel = ndel - 2;
246 end
247 delta = par.FixedStep*par.StepRatio .^(-(0:(ndel-1)))';
248end
249
250% generate finite differencing rule in advance.
251% The rule is for a nominal unit step size, and will
252% be scaled later to reflect the local step size.
253fdarule = 1;
254switch par.Style
255 case 'central'
256 % for central rules, we will reduce the load by an
257 % even or odd transformation as appropriate.
258 if par.MethodOrder==2
259 switch par.DerivativeOrder
260 case 1
261 % the odd transformation did all the work
262 fdarule = 1;
263 case 2
264 % the even transformation did all the work
265 fdarule = 2;
266 case 3
267 % the odd transformation did most of the work, but
268 % we need to kill off the linear term
269 fdarule = [0 1]/fdamat(par.StepRatio,1,2);
270 case 4
271 % the even transformation did most of the work, but
272 % we need to kill off the quadratic term
273 fdarule = [0 1]/fdamat(par.StepRatio,2,2);
274 end
275 else
276 % a 4th order method. We've already ruled out the 1st
277 % order methods since these are central rules.
278 switch par.DerivativeOrder
279 case 1
280 % the odd transformation did most of the work, but
281 % we need to kill off the cubic term
282 fdarule = [1 0]/fdamat(par.StepRatio,1,2);
283 case 2
284 % the even transformation did most of the work, but
285 % we need to kill off the quartic term
286 fdarule = [1 0]/fdamat(par.StepRatio,2,2);
287 case 3
288 % the odd transformation did much of the work, but
289 % we need to kill off the linear & quintic terms
290 fdarule = [0 1 0]/fdamat(par.StepRatio,1,3);
291 case 4
292 % the even transformation did much of the work, but
293 % we need to kill off the quadratic and 6th order terms
294 fdarule = [0 1 0]/fdamat(par.StepRatio,2,3);
295 end
296 end
297 case {'forward' 'backward'}
298 % These two cases are identical, except at the very end,
299 % where a sign will be introduced.
300
301 % No odd/even trans, but we already dropped
302 % off the constant term
303 if par.MethodOrder==1
304 if par.DerivativeOrder==1
305 % an easy one
306 fdarule = 1;
307 else
308 % 2:4
309 v = zeros(1,par.DerivativeOrder);
310 v(par.DerivativeOrder) = 1;
311 fdarule = v/fdamat(par.StepRatio,0,par.DerivativeOrder);
312 end
313 else
314 % par.MethodOrder methods drop off the lower order terms,
315 % plus terms directly above DerivativeOrder
316 v = zeros(1,par.DerivativeOrder + par.MethodOrder - 1);
317 v(par.DerivativeOrder) = 1;
318 fdarule = v/fdamat(par.StepRatio,0,par.DerivativeOrder+par.MethodOrder-1);
319 end
320
321 % correct sign for the 'backward' rule
322 if par.Style(1) == 'b'
323 fdarule = -fdarule;
324 end
325
326end % switch on par.style (generating fdarule)
327nfda = length(fdarule);
328
329% will we need fun(x0)?
330if (rem(par.DerivativeOrder,2) == 0) || ~strncmpi(par.Style,'central',7)
331 if strcmpi(par.Vectorized,'yes')
332 f_x0 = fun(x0);
333 else
334 % not vectorized, so loop
335 f_x0 = zeros(size(x0));
336 for j = 1:numel(x0)
337 f_x0(j) = fun(x0(j));
338 end
339 end
340else
341 f_x0 = [];
342end
343
344% Loop over the elements of x0, reducing it to
345% a scalar problem. Sorry, vectorization is not
346% complete here, but this IS only a single loop.
347der = zeros(nx0);
348errest = der;
349finaldelta = der;
350for i = 1:n
351 x0i = x0(i);
352 h = par.NominalStep(i);
353
354 % a central, forward or backwards differencing rule?
355 % f_del is the set of all the function evaluations we
356 % will generate. For a central rule, it will have the
357 % even or odd transformation built in.
358 if par.Style(1) == 'c'
359 % A central rule, so we will need to evaluate
360 % symmetrically around x0i.
361 if strcmpi(par.Vectorized,'yes')
362 f_plusdel = fun(x0i+h*delta);
363 f_minusdel = fun(x0i-h*delta);
364 else
365 % not vectorized, so loop
366 f_minusdel = zeros(size(delta));
367 f_plusdel = zeros(size(delta));
368 for j = 1:numel(delta)
369 f_plusdel(j) = fun(x0i+h*delta(j));
370 f_minusdel(j) = fun(x0i-h*delta(j));
371 end
372 end
373
374 if ismember(par.DerivativeOrder,[1 3])
375 % odd transformation
376 f_del = (f_plusdel - f_minusdel)/2;
377 else
378 f_del = (f_plusdel + f_minusdel)/2 - f_x0(i);
379 end
380 elseif par.Style(1) == 'f'
381 % forward rule
382 % drop off the constant only
383 if strcmpi(par.Vectorized,'yes')
384 f_del = fun(x0i+h*delta) - f_x0(i);
385 else
386 % not vectorized, so loop
387 f_del = zeros(size(delta));
388 for j = 1:numel(delta)
389 f_del(j) = fun(x0i+h*delta(j)) - f_x0(i);
390 end
391 end
392 else
393 % backward rule
394 % drop off the constant only
395 if strcmpi(par.Vectorized,'yes')
396 f_del = fun(x0i-h*delta) - f_x0(i);
397 else
398 % not vectorized, so loop
399 f_del = zeros(size(delta));
400 for j = 1:numel(delta)
401 f_del(j) = fun(x0i-h*delta(j)) - f_x0(i);
402 end
403 end
404 end
405
406 % check the size of f_del to ensure it was properly vectorized.
407 f_del = f_del(:);
408 if length(f_del)~=ndel
409 error 'fun did not return the correct size result (fun must be vectorized)'
410 end
411
412 % Apply the finite difference rule at each delta, scaling
413 % as appropriate for delta and the requested DerivativeOrder.
414 % First, decide how many of these estimates we will end up with.
415 ne = ndel + 1 - nfda - par.RombergTerms;
416
417 % Form the initial derivative estimates from the chosen
418 % finite difference method.
419 der_init = vec2mat(f_del,ne,nfda)*fdarule.';
420
421 % scale to reflect the local delta
422 der_init = der_init(:)./(h*delta(1:ne)).^par.DerivativeOrder;
423
424 % Each approximation that results is an approximation
425 % of order par.DerivativeOrder to the desired derivative.
426 % Additional (higher order, even or odd) terms in the
427 % Taylor series also remain. Use a generalized (multi-term)
428 % Romberg extrapolation to improve these estimates.
429 switch par.Style
430 case 'central'
431 rombexpon = 2*(1:par.RombergTerms) + par.MethodOrder - 2;
432 otherwise
433 rombexpon = (1:par.RombergTerms) + par.MethodOrder - 1;
434 end
435 [der_romb,errors] = rombextrap(par.StepRatio,der_init,rombexpon);
436
437 % Choose which result to return
438
439 % first, trim off the
440 if isempty(par.FixedStep)
441 % trim off the estimates at each end of the scale
442 nest = length(der_romb);
443 switch par.DerivativeOrder
444 case {1 2}
445 trim = [1 2 nest-1 nest];
446 case 3
447 trim = [1:4 nest+(-3:0)];
448 case 4
449 trim = [1:6 nest+(-5:0)];
450 end
451
452 [der_romb,tags] = sort(der_romb);
453
454 der_romb(trim) = [];
455 tags(trim) = [];
456 errors = errors(tags);
457 trimdelta = delta(tags);
458
459 [errest(i),ind] = min(errors);
460
461 finaldelta(i) = h*trimdelta(ind);
462 der(i) = der_romb(ind);
463 else
464 [errest(i),ind] = min(errors);
465 finaldelta(i) = h*delta(ind);
466 der(i) = der_romb(ind);
467 end
468end
469
470end % mainline end
471
472% ============================================
473% subfunction - romberg extrapolation
474% ============================================
475function [der_romb,errest] = rombextrap(StepRatio,der_init,rombexpon)
476% do romberg extrapolation for each estimate
477%
478% StepRatio - Ratio decrease in step
479% der_init - initial derivative estimates
480% rombexpon - higher order terms to cancel using the romberg step
481%
482% der_romb - derivative estimates returned
483% errest - error estimates
484% amp - noise amplification factor due to the romberg step
485
486srinv = 1/StepRatio;
487
488% do nothing if no romberg terms
489nexpon = length(rombexpon);
490rmat = ones(nexpon+2,nexpon+1);
491switch nexpon
492 case 0
493 % rmat is simple: ones(2,1)
494 case 1
495 % only one romberg term
496 rmat(2,2) = srinv^rombexpon;
497 rmat(3,2) = srinv^(2*rombexpon);
498 case 2
499 % two romberg terms
500 rmat(2,2:3) = srinv.^rombexpon;
501 rmat(3,2:3) = srinv.^(2*rombexpon);
502 rmat(4,2:3) = srinv.^(3*rombexpon);
503 case 3
504 % three romberg terms
505 rmat(2,2:4) = srinv.^rombexpon;
506 rmat(3,2:4) = srinv.^(2*rombexpon);
507 rmat(4,2:4) = srinv.^(3*rombexpon);
508 rmat(5,2:4) = srinv.^(4*rombexpon);
509end
510
511% qr factorization used for the extrapolation as well
512% as the uncertainty estimates
513[qromb,rromb] = qr(rmat,0);
514
515% the noise amplification is further amplified by the Romberg step.
516% amp = cond(rromb);
517
518% this does the extrapolation to a zero step size.
519ne = length(der_init);
520rhs = vec2mat(der_init,nexpon+2,max(1,ne - (nexpon+2)));
521rombcoefs = rromb\(qromb.'*rhs);
522der_romb = rombcoefs(1,:).';
523
524% uncertainty estimate of derivative prediction
525s = sqrt(sum((rhs - rmat*rombcoefs).^2,1));
526rinv = rromb\eye(nexpon+1);
527cov1 = sum(rinv.^2,2); % 1 spare dof
528errest = s.'*12.7062047361747*sqrt(cov1(1));
529
530end % rombextrap
531
532
533% ============================================
534% subfunction - vec2mat
535% ============================================
536function mat = vec2mat(vec,n,m)
537% forms the matrix M, such that M(i,j) = vec(i+j-1)
538[i,j] = ndgrid(1:n,0:m-1);
539ind = i+j;
540mat = vec(ind);
541if n==1
542 mat = mat.';
543end
544
545end % vec2mat
546
547
548% ============================================
549% subfunction - fdamat
550% ============================================
551function mat = fdamat(sr,parity,nterms)
552% Compute matrix for fda derivation.
553% parity can be
554% 0 (one sided, all terms included but zeroth order)
555% 1 (only odd terms included)
556% 2 (only even terms included)
557% nterms - number of terms
558
559% sr is the ratio between successive steps
560srinv = 1./sr;
561
562switch parity
563 case 0
564 % single sided rule
565 [i,j] = ndgrid(1:nterms);
566 c = 1./factorial(1:nterms);
567 mat = c(j).*srinv.^((i-1).*j);
568 case 1
569 % odd order derivative
570 [i,j] = ndgrid(1:nterms);
571 c = 1./factorial(1:2:(2*nterms));
572 mat = c(j).*srinv.^((i-1).*(2*j-1));
573 case 2
574 % even order derivative
575 [i,j] = ndgrid(1:nterms);
576 c = 1./factorial(2:2:(2*nterms));
577 mat = c(j).*srinv.^((i-1).*(2*j));
578end
579
580end % fdamat
581
582
583
584% ============================================
585% subfunction - check_params
586% ============================================
587function par = check_params(par)
588% check the parameters for acceptability
589%
590% Defaults
591% par.DerivativeOrder = 1;
592% par.MethodOrder = 2;
593% par.Style = 'central';
594% par.RombergTerms = 2;
595% par.FixedStep = [];
596
597% DerivativeOrder == 1 by default
598if isempty(par.DerivativeOrder)
599 par.DerivativeOrder = 1;
600else
601 if (length(par.DerivativeOrder)>1) || ~ismember(par.DerivativeOrder,1:4)
602 error 'DerivativeOrder must be scalar, one of [1 2 3 4].'
603 end
604end
605
606% MethodOrder == 2 by default
607if isempty(par.MethodOrder)
608 par.MethodOrder = 2;
609else
610 if (length(par.MethodOrder)>1) || ~ismember(par.MethodOrder,[1 2 3 4])
611 error 'MethodOrder must be scalar, one of [1 2 3 4].'
612 elseif ismember(par.MethodOrder,[1 3]) && (par.Style(1)=='c')
613 error 'MethodOrder==1 or 3 is not possible with central difference methods'
614 end
615end
616
617% style is char
618valid = {'central', 'forward', 'backward'};
619if isempty(par.Style)
620 par.Style = 'central';
621elseif ~ischar(par.Style)
622 error 'Invalid Style: Must be character'
623end
624ind = find(strncmpi(par.Style,valid,length(par.Style)));
625if (length(ind)==1)
626 par.Style = valid{ind};
627else
628 error(['Invalid Style: ',par.Style])
629end
630
631% vectorized is char
632valid = {'yes', 'no'};
633if isempty(par.Vectorized)
634 par.Vectorized = 'yes';
635elseif ~ischar(par.Vectorized)
636 error 'Invalid Vectorized: Must be character'
637end
638ind = find(strncmpi(par.Vectorized,valid,length(par.Vectorized)));
639if (length(ind)==1)
640 par.Vectorized = valid{ind};
641else
642 error(['Invalid Vectorized: ',par.Vectorized])
643end
644
645% RombergTerms == 2 by default
646if isempty(par.RombergTerms)
647 par.RombergTerms = 2;
648else
649 if (length(par.RombergTerms)>1) || ~ismember(par.RombergTerms,0:3)
650 error 'RombergTerms must be scalar, one of [0 1 2 3].'
651 end
652end
653
654% FixedStep == [] by default
655if (length(par.FixedStep)>1) || (~isempty(par.FixedStep) && (par.FixedStep<=0))
656 error 'FixedStep must be empty or a scalar, >0.'
657end
658
659% MaxStep == 10 by default
660if isempty(par.MaxStep)
661 par.MaxStep = 10;
662elseif (length(par.MaxStep)>1) || (par.MaxStep<=0)
663 error 'MaxStep must be empty or a scalar, >0.'
664end
665
666end % check_params
667
668
669% ============================================
670% Included subfunction - parse_pv_pairs
671% ============================================
672function params=parse_pv_pairs(params,pv_pairs)
673% parse_pv_pairs: parses sets of property value pairs, allows defaults
674% usage: params=parse_pv_pairs(default_params,pv_pairs)
675%
676% arguments: (input)
677% default_params - structure, with one field for every potential
678% property/value pair. Each field will contain the default
679% value for that property. If no default is supplied for a
680% given property, then that field must be empty.
681%
682% pv_array - cell array of property/value pairs.
683% Case is ignored when comparing properties to the list
684% of field names. Also, any unambiguous shortening of a
685% field/property name is allowed.
686%
687% arguments: (output)
688% params - parameter struct that reflects any updated property/value
689% pairs in the pv_array.
690%
691% Example usage:
692% First, set default values for the parameters. Assume we
693% have four parameters that we wish to use optionally in
694% the function examplefun.
695%
696% - 'viscosity', which will have a default value of 1
697% - 'volume', which will default to 1
698% - 'pie' - which will have default value 3.141592653589793
699% - 'description' - a text field, left empty by default
700%
701% The first argument to examplefun is one which will always be
702% supplied.
703%
704% function examplefun(dummyarg1,varargin)
705% params.Viscosity = 1;
706% params.Volume = 1;
707% params.Pie = 3.141592653589793
708%
709% params.Description = '';
710% params=parse_pv_pairs(params,varargin);
711% params
712%
713% Use examplefun, overriding the defaults for 'pie', 'viscosity'
714% and 'description'. The 'volume' parameter is left at its default.
715%
716% examplefun(rand(10),'vis',10,'pie',3,'Description','Hello world')
717%
718% params =
719% Viscosity: 10
720% Volume: 1
721% Pie: 3
722% Description: 'Hello world'
723%
724% Note that capitalization was ignored, and the property 'viscosity'
725% was truncated as supplied. Also note that the order the pairs were
726% supplied was arbitrary.
727
728npv = length(pv_pairs);
729n = npv/2;
730
731if n~=floor(n)
732 error 'Property/value pairs must come in PAIRS.'
733end
734if n<=0
735 % just return the defaults
736 return
737end
738
739if ~isstruct(params)
740 error 'No structure for defaults was supplied'
741end
742
743% there was at least one pv pair. process any supplied
744propnames = fieldnames(params);
745lpropnames = lower(propnames);
746for i=1:n
747 p_i = lower(pv_pairs{2*i-1});
748 v_i = pv_pairs{2*i};
749
750 ind = strmatch(p_i,lpropnames,'exact');
751 if isempty(ind)
752 ind = find(strncmp(p_i,lpropnames,length(p_i)));
753 if isempty(ind)
754 error(['No matching property found for: ',pv_pairs{2*i-1}])
755 elseif length(ind)>1
756 error(['Ambiguous property name: ',pv_pairs{2*i-1}])
757 end
758 end
759 p_i = propnames{ind};
760
761 % override the corresponding default in params
762 params = setfield(params,p_i,v_i); %#ok
763
764end
765
766end % parse_pv_pairs
767
768
769
770
771
772