Approximate a periodic curve.
(
data: Array,
us: Optional[Array] = None,
knots: int | Array = 50,
order: int = 3,
penalty: int = 4,
lam: float = 0,
)
| 1519 | |
| 1520 | @multidispatch |
| 1521 | def periodicApproximate( |
| 1522 | data: Array, |
| 1523 | us: Optional[Array] = None, |
| 1524 | knots: int | Array = 50, |
| 1525 | order: int = 3, |
| 1526 | penalty: int = 4, |
| 1527 | lam: float = 0, |
| 1528 | ) -> Curve: |
| 1529 | """ |
| 1530 | Approximate a periodic curve. |
| 1531 | """ |
| 1532 | |
| 1533 | npts = data.shape[0] |
| 1534 | |
| 1535 | # parameterize the points if needed |
| 1536 | if us is None: |
| 1537 | us = linspace(0, 1, npts, endpoint=False) |
| 1538 | |
| 1539 | # construct the knot vector |
| 1540 | if isinstance(knots, int): |
| 1541 | knots_ = linspace(0, 1, knots) |
| 1542 | else: |
| 1543 | knots_ = np.array(knots) |
| 1544 | |
| 1545 | # construct the design matrix |
| 1546 | C = periodicDesignMatrix(us, order, knots_).csc() |
| 1547 | CtC = C.T @ C |
| 1548 | |
| 1549 | # add the penalty if requested |
| 1550 | if lam: |
| 1551 | up = linspace(0, 1, order * npts, endpoint=False) |
| 1552 | |
| 1553 | assert penalty <= order + 2 |
| 1554 | |
| 1555 | # discrete + exact derivatives |
| 1556 | if penalty > order: |
| 1557 | Pexact = periodicDerMatrix(up, order, order - 1, knots_)[-1].csc() |
| 1558 | Pdiscrete = periodicDiscretePenalty(up, penalty - order).csc() |
| 1559 | |
| 1560 | P = Pdiscrete @ Pexact |
| 1561 | |
| 1562 | # only exact derivatives |
| 1563 | else: |
| 1564 | P = periodicDerMatrix(up, order, penalty, knots_)[-1].csc() |
| 1565 | |
| 1566 | CtC += lam * P.T @ P |
| 1567 | |
| 1568 | # factorize |
| 1569 | D, L, P = ldl(CtC, True) |
| 1570 | |
| 1571 | # invert |
| 1572 | pts = ldl_solve(C.T @ data, D, L, P).toarray() |
| 1573 | |
| 1574 | # convert to an edge |
| 1575 | rv = Curve(pts, knots_, order, periodic=True) |
| 1576 | |
| 1577 | return rv |
| 1578 |