Skip to content

Commit 6770392

Browse files
baggepinnenclaude
andcommitted
fix _default_dt for DelayLtiSystem to actually adapt to delay size
The previous heuristic always returned `0.07` because the appended `0` in `minimum([abs.(real.(ps));0])` and `minimum([sys.Tau;0])` forced `r = 0`, which then fell back to `r = 1.0`. As a result `step(delay(0.01))` (issue #544) sampled at `dt = 0.07` and could not resolve the delay. Rewritten to mirror `_default_dt(::LTISystem)`: take the fastest pole of `sys.P.P` and the smallest positive delay, and pick the more demanding of `1/(12·ω_max)` and `τ_min/12`. Add a regression test for #544. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2e102ad commit 6770392

2 files changed

Lines changed: 19 additions & 9 deletions

File tree

lib/ControlSystemsBase/src/delay_systems.jl

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,15 @@ end
8080
# Again we have to do something for default vectors, more or less a copy from timeresp.jl
8181
function _default_dt(sys::DelayLtiSystem)
8282
if !isstable(sys.P.P)
83-
return 0.05 # Something small
84-
else
85-
ps = poles(sys.P.P)
86-
r = minimum([abs.(real.(ps));0]) # Find the fastest pole of sys.P.P
87-
r = min(r, minimum([sys.Tau;0])) # Find the fastest delay
88-
if r == 0.0
89-
r = 1.0
90-
end
91-
return 0.07/r
83+
return 0.05
9284
end
85+
ps = poles(sys.P.P)
86+
ω_max = isempty(ps) ? 0.0 : maximum(abs, ps)
87+
τ_min = minimum((τ for τ in sys.Tau if τ > 0); init = Inf)
88+
dt_pole = ω_max > 0 ? round(1/(12*ω_max), sigdigits=2) : Inf
89+
dt_delay = isfinite(τ_min) ? round(τ_min/12, sigdigits=2) : Inf
90+
dt = min(dt_pole, dt_delay)
91+
return isfinite(dt) ? dt : 0.05
9392
end
9493

9594

test/test_delay_timeresp.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,14 @@ P = 1 / (0.85*s + 1)*exp(-0.14*s)
133133
res = step(P, 5)
134134
@test res.t[end] > 4.5
135135
@test length(res.y) > 30
136+
137+
# Issue #544: step(delay(τ)) with small τ used to throw BoundsError after
138+
# `dt <= dtmin` from the DDE solver; default dt now adapts to τ.
139+
let sys = delay(0.01)
140+
res = step(sys)
141+
@test res.t[2] - res.t[1] 0.01/5
142+
@test res.t[end] > 0.1
143+
@test all(isfinite, res.y)
144+
@test res.y[1] 0 atol = 1e-8
145+
@test res.y[end] 1 atol = 1e-3
146+
end

0 commit comments

Comments
 (0)