or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

arma-methods.mdcorrelation-signal.mdeigenvalue-methods.mdindex.mdlinear-prediction.mdmath-tools.mdnonparametric-methods.mdparametric-ar.mdwindow-functions.md

math-tools.mddocs/

0

# Mathematical Tools

1

2

Linear algebra utilities, model selection criteria, transfer function analysis, and mathematical tools supporting spectral analysis. These functions provide the mathematical foundation for advanced signal processing and system identification applications.

3

4

## Capabilities

5

6

### Linear Algebra Utilities

7

8

Core linear algebra functions for matrix operations and decompositions used in spectral analysis.

9

10

```python { .api }

11

def CHOLESKY(A, B, method='scipy'):

12

"""

13

Solve linear system AX=B using Cholesky decomposition.

14

15

Parameters:

16

- A: array-like, Hermitian positive definite coefficient matrix

17

- B: array-like, right-hand side matrix or vector

18

- method: str, computation method ('scipy', 'numpy', 'numpy_solver')

19

20

Returns:

21

array: Solution matrix X such that AX = B

22

"""

23

24

def pascal(n):

25

"""

26

Generate Pascal matrix of size n x n.

27

28

Parameters:

29

- n: int, matrix size

30

31

Returns:

32

array: Pascal matrix (symmetric positive definite)

33

"""

34

35

def corrmtx(x_input, m, method='autocorrelation'):

36

"""

37

Generate correlation matrix for linear prediction.

38

39

Parameters:

40

- x_input: array-like, input data vector

41

- m: int, matrix order (number of coefficients)

42

- method: str, matrix construction method ('autocorrelation', 'covariance', 'prewindowed', 'postwindowed')

43

44

Returns:

45

array: Correlation matrix for linear prediction analysis

46

"""

47

48

def csvd(A):

49

"""

50

Complex singular value decomposition.

51

52

Parameters:

53

- A: array-like, input matrix (real or complex)

54

55

Returns:

56

tuple: (U array, singular values array, V^H array)

57

"""

58

```

59

60

### Model Selection Criteria

61

62

Information-theoretic criteria for automatic model order selection in parametric spectral estimation.

63

64

```python { .api }

65

def AIC(N, rho, k):

66

"""

67

Akaike Information Criterion for model order selection.

68

69

Parameters:

70

- N: int, data length

71

- rho: float, prediction error (noise variance)

72

- k: int, model order (number of parameters)

73

74

Returns:

75

float: AIC value (lower is better)

76

"""

77

78

def AICc(N, rho, k, norm=True):

79

"""

80

Corrected AIC for small sample sizes.

81

82

Parameters:

83

- N: int, data length

84

- rho: float, prediction error

85

- k: int, model order

86

- norm: bool, apply normalization factor

87

88

Returns:

89

float: Corrected AIC value

90

"""

91

92

def MDL(N, rho, k):

93

"""

94

Minimum Description Length criterion.

95

96

Parameters:

97

- N: int, data length

98

- rho: float, prediction error

99

- k: int, model order

100

101

Returns:

102

float: MDL value (lower is better)

103

"""

104

105

def FPE(N, rho, k=None):

106

"""

107

Final Prediction Error criterion.

108

109

Parameters:

110

- N: int, data length

111

- rho: float, prediction error

112

- k: int, model order (None for simple FPE)

113

114

Returns:

115

float: FPE value

116

"""

117

118

def KIC(N, rho, k):

119

"""

120

Kullback Information Criterion.

121

122

Parameters:

123

- N: int, data length

124

- rho: float, prediction error

125

- k: int, model order

126

127

Returns:

128

float: KIC value

129

"""

130

131

def AKICc(N, rho, k):

132

"""

133

Asymmetric KIC corrected for small samples.

134

135

Parameters:

136

- N: int, data length

137

- rho: float, prediction error

138

- k: int, model order

139

140

Returns:

141

float: AKICc value

142

"""

143

144

def CAT(N, rho, k):

145

"""

146

Criterion Autoregressive Transfer function.

147

148

Parameters:

149

- N: int, data length

150

- rho: float, prediction error

151

- k: int, model order

152

153

Returns:

154

float: CAT value

155

"""

156

```

157

158

### Automatic Model Order Selection

159

160

Class-based interface for automatic model order selection using various criteria.

161

162

```python { .api }

163

class Criteria(name, N):

164

"""

165

Automatic order selection for parametric methods.

166

167

Parameters:

168

- name: str, criterion name ('AIC', 'MDL', 'FPE', 'CAT', etc.)

169

- N: int, data length

170

171

Methods:

172

- __call__(rho, k): compute criterion value

173

- find_order(rho_values, orders): find optimal order

174

"""

175

```

176

177

### Transfer Function Analysis

178

179

Functions for converting between different transfer function representations and performing system analysis.

180

181

```python { .api }

182

def tf2zp(b, a):

183

"""

184

Transfer function to zeros and poles conversion.

185

186

Parameters:

187

- b: array-like, numerator polynomial coefficients

188

- a: array-like, denominator polynomial coefficients

189

190

Returns:

191

tuple: (zeros array, poles array)

192

"""

193

194

def zp2tf(z, p, k):

195

"""

196

Zeros and poles to transfer function conversion.

197

198

Parameters:

199

- z: array-like, zeros of the transfer function

200

- p: array-like, poles of the transfer function

201

- k: float, system gain

202

203

Returns:

204

tuple: (numerator coefficients array, denominator coefficients array)

205

"""

206

207

def tf2zpk(b, a):

208

"""

209

Transfer function to zeros, poles, and gain conversion.

210

211

Parameters:

212

- b: array-like, numerator polynomial coefficients

213

- a: array-like, denominator polynomial coefficients

214

215

Returns:

216

tuple: (zeros array, poles array, gain float)

217

"""

218

219

def zpk2tf(z, p, k):

220

"""

221

Zeros, poles, and gain to transfer function conversion.

222

223

Parameters:

224

- z: array-like, zeros of the transfer function

225

- p: array-like, poles of the transfer function

226

- k: float, system gain

227

228

Returns:

229

tuple: (numerator coefficients array, denominator coefficients array)

230

"""

231

232

def eqtflength(b, a):

233

"""

234

Equalize lengths of transfer function numerator and denominator.

235

236

Parameters:

237

- b: array-like, numerator coefficients

238

- a: array-like, denominator coefficients

239

240

Returns:

241

tuple: (equalized numerator array, equalized denominator array)

242

"""

243

```

244

245

### Advanced Transfer Function Conversions

246

247

Functions for state-space and lattice filter representations.

248

249

```python { .api }

250

def zpk2ss(z, p, k):

251

"""

252

Convert zeros, poles, gain to state-space representation.

253

254

Parameters:

255

- z: array-like, zeros of the transfer function

256

- p: array-like, poles of the transfer function

257

- k: float, system gain

258

259

Returns:

260

tuple: (A matrix, B vector, C vector, D scalar) state-space matrices

261

"""

262

263

def ss2zpk(a, b, c, d, input=0):

264

"""

265

Convert state-space to zeros, poles, gain representation.

266

267

Parameters:

268

- a: array-like, state matrix

269

- b: array-like, input matrix

270

- c: array-like, output matrix

271

- d: array-like, feedthrough matrix

272

- input: int, input channel for MIMO systems

273

274

Returns:

275

tuple: (zeros array, poles array, gain float)

276

"""

277

278

def tf2latc(num=[1.], den=[1.]):

279

"""

280

Convert transfer function to lattice filter coefficients.

281

282

Parameters:

283

- num: array-like, numerator coefficients (default [1.])

284

- den: array-like, denominator coefficients (default [1.])

285

286

Returns:

287

array: Lattice reflection coefficients

288

"""

289

290

def allpole2latc(num, den):

291

"""

292

Convert all-pole transfer function to lattice form.

293

294

Parameters:

295

- num: array-like, numerator coefficients

296

- den: array-like, denominator coefficients

297

298

Returns:

299

array: Lattice coefficients for all-pole system

300

"""

301

```

302

303

### Toeplitz System Solver

304

305

Specialized solver for Hermitian Toeplitz systems commonly encountered in signal processing.

306

307

```python { .api }

308

def HERMTOEP(T0, T, Z):

309

"""

310

Solve Hermitian Toeplitz system efficiently.

311

312

Parameters:

313

- T0: complex, Toeplitz matrix diagonal element

314

- T: array-like, first row/column of Toeplitz matrix (excluding T0)

315

- Z: array-like, right-hand side vector

316

317

Returns:

318

array: Solution vector for Toeplitz system

319

"""

320

```

321

322

## Usage Examples

323

324

### Model Order Selection

325

326

```python

327

import spectrum

328

import numpy as np

329

import matplotlib.pyplot as plt

330

331

# Generate AR signal with known order

332

np.random.seed(42)

333

N = 200

334

true_order = 4

335

336

# AR coefficients for a 4th-order system

337

ar_true = np.array([1.0, -2.7607, 3.8106, -2.6535, 0.9238])

338

339

# Generate AR signal

340

noise = np.random.randn(N)

341

signal = np.zeros(N)

342

signal[:true_order] = noise[:true_order]

343

344

for n in range(true_order, N):

345

signal[n] = -np.sum(ar_true[1:] * signal[n-true_order:n][::-1]) + noise[n]

346

347

# Test different model orders

348

max_order = 15

349

orders = range(1, max_order + 1)

350

criteria_values = {

351

'AIC': [],

352

'MDL': [],

353

'FPE': [],

354

'CAT': [],

355

'AICc': []

356

}

357

358

# Compute AR parameters and criteria for each order

359

for order in orders:

360

# Estimate AR parameters using Yule-Walker

361

ar_coeffs, rho, _ = spectrum.aryule(signal, order)

362

363

# Compute various criteria

364

criteria_values['AIC'].append(spectrum.AIC(N, rho, order))

365

criteria_values['MDL'].append(spectrum.MDL(N, rho, order))

366

criteria_values['FPE'].append(spectrum.FPE(N, rho, order))

367

criteria_values['CAT'].append(spectrum.CAT(N, rho, order))

368

criteria_values['AICc'].append(spectrum.AICc(N, rho, order))

369

370

# Find optimal orders

371

optimal_orders = {}

372

for name, values in criteria_values.items():

373

optimal_orders[name] = orders[np.argmin(values)]

374

375

# Plot results

376

plt.figure(figsize=(15, 10))

377

378

plt.subplot(2, 3, 1)

379

plt.plot(signal)

380

plt.title(f'Generated AR({true_order}) Signal')

381

plt.xlabel('Sample')

382

plt.ylabel('Amplitude')

383

plt.grid(True)

384

385

# Plot criteria

386

for i, (name, values) in enumerate(criteria_values.items()):

387

plt.subplot(2, 3, 2 + i)

388

plt.plot(orders, values, 'o-', linewidth=2, markersize=6)

389

plt.axvline(true_order, color='r', linestyle='--', alpha=0.7, label=f'True order = {true_order}')

390

plt.axvline(optimal_orders[name], color='g', linestyle=':', alpha=0.7,

391

label=f'Optimal = {optimal_orders[name]}')

392

plt.title(f'{name} Criterion')

393

plt.xlabel('Model Order')

394

plt.ylabel(f'{name} Value')

395

plt.legend()

396

plt.grid(True)

397

398

plt.tight_layout()

399

plt.show()

400

401

# Print results summary

402

print("Model Order Selection Results:")

403

print("-" * 40)

404

print(f"True AR order: {true_order}")

405

print("\nCriterion Optimal Order")

406

print("-" * 25)

407

for name, optimal in optimal_orders.items():

408

status = "✓" if optimal == true_order else "✗"

409

print(f"{name:8s} {optimal:2d} {status}")

410

411

# Demonstrate Criteria class usage

412

print("\nUsing Criteria class:")

413

print("-" * 25)

414

aic_criterion = spectrum.Criteria('AIC', N)

415

for order in [3, 4, 5]:

416

ar_coeffs, rho, _ = spectrum.aryule(signal, order)

417

aic_val = aic_criterion(rho, order) # This should work if implemented

418

print(f"Order {order}: AIC = {aic_val:.3f}")

419

```

420

421

### Linear Algebra and Matrix Operations

422

423

```python

424

import spectrum

425

import numpy as np

426

import matplotlib.pyplot as plt

427

428

# Demonstrate Cholesky solver for linear systems

429

print("Cholesky Decomposition Example:")

430

print("-" * 35)

431

432

# Create a positive definite matrix (correlation matrix)

433

N = 100

434

n = np.arange(N)

435

signal = np.sin(2*np.pi*0.1*n) + 0.1*np.random.randn(N)

436

437

# Create autocorrelation matrix using different methods

438

methods = ['autocorrelation', 'covariance']

439

order = 10

440

441

plt.figure(figsize=(15, 8))

442

443

for i, method in enumerate(methods):

444

# Generate correlation matrix

445

R = spectrum.corrmtx(signal, order-1, method=method)

446

447

plt.subplot(2, 4, 1 + i)

448

plt.imshow(np.real(R), cmap='coolwarm')

449

plt.colorbar()

450

plt.title(f'Correlation Matrix ({method})')

451

452

plt.subplot(2, 4, 3 + i)

453

plt.imshow(np.imag(R), cmap='coolwarm')

454

plt.colorbar()

455

plt.title(f'Imaginary Part ({method})')

456

457

# Test Cholesky solver

458

b = np.random.randn(R.shape[0]) # Random right-hand side

459

460

try:

461

# Solve using Cholesky decomposition

462

x_chol = spectrum.CHOLESKY(R, b, method='scipy')

463

464

# Solve using standard method for comparison

465

x_std = np.linalg.solve(R, b)

466

467

error = np.linalg.norm(x_chol - x_std)

468

print(f"{method} method:")

469

print(f" Matrix size: {R.shape}")

470

print(f" Condition number: {np.linalg.cond(R):.2e}")

471

print(f" Cholesky error: {error:.2e}")

472

print(f" Matrix is positive definite: {np.all(np.linalg.eigvals(R) > 0)}")

473

474

except Exception as e:

475

print(f"Cholesky failed for {method}: {e}")

476

477

# Pascal matrix example

478

plt.subplot(2, 4, 5)

479

pascal_mat = spectrum.pascal(8)

480

plt.imshow(pascal_mat, cmap='Blues')

481

plt.colorbar()

482

plt.title('Pascal Matrix')

483

484

# Complex SVD demonstration

485

plt.subplot(2, 4, 6)

486

# Create complex test matrix

487

A_complex = np.random.randn(6, 4) + 1j * np.random.randn(6, 4)

488

U, s, Vh = spectrum.csvd(A_complex)

489

490

plt.semilogy(s, 'o-', linewidth=2, markersize=8)

491

plt.title('Singular Values (Complex SVD)')

492

plt.xlabel('Index')

493

plt.ylabel('Singular Value')

494

plt.grid(True)

495

496

plt.tight_layout()

497

plt.show()

498

499

# Verify SVD reconstruction

500

A_reconstructed = U @ np.diag(s) @ Vh

501

reconstruction_error = np.linalg.norm(A_complex - A_reconstructed)

502

print(f"\nComplex SVD verification:")

503

print(f"Original matrix shape: {A_complex.shape}")

504

print(f"Reconstruction error: {reconstruction_error:.2e}")

505

```

506

507

### Transfer Function Analysis

508

509

```python

510

import spectrum

511

import numpy as np

512

import matplotlib.pyplot as plt

513

514

# Define a test transfer function (2nd order low-pass filter)

515

# H(s) = 1 / (s^2 + 2*ζ*ωn*s + ωn^2)

516

wn = 2*np.pi*10 # Natural frequency = 10 Hz

517

zeta = 0.7 # Damping ratio

518

519

# Continuous-time coefficients

520

num_s = [wn**2]

521

den_s = [1, 2*zeta*wn, wn**2]

522

523

# Convert to discrete-time using bilinear transform (approximation)

524

fs = 100 # Sampling frequency

525

T = 1/fs

526

527

# Bilinear transform: s = 2/T * (z-1)/(z+1)

528

# This is a simplified example - normally use scipy.signal.bilinear

529

num_z = num_s

530

den_z = den_s # Simplified for demonstration

531

532

# Convert to zeros, poles, gain representation

533

zeros, poles, gain = spectrum.tf2zpk(num_z, den_z)

534

535

print("Transfer Function Analysis:")

536

print("-" * 30)

537

print(f"Numerator coefficients: {num_z}")

538

print(f"Denominator coefficients: {den_z}")

539

print(f"Zeros: {zeros}")

540

print(f"Poles: {poles}")

541

print(f"Gain: {gain}")

542

543

# Convert back to transfer function

544

num_recovered, den_recovered = spectrum.zpk2tf(zeros, poles, gain)

545

print(f"Recovered numerator: {num_recovered}")

546

print(f"Recovered denominator: {den_recovered}")

547

548

# Verify conversion accuracy

549

num_error = np.max(np.abs(np.array(num_z) - num_recovered[:len(num_z)]))

550

den_error = np.max(np.abs(np.array(den_z) - den_recovered[:len(den_z)]))

551

print(f"Numerator error: {num_error:.2e}")

552

print(f"Denominator error: {den_error:.2e}")

553

554

# Pole-zero plot and frequency response

555

plt.figure(figsize=(15, 8))

556

557

# Pole-zero plot

558

plt.subplot(2, 3, 1)

559

plt.plot(np.real(zeros), np.imag(zeros), 'bo', markersize=10, label='Zeros')

560

plt.plot(np.real(poles), np.imag(poles), 'rx', markersize=10, label='Poles')

561

562

# Unit circle for discrete-time systems

563

theta = np.linspace(0, 2*np.pi, 100)

564

plt.plot(np.cos(theta), np.sin(theta), 'k--', alpha=0.5, label='Unit Circle')

565

566

plt.axis('equal')

567

plt.xlabel('Real Part')

568

plt.ylabel('Imaginary Part')

569

plt.title('Pole-Zero Plot')

570

plt.legend()

571

plt.grid(True)

572

573

# Frequency response

574

w = np.linspace(0, np.pi, 512) # Normalized frequency

575

H = np.polyval(num_recovered, np.exp(1j*w)) / np.polyval(den_recovered, np.exp(1j*w))

576

577

plt.subplot(2, 3, 2)

578

plt.plot(w/(2*np.pi)*fs, 20*np.log10(np.abs(H)))

579

plt.xlabel('Frequency (Hz)')

580

plt.ylabel('Magnitude (dB)')

581

plt.title('Frequency Response - Magnitude')

582

plt.grid(True)

583

584

plt.subplot(2, 3, 3)

585

plt.plot(w/(2*np.pi)*fs, np.angle(H)*180/np.pi)

586

plt.xlabel('Frequency (Hz)')

587

plt.ylabel('Phase (degrees)')

588

plt.title('Frequency Response - Phase')

589

plt.grid(True)

590

591

# Test lattice conversion for all-pole system (AR filter)

592

ar_coeffs = [1, -1.5, 0.7] # AR polynomial

593

lattice_coeffs = spectrum.tf2latc(num=[1], den=ar_coeffs)

594

595

plt.subplot(2, 3, 4)

596

plt.stem(range(len(lattice_coeffs)), lattice_coeffs, basefmt=' ')

597

plt.title('Lattice Coefficients')

598

plt.xlabel('Stage')

599

plt.ylabel('Reflection Coefficient')

600

plt.grid(True)

601

602

# System stability analysis

603

plt.subplot(2, 3, 5)

604

# Plot poles in z-plane for stability analysis

605

pole_magnitudes = np.abs(poles)

606

stable = np.all(pole_magnitudes < 1)

607

608

colors = ['green' if mag < 1 else 'red' for mag in pole_magnitudes]

609

plt.scatter(np.real(poles), np.imag(poles), c=colors, s=100, alpha=0.7)

610

plt.plot(np.cos(theta), np.sin(theta), 'k--', alpha=0.5)

611

plt.axis('equal')

612

plt.xlim(-1.5, 1.5)

613

plt.ylim(-1.5, 1.5)

614

plt.xlabel('Real Part')

615

plt.ylabel('Imaginary Part')

616

plt.title(f'System Stability ({"Stable" if stable else "Unstable"})')

617

plt.grid(True)

618

619

# Group delay

620

plt.subplot(2, 3, 6)

621

# Approximate group delay calculation

622

w_gd = w[1:-1]

623

phase = np.angle(H)

624

group_delay = -np.diff(phase) / np.diff(w)

625

group_delay = np.append(group_delay, group_delay[-1]) # Extend for plotting

626

627

plt.plot(w_gd/(2*np.pi)*fs, group_delay[:-1])

628

plt.xlabel('Frequency (Hz)')

629

plt.ylabel('Group Delay (samples)')

630

plt.title('Group Delay')

631

plt.grid(True)

632

633

plt.tight_layout()

634

plt.show()

635

636

# Print stability analysis

637

print(f"\nStability Analysis:")

638

print(f"All poles inside unit circle: {stable}")

639

for i, (pole, mag) in enumerate(zip(poles, pole_magnitudes)):

640

status = "Stable" if mag < 1 else "Unstable"

641

print(f"Pole {i+1}: {pole:.3f}, |pole| = {mag:.3f} ({status})")

642

```

643

644

### Advanced Mathematical Tools

645

646

```python

647

import spectrum

648

import numpy as np

649

import matplotlib.pyplot as plt

650

651

# Demonstrate Toeplitz solver

652

print("Toeplitz System Solver:")

653

print("-" * 25)

654

655

# Create Hermitian Toeplitz matrix

656

n = 8

657

T0 = 2.0 # Diagonal element

658

T = np.array([1.5, 0.8, 0.3, 0.1, 0.05, 0.02, 0.01]) # First row/column

659

660

# Construct full Toeplitz matrix for verification

661

from scipy.linalg import toeplitz

662

full_T = toeplitz([T0] + list(T), [T0] + list(T))

663

664

# Random right-hand side

665

Z = np.random.randn(n) + 1j * np.random.randn(n)

666

667

# Solve using specialized Toeplitz solver

668

try:

669

X_toep = spectrum.HERMTOEP(T0, T, Z)

670

print(f"Toeplitz solver successful")

671

672

# Verify solution

673

residual = np.linalg.norm(full_T @ X_toep - Z)

674

print(f"Residual error: {residual:.2e}")

675

676

except Exception as e:

677

print(f"Toeplitz solver failed: {e}")

678

# Fall back to standard solver

679

X_toep = np.linalg.solve(full_T, Z)

680

681

# Compare computational complexity demonstration

682

sizes = [8, 16, 32, 64, 128]

683

times_standard = []

684

times_toeplitz = []

685

686

import time

687

688

plt.figure(figsize=(12, 8))

689

690

plt.subplot(2, 2, 1)

691

plt.imshow(np.real(full_T), cmap='coolwarm')

692

plt.colorbar()

693

plt.title('Toeplitz Matrix (Real Part)')

694

695

plt.subplot(2, 2, 2)

696

solution_error = np.abs(X_toep - np.linalg.solve(full_T, Z))

697

plt.semilogy(solution_error, 'o-')

698

plt.title('Solution Error (Toeplitz vs Standard)')

699

plt.xlabel('Element Index')

700

plt.ylabel('Absolute Error')

701

plt.grid(True)

702

703

# Model selection criteria comparison on real data

704

# Generate test signals with different characteristics

705

plt.subplot(2, 2, 3)

706

707

# Generate AR signals with different orders

708

true_orders = [2, 4, 6, 8]

709

N = 150

710

test_orders = range(1, 12)

711

712

criteria_comparison = {}

713

for criterion in ['AIC', 'MDL', 'FPE']:

714

criteria_comparison[criterion] = []

715

716

for true_order in true_orders:

717

# Generate random AR coefficients

718

ar_coeffs = np.random.randn(true_order + 1)

719

ar_coeffs[0] = 1 # Normalize

720

721

# Ensure stability by scaling if needed

722

poles = np.roots(ar_coeffs)

723

if np.any(np.abs(poles) >= 1):

724

ar_coeffs[1:] *= 0.9 / np.max(np.abs(poles))

725

726

# Generate signal

727

noise = np.random.randn(N)

728

signal = np.zeros(N)

729

signal[:true_order] = noise[:true_order]

730

731

for n in range(true_order, N):

732

signal[n] = -np.sum(ar_coeffs[1:] * signal[n-true_order:n][::-1]) + noise[n]

733

734

# Find optimal orders using different criteria

735

for criterion in criteria_comparison:

736

criterion_values = []

737

for order in test_orders:

738

_, rho, _ = spectrum.aryule(signal, order)

739

if criterion == 'AIC':

740

val = spectrum.AIC(N, rho, order)

741

elif criterion == 'MDL':

742

val = spectrum.MDL(N, rho, order)

743

elif criterion == 'FPE':

744

val = spectrum.FPE(N, rho, order)

745

criterion_values.append(val)

746

747

optimal_order = test_orders[np.argmin(criterion_values)]

748

criteria_comparison[criterion].append(optimal_order)

749

750

# Plot criterion performance

751

x_pos = np.arange(len(true_orders))

752

width = 0.25

753

754

for i, criterion in enumerate(criteria_comparison):

755

plt.bar(x_pos + i*width, criteria_comparison[criterion], width,

756

label=criterion, alpha=0.7)

757

758

plt.bar(x_pos + len(criteria_comparison)*width, true_orders, width,

759

label='True Order', alpha=0.7, color='red')

760

761

plt.xlabel('Test Signal')

762

plt.ylabel('Selected Order')

763

plt.title('Criterion Performance Comparison')

764

plt.xticks(x_pos + width, [f'AR({order})' for order in true_orders])

765

plt.legend()

766

plt.grid(True, alpha=0.3)

767

768

# Statistical analysis of criterion performance

769

plt.subplot(2, 2, 4)

770

accuracy_scores = {}

771

for criterion in criteria_comparison:

772

correct_selections = sum(1 for pred, true in zip(criteria_comparison[criterion], true_orders)

773

if pred == true)

774

accuracy_scores[criterion] = correct_selections / len(true_orders) * 100

775

776

criteria_names = list(accuracy_scores.keys())

777

accuracy_values = list(accuracy_scores.values())

778

779

plt.bar(criteria_names, accuracy_values, color=['blue', 'green', 'orange'])

780

plt.ylabel('Accuracy (%)')

781

plt.title('Order Selection Accuracy')

782

plt.ylim(0, 100)

783

for i, v in enumerate(accuracy_values):

784

plt.text(i, v + 2, f'{v:.1f}%', ha='center')

785

plt.grid(True, alpha=0.3)

786

787

plt.tight_layout()

788

plt.show()

789

790

print(f"\nCriterion Performance Summary:")

791

print(f"-" * 35)

792

for criterion, accuracy in accuracy_scores.items():

793

print(f"{criterion:8s}: {accuracy:5.1f}% correct selections")

794

795

# Demonstrate eigenvalue computations for correlation matrices

796

print(f"\nCorrelation Matrix Properties:")

797

print(f"-" * 32)

798

799

# Generate signal and correlation matrix

800

test_signal = np.random.randn(100)

801

R = spectrum.corrmtx(test_signal, 10, method='autocorrelation')

802

803

eigenvals = np.linalg.eigvals(R)

804

condition_number = np.max(eigenvals) / np.min(eigenvals)

805

trace = np.trace(R)

806

determinant = np.linalg.det(R)

807

808

print(f"Matrix size: {R.shape}")

809

print(f"Condition number: {condition_number:.2e}")

810

print(f"Trace: {trace:.3f}")

811

print(f"Determinant: {determinant:.3e}")

812

print(f"Positive definite: {np.all(eigenvals > 0)}")

813

print(f"Eigenvalue range: [{np.min(eigenvals):.3e}, {np.max(eigenvals):.3e}]")

814

```