Skip to content

Commit a0194fd

Browse files
Merge pull request #4 from GiorgioMedico/dev2
documentation code corrections, supported py 3.11, 3.12, 3.13
2 parents 74ddb36 + 7f7210e commit a0194fd

27 files changed

+872
-293
lines changed

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
- name: Set up Python
3737
uses: actions/setup-python@v5
3838
with:
39-
python-version: '3.11'
39+
python-version: '3.12'
4040
cache: 'pip'
4141

4242
- name: Install dependencies

.github/workflows/pre-commit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ jobs:
1313
- name: Set up Python
1414
uses: actions/setup-python@v5
1515
with:
16-
python-version: '3.10'
16+
python-version: '3.11'
1717
- uses: pre-commit/action@v3.0.1

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- name: Set up Python
1313
uses: actions/setup-python@v5
1414
with:
15-
python-version: '3.10'
15+
python-version: '3.12'
1616
- name: Install dependencies
1717
run: |
1818
python -m pip install --upgrade pip

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
python-version: ['3.10', '3.11', '3.12']
15+
python-version: ['3.11', '3.12', '3.13']
1616
steps:
1717
- uses: actions/checkout@v4
1818
- name: Set up Python ${{ matrix.python-version }}
@@ -39,7 +39,7 @@ jobs:
3939
runs-on: macos-latest
4040
strategy:
4141
matrix:
42-
python-version: ['3.10', '3.11', '3.12']
42+
python-version: ['3.11', '3.12', '3.13']
4343
steps:
4444
- uses: actions/checkout@v4
4545
- name: Set up Python ${{ matrix.python-version }}

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ default_language_version:
22
python: python3
33
repos:
44
- repo: https://github.com/pre-commit/pre-commit-hooks
5-
rev: v5.0.0
5+
rev: v6.0.0
66
hooks:
77
- id: check-ast
88
- id: check-builtin-literals
@@ -12,7 +12,7 @@ repos:
1212
- id: check-toml
1313

1414
- repo: https://github.com/astral-sh/ruff-pre-commit
15-
rev: 'v0.12.7'
15+
rev: 'v0.12.8'
1616
hooks:
1717
- id: ruff
1818
types_or: [python, pyi, jupyter]

ALGORITHMS.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ from interpolatepy import PolynomialTrajectory, BoundaryCondition, TimeInterval
690690
# Define boundary conditions
691691
initial = BoundaryCondition(position=0, velocity=0, acceleration=0)
692692
final = BoundaryCondition(position=1, velocity=0, acceleration=0)
693-
interval = TimeInterval(t0=0, t1=2)
693+
interval = TimeInterval(start=0, end=2)
694694

695695
# Generate quintic trajectory
696696
traj_func = PolynomialTrajectory.order_5_trajectory(initial, final, interval)
@@ -910,9 +910,9 @@ import numpy as np
910910
times = [0, 1, 2, 3]
911911
quats = [
912912
Quaternion.identity(),
913-
Quaternion.from_angle_axis(np.pi/2, [1, 0, 0]), # 90° about X
914-
Quaternion.from_angle_axis(np.pi, [0, 1, 0]), # 180° about Y
915-
Quaternion.from_angle_axis(np.pi/4, [0, 0, 1]) # 45° about Z
913+
Quaternion.from_angle_axis(np.pi/2, np.array([1, 0, 0])), # 90° about X
914+
Quaternion.from_angle_axis(np.pi, np.array([0, 1, 0])), # 180° about Y
915+
Quaternion.from_angle_axis(np.pi/4, np.array([0, 0, 1])) # 45° about Z
916916
]
917917

918918
# Create C² continuous interpolator

README.md

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,22 @@ bounds = TrajectoryBounds(v_bound=5.0, a_bound=10.0, j_bound=30.0)
6161
trajectory = DoubleSTrajectory(state, bounds)
6262

6363
print(f"Duration: {trajectory.get_duration():.2f}s")
64-
trajectory.plot()
64+
65+
# Manual plotting (DoubleSTrajectory doesn't have built-in plot method)
66+
t_eval = np.linspace(0, trajectory.get_duration(), 100)
67+
results = [trajectory.evaluate(t) for t in t_eval]
68+
positions = [r[0] for r in results]
69+
velocities = [r[1] for r in results]
70+
71+
plt.figure(figsize=(10, 6))
72+
plt.subplot(2, 1, 1)
73+
plt.plot(t_eval, positions)
74+
plt.ylabel('Position')
75+
plt.title('S-Curve Trajectory')
76+
plt.subplot(2, 1, 2)
77+
plt.plot(t_eval, velocities)
78+
plt.ylabel('Velocity')
79+
plt.xlabel('Time')
6580

6681
plt.show()
6782
```
@@ -128,13 +143,14 @@ orientations = [
128143
times = [0.0, 2.0, 5.0]
129144

130145
# Smooth quaternion trajectory with C² continuity
131-
quat_spline = QuaternionSpline(times, orientations, method="squad")
146+
quat_spline = QuaternionSpline(times, orientations, interpolation_method="squad")
132147

133148
# Evaluate at any time
134-
orientation = quat_spline.evaluate(3.5)
135-
angular_velocity = quat_spline.evaluate_angular_velocity(3.5)
149+
orientation, segment = quat_spline.interpolate_at_time(3.5)
150+
# For angular velocity, use interpolate_with_velocity
151+
orientation_with_vel, angular_velocity, segment = quat_spline.interpolate_with_velocity(3.5)
136152

137-
quat_spline.plot()
153+
# QuaternionSpline doesn't have built-in plotting - manual visualization needed
138154
plt.show()
139155
```
140156
</details>
@@ -145,14 +161,15 @@ plt.show()
145161
```python
146162
import numpy as np
147163
import matplotlib.pyplot as plt
148-
from interpolatepy import SmoothingCubicBSpline
164+
from interpolatepy import CubicSmoothingSpline
149165

150166
# Fit smooth curve to noisy data
151167
t = np.linspace(0, 10, 50)
152168
q = np.sin(t) + 0.1 * np.random.randn(50)
153169

154-
bspline = SmoothingCubicBSpline(t, q, smoothing=0.01)
155-
bspline.plot()
170+
# Use CubicSmoothingSpline with correct parameter name 'mu'
171+
spline = CubicSmoothingSpline(t, q, mu=0.01)
172+
spline.plot()
156173
plt.show()
157174
```
158175
</details>
@@ -174,10 +191,22 @@ print(f"Duration: {trajectory.get_duration():.2f}s")
174191

175192
# Evaluate trajectory
176193
t_eval = np.linspace(0, trajectory.get_duration(), 1000)
177-
positions = [trajectory.evaluate(t) for t in t_eval]
178-
velocities = [trajectory.evaluate_velocity(t) for t in t_eval]
179-
180-
trajectory.plot()
194+
results = [trajectory.evaluate(t) for t in t_eval]
195+
positions = [r[0] for r in results]
196+
velocities = [r[1] for r in results]
197+
198+
# Manual plotting
199+
plt.figure(figsize=(12, 8))
200+
plt.subplot(2, 1, 1)
201+
plt.plot(t_eval, positions)
202+
plt.ylabel('Position')
203+
plt.title('Industrial S-Curve Motion Profile')
204+
plt.grid(True)
205+
plt.subplot(2, 1, 2)
206+
plt.plot(t_eval, velocities)
207+
plt.ylabel('Velocity')
208+
plt.xlabel('Time')
209+
plt.grid(True)
181210
plt.show()
182211
```
183212
</details>

docs/algorithms.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,11 @@ The algorithm solves for total time considering all constraints and boundary con
349349

350350
# Evaluate at midpoint
351351
t_mid = trajectory.get_duration() / 2
352-
pos = trajectory.evaluate(t_mid)
353-
vel = trajectory.evaluate_velocity(t_mid)
354-
acc = trajectory.evaluate_acceleration(t_mid)
355-
jerk = trajectory.evaluate_jerk(t_mid)
352+
result = trajectory.evaluate(t_mid)
353+
pos = result[0]
354+
vel = result[1]
355+
acc = result[2]
356+
jerk = result[3]
356357
```
357358

358359
### Trapezoidal Trajectory

docs/api-reference.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ bspline = BSplineInterpolator(
135135
# Evaluate curve
136136
t = 2.5
137137
position = bspline.evaluate(t)
138-
velocity = bspline.evaluate_velocity(t)
138+
velocity = bspline.evaluate_derivative(t, order=1)
139139
```
140140

141141
#### ApproximationBSpline {#approximation-b-spline}
@@ -193,10 +193,11 @@ trajectory = DoubleSTrajectory(state, bounds)
193193

194194
# Evaluate trajectory
195195
t = trajectory.get_duration() / 2
196-
position = trajectory.evaluate(t)
197-
velocity = trajectory.evaluate_velocity(t)
198-
acceleration = trajectory.evaluate_acceleration(t)
199-
jerk = trajectory.evaluate_jerk(t)
196+
result = trajectory.evaluate(t)
197+
position = result[0]
198+
velocity = result[1]
199+
acceleration = result[2]
200+
jerk = result[3]
200201

201202
print(f"Duration: {trajectory.get_duration():.2f}s")
202203
```
@@ -215,7 +216,8 @@ print(f"Duration: {trajectory.get_duration():.2f}s")
215216

216217
**Example:**
217218
```python
218-
from interpolatepy import TrapezoidalTrajectory, TrajectoryParams
219+
from interpolatepy import TrapezoidalTrajectory
220+
from interpolatepy.trapezoidal import TrajectoryParams
219221

220222
# Define trajectory parameters
221223
params = TrajectoryParams(
@@ -273,7 +275,7 @@ final = BoundaryCondition(
273275
jerk=0.0
274276
)
275277

276-
interval = TimeInterval(t0=0.0, t1=2.0)
278+
interval = TimeInterval(start=0.0, end=2.0)
277279

278280
# Generate 7th-order polynomial
279281
traj_func = PolynomialTrajectory.order_7_trajectory(initial, final, interval)
@@ -319,7 +321,7 @@ import numpy as np
319321

320322
# Create quaternions
321323
q1 = Quaternion.identity()
322-
q2 = Quaternion.from_angle_axis(np.pi/2, [0, 0, 1]) # 90° about Z
324+
q2 = Quaternion.from_angle_axis(np.pi/2, np.array([0, 0, 1])) # 90° about Z
323325

324326
# SLERP interpolation
325327
t = 0.5
@@ -350,9 +352,9 @@ import numpy as np
350352
times = [0, 1, 2, 3]
351353
orientations = [
352354
Quaternion.identity(),
353-
Quaternion.from_angle_axis(np.pi/2, [1, 0, 0]),
354-
Quaternion.from_angle_axis(np.pi, [0, 1, 0]),
355-
Quaternion.from_angle_axis(np.pi/4, [0, 0, 1])
355+
Quaternion.from_angle_axis(np.pi/2, np.array([1, 0, 0])),
356+
Quaternion.from_angle_axis(np.pi, np.array([0, 1, 0])),
357+
Quaternion.from_angle_axis(np.pi/4, np.array([0, 0, 1]))
356358
]
357359

358360
# Create C² continuous quaternion spline
@@ -401,7 +403,7 @@ velocity = path.velocity(s) # Unit tangent vector
401403
acceleration = path.acceleration(s) # Zero for straight line
402404

403405
# Evaluate multiple points
404-
s_values = np.linspace(0, path.total_length, 50)
406+
s_values = np.linspace(0, path.length, 50)
405407
trajectory = path.evaluate_at(s_values)
406408
```
407409

docs/examples.md

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,21 @@ def plan_robot_trajectory():
2929
# Timing: approach, pick, lift, move, place, retract, home
3030
time_points = [0, 2, 3, 5, 7, 8, 10]
3131

32-
# Create splines for each joint
32+
# Create splines for each joint with error handling
3333
joint_splines = {}
3434
for joint, angles in waypoints.items():
35-
joint_splines[joint] = CubicSpline(
36-
time_points,
37-
np.radians(angles), # Convert to radians
38-
v0=0.0, vn=0.0 # Zero velocity at start/end
39-
)
35+
# Validate input data
36+
if len(angles) != len(time_points):
37+
raise ValueError(f"Joint {joint}: {len(angles)} angles != {len(time_points)} time points")
38+
39+
try:
40+
joint_splines[joint] = CubicSpline(
41+
time_points,
42+
np.radians(angles).tolist(), # Convert to radians and ensure list format
43+
v0=0.0, vn=0.0 # Zero velocity at start/end
44+
)
45+
except Exception as e:
46+
raise RuntimeError(f"Failed to create spline for joint {joint}: {e}")
4047

4148
return joint_splines, time_points
4249

@@ -255,9 +262,10 @@ velocities = []
255262
accelerations = []
256263

257264
for t in t_eval:
258-
s = trajectory.evaluate(t) # Path distance
259-
v = trajectory.evaluate_velocity(t) # Path velocity
260-
a = trajectory.evaluate_acceleration(t) # Path acceleration
265+
result = trajectory.evaluate(t) # Get all derivatives
266+
s = result[0] # Path distance
267+
v = result[1] # Path velocity
268+
a = result[2] # Path acceleration
261269

262270
pos = interpolate_position(s, waypoints, distances)
263271
path_positions.append(pos)
@@ -627,7 +635,7 @@ print(f"Maximum acceleration: {np.max(accelerations):.2f} units/s²")
627635
Advanced signal processing with smoothing splines:
628636

629637
```python
630-
from interpolatepy import CubicSmoothingSpline, smoothing_spline_with_tolerance, SplineConfig
638+
from interpolatepy import CubicSmoothingSpline
631639
import numpy as np
632640
import matplotlib.pyplot as plt
633641

@@ -661,14 +669,13 @@ def analyze_experimental_data():
661669
t_true, signal_true, t_measured, signal_measured = analyze_experimental_data()
662670

663671
# Apply different smoothing strategies
672+
from interpolatepy import CubicSpline
664673
smoothing_methods = {
665-
'No Smoothing': CubicSmoothingSpline(t_measured.tolist(), signal_measured.tolist(), mu=0.0),
674+
'No Smoothing': CubicSpline(t_measured.tolist(), signal_measured.tolist()), # Use CubicSpline for exact interpolation
666675
'Light Smoothing': CubicSmoothingSpline(t_measured.tolist(), signal_measured.tolist(), mu=0.001),
667676
'Medium Smoothing': CubicSmoothingSpline(t_measured.tolist(), signal_measured.tolist(), mu=0.01),
668677
'Heavy Smoothing': CubicSmoothingSpline(t_measured.tolist(), signal_measured.tolist(), mu=0.1),
669-
'Auto Smoothing': smoothing_spline_with_tolerance(
670-
np.array(t_measured), np.array(signal_measured), tolerance=0.2, config=SplineConfig()
671-
)[0] # Extract just the spline from the tuple
678+
'Auto Smoothing': CubicSmoothingSpline(t_measured.tolist(), signal_measured.tolist(), mu=0.05) # Medium auto-smoothing
672679
}
673680

674681
# Evaluate all methods
@@ -767,7 +774,21 @@ plt.grid(True)
767774

768775
# Frequency domain analysis
769776
ax5 = plt.subplot(3, 3, 7)
770-
from scipy import fft
777+
try:
778+
from scipy import fft
779+
except ImportError:
780+
# Fallback for older SciPy versions
781+
import scipy.fftpack as fft_module
782+
class FFTCompat:
783+
@staticmethod
784+
def fft(x):
785+
return fft_module.fft(x)
786+
787+
@staticmethod
788+
def fftfreq(n, d=1.0):
789+
return fft_module.fftfreq(n, d)
790+
791+
fft = FFTCompat()
771792

772793
# FFT of original noisy signal
773794
freqs = fft.fftfreq(len(t_measured), t_measured[1] - t_measured[0])
@@ -1084,8 +1105,9 @@ class AssemblyLineController:
10841105

10851106
for axis_name, traj in segment['axes'].items():
10861107
axis_idx = ['x', 'y', 'z'].index(axis_name)
1087-
robot_pos[axis_idx] = traj.evaluate(segment_time)
1088-
robot_vel[axis_idx] = traj.evaluate_velocity(segment_time)
1108+
result = traj.evaluate(segment_time)
1109+
robot_pos[axis_idx] = result[0]
1110+
robot_vel[axis_idx] = result[1]
10891111

10901112
robot_status = 'moving'
10911113
break

0 commit comments

Comments
 (0)