Generated reference › Nonlinear Least Squares — Control Systems/Optimization
kind: generated#block#control-systems-optimization

Nonlinear Least Squares — Control Systems/Optimization

min ∑F²

Control_Systems/Optimization/Nonlinear_Least_Squares · 1 input / 3 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Description#

The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.

Nonlinear Least Squares

Control Systems / Optimization

Finds the x that minimizes a sum of squared polynomial residuals whose coefficients arrive on a port – MATLAB's lsqnonlin at its default trust-region-reflective algorithm, solved again on every sample:

Fr(x) = Σt cr,t · x1e(t,1) · … · xne(t,n),   r = 1 … m,   minimizing F′F

The exponents e are configuration and the coefficients c are the signal, exactly as in Nelder-Mead Search and Unconstrained Minimization. What is new is that m residuals share one exponent pattern, and m need not equal n – which is what makes this a least-squares problem rather than a root find. Its square sibling is Nonlinear System Solve, whose column is the same shape at m = n.

The Jacobian is analytic: a polynomial's derivative is another polynomial, so the block reproduces lsqnonlin configured with SpecifyObjectiveGradient, not its finite-difference default.

The factory setting is Rosenbrock's function as lsqnonlin's own documented residual pair, F = [10(x₂−x₁²); 1−x₁] from [−1.2; 1]: the four terms [0 1; 2 0; 0 0; 1 0] against coefficients [10; −10; 0; 0; 0; 0; 1; −1]. It reaches the minimum in 23 iterations and 24 evaluations, which is lsqnonlin's count exactly – and the same surface the two neighbouring blocks are set to, so all three can be dropped on one diagram and compared.

Ports

  • c – the term coefficients, a single column [m·T,1]: residual r occupies rows (r−1)T+1 … rT, in the row order of Term Exponents. A matrix port is not offered, for the reason its square sibling gives: the renderers reshape row-major in Python and column-major in MATLAB, and one column cannot be read two ways.
  • x – the minimizer, [n,1] (n = the columns of Term Exponents).
  • resnorm – F′F at that x, a scalar [1,1]. MATLAB's second output, and note it is the sum of squares, not half of it.
  • exitflag – a scalar [1,1], lsqnonlin's own: 1 the gradient test was met; 3 the change in F′F fell below Function Tolerance; 2 the step fell below Step Tolerance; 0 a limit below stopped the search.

Parameters

  • Options – empty (default), or the path of a Solver Options block (Home/Solver Options), MATLAB’s options argument: for the run, every option it sets replaces this block’s parameter of the same name; one it leaves at default, or one this block does not have, changes nothing.
  • Term Exponents – a [T,n] matrix of whole numbers from 0 to 3: row t, column i is the power of xi in term t. T is 1 to 5 terms, n is 1 to 4 variables, and no single term may total more than degree 3. Those caps are the export's – see Code export.
  • Residual Count – m, how many residuals share that pattern: 1 to 6, and never fewer than the number of variables. That floor is lsqnonlin's own, not this block's: with fewer residuals than unknowns the algorithm stops with an error, and here it is refused at config load with the reason.
  • Start Point – x0, a vector of n entries. The search is LOCAL: it descends into the valley it starts in.
  • Optimality Tolerance – OptimalityTolerance, positive; default 1e-6. The first test on every pass, met when ∥J′F∥∞ falls below it – which is exactly the number lsqnonlin reports as output.firstorderopt. Flag 1.
  • Function Tolerance – FunctionTolerance, positive; default 1e-6. Met when the step is well inside the trust region, the step was a good one, and F′F changed by less than tol·(1+|F′F|). Flag 3.
  • Step Tolerance – StepTolerance, positive; default 1e-6. Checked only after the two above, and only from the second iteration on. Flag 2.
  • Maximum Iterations – 1 to 2000, default 400.
  • Maximum Function Evaluations – same range, default 400. Whichever limit binds first gives exit flag 0.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text, printed from one description of the iteration, so every target does the same arithmetic in the same order as the simulation.

The exponent pattern is unrolled: a power becomes repeated multiplication, because no target can take a loop bound out of a real array. One evaluation computes all m residuals and all m·n Jacobian entries in the same pass, and the body holds two of them, which is why m, n, T and the degree are capped where they are. Everything else – the Householder QR that decides whether the Jacobian needs regularizing, the inner conjugate gradient, the subspace trust-region solve and its Brent root – is emitted as real loops with fixed trip counts and a flag that stops the arithmetic once the answer is found.

⚠ The three HDL targets run the search in simulation-only real arithmetic, quantizing only at the port boundaries: a trust-region step divides and compares across many orders of magnitude, which a Q16.16 datapath does not carry.

Simulink bridge

None (Support::None). The Optimization Toolbox ships no Simulink library at all and lsqnonlin is a MATLAB function, so there is no block to map onto; the bridge reports this block rather than dropping it silently, and it has no parity testbench. Code export verification still covers it across all ten languages.

Notes

  • Stateless: the search restarts from Start Point on every sample, so the answer depends only on the coefficients present at that step.
  • ⚠ A RANK-DEFICIENT JACOBIAN IS A DEFINED CASE, NOT A FAILURE. When J′J is singular the algorithm does not give up and does not report a bad step: it regularizes the preconditioner – J′J + λ²I for the first λ in 1, 4, 16, … that makes the factorization safe – and takes a Levenberg-Marquardt-like direction instead of a Gauss-Newton one. That is lsqnonlin's own behaviour, and it is common with freely varying coefficients rather than exotic.
  • ⚠ resnorm is F′F, not ½F′F. MATLAB's own convention, and the source says so in as many words where it forms the predicted-reduction ratio.
  • ⚠ LOCAL, and a small gradient is not a certificate. A different Start Point can reach a different minimum, and a residual system with no finite minimizer walks x outwards until a limit stops it – exit flag 0 with a large x is that case, not a defect.
  • eps has no spelling in nine of the ten targets, so MATLAB's eps and sqrt(eps) are the exact binary constants 2−52 and 2−26 here.

Code facts#

FactValue
registered typeControl_Systems/Optimization/Nonlinear_Least_Squares
familyControl_Systems/Optimization
solver environment classICoreBlock_0_Control_Systems_1_Optimization_2_Nonlinear_Least_Squares
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Optimization/Nonlinear_Least_Squares/ICoreBlock_0_Control_Systems_1_Optimization_2_Nonlinear_Least_Squares.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Optimization/Nonlinear_Least_Squares/ICoreBlock_0_Control_Systems_1_Optimization_2_Nonlinear_Least_Squares.h
default size on canvas170 × 90 px
ports at insert1 in, 3 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublec
2outICoreDoublex
3outICoreDoubleresnorm
4outICoreDoubleexitflag

Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.

Configuration variables#

Config variableDefaultSimulink parameter
Term Exponents[0 1; 2 0; 0 0; 1 0]—
Residual Count2—
Start Point[-1.2; 1]—
Optimality Tolerance1e-6—
Function Tolerance1e-6—
Step Tolerance1e-6—
Maximum Iterations400—
Maximum Function Evaluations400—
Options——

Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.

supportSupport::None
Simulink path—
port-count rulePortsParam::None
SampleTime parameteryes

Caveat (shown to the user): the Optimization Toolbox ships no Simulink library at all, so there is no block to map onto and no library path a diagram could name; lsqnonlin is a MATLAB function. The block is reported rather than dropped when a model crosses

Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:

  • B0 every stimulus in the sample errored — cross-checks skipped

The verdict above is tools/docs/check_block_descriptions.py (P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.

File banner (developer view)#

The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).

Nonlinear Least Squares -- lsqnonlin over polynomial residuals whose coefficients are a wire F_r(x) = sum over terms of c(r,t) * x1^e(t,1) * ... * xn^e(t,n) r = 1 .. m [x, resnorm, exitflag] = lsqnonlin(F, x0) resnorm = F'F

THE SEAM IS THE FAMILY'S, ONE DIMENSION WIDER. Nelder-Mead Search made the exponent pattern configuration and the coefficient column the signal; Nonlinear System Solve stacked n of them into one column for a square system. This block stacks m, and m need not equal n -- which is what makes it a least-squares problem rather than a root find.

⚠⚠ THIS ROW WAS ON THE BOARD AS A DESIGN, AND IT IS A TRANSCRIPTION. See the Unconstrained Minimization block beside it for the correction in full: MATLAB's optimization ENGINES are in toolbox/shared/optimlib, not toolbox/optim/optim, which holds only the drivers. snls.m, trdog.m, trust.m, pcgr.m, aprecon.m and definev.m are all readable there, and none of the hot path is .p. The board's note said otherwise and the three rows written against it are annotated rather than rewritten.

⚠ THE SEARCH ITSELF IS NO LONGER IN THIS FILE. lsqnonlin and lsqcurvefit are ONE solver -- lsqcurvefit.m forms F(x, xdata) - ydata in a nested function and hands it to the same lsqncommon -- so the transcription moved to ../ICoreTrustRegionSupport.h when the Nonlinear Curve Fit block beside it was built on it. What remains here is the residual family, its Jacobian, and the block. Why the unbounded case is a quarter of snls.m, why the inner conjugate gradient is exact, why a rank-deficient Jacobian still reports a positive definite system -- the flag that decides whether this search can stop on optimality at all -- and why eigenvector signs cannot matter are all on that header.

⚠ THE MOVE CHANGED THE EMITTED TEXT BY NOT ONE BYTE, AND THAT IS HOW IT WAS CHECKED: the declaration order, the statement order and every literal are the same, so the ten exported bodies this block produces are character-identical to the ones it produced before it. ⚠ MEASURED AGAINST R2026a, over 600 random residual systems in the block's own form and at every shape the config accepts -- 300 at 1 to 3 variables with m from n to 5, 150 at n = 4 and m = 4 (where floor(n/2) makes the inner CG take TWO steps rather than one), and 150 at the WIDEST shape, n = 4 with 5 or 6 residuals. 2 to 6 terms, total degree <= 3. The reference in this file, compiled standalone, against lsqnonlin at Algorithm='trust-region-reflective' with the same analytic Jacobian supplied:

exit flags identical over the whole corpus 587 / 600

and restricted to the 534 problems MATLAB converges in under fifty iterations, which is what a user of this block is looking at:

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Nonlinear Least Squares. That is a fact about the single-block rig, not a verdict on the block: an offline batch fit, a block whose output only appears at onSolverFinish, or one that needs a driven environment cannot be exercised alone.

Category unsampled · sample time 0.1 · 60 steps · commit e901ec0f4 · produced by docsSample --out <folder> --blocks Control_Systems/Optimization/Nonlinear_Least_Squares --steps 60

Sample data: docs/generated/samples/Control_Systems__Optimization__Nonlinear_Least_Squares.json