Skip to content

Commit 9a5d70d

Browse files
Merge pull request #59 from ven-k/vk/smooth_blocks
Add `smooth` sources in `Blocks` + Add `Square` and `Triangular` sources
2 parents 5db8c57 + 883baa8 commit 9a5d70d

File tree

4 files changed

+408
-62
lines changed

4 files changed

+408
-62
lines changed

src/Blocks/Blocks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export Abs, Sign, Sqrt, Sin, Cos, Tan, Asin, Acos, Atan, Atan2, Sinh, Cosh, Tanh
1616
export Log, Log10
1717
include("math.jl")
1818

19-
export Constant, Sine, Cosine, ContinuousClock, Ramp, Step, ExpSine
19+
export Constant, Sine, Cosine, ContinuousClock, Ramp, Step, ExpSine, Square, Triangular
2020
include("sources.jl")
2121

2222
export Limiter, DeadZone, SlewRateLimiter

src/Blocks/sources.jl

Lines changed: 204 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,47 @@
1+
# Define and register smooth functions
2+
# These are "smooth" aka differentiable and avoid Gibbs effect
3+
# These follow: `offset` + `smooth_wave` * `smooth_step` with zero output for `t < start_time`
4+
function smooth_cos(x, δ, f, amplitude, ϕ, offset, start_time)
5+
offset + amplitude * cos(2*π*f*(x - start_time) + ϕ) * smooth_step(x, δ, one(x), zero(x), start_time)
6+
end
7+
8+
function smooth_damped_sin(x, δ, f, amplitude, damping, ϕ, offset, start_time)
9+
offset + exp((start_time - x)*damping)*amplitude*sin(2*π*f*(x - start_time) + ϕ) * smooth_step(x, δ, one(x), zero(x), start_time)
10+
end
11+
12+
function smooth_ramp(x, δ, height, duration, offset, start_time)
13+
offset + height/(duration) * (smooth_xH(x, δ, start_time) - smooth_xH(x, δ, start_time+duration))
14+
end
15+
16+
function smooth_sin(x, δ, f, amplitude, ϕ, offset, start_time)
17+
offset + amplitude * sin(2*pi*f*(x - start_time) + ϕ) * smooth_step(x, δ, one(x), zero(x), start_time)
18+
end
19+
20+
function smooth_square(x, δ, f, amplitude, offset, start_time)
21+
offset + amplitude*2atan(sin(2π*(x - start_time)*f)/δ)/π * smooth_step(x, δ, one(x), zero(x), start_time)
22+
end
23+
24+
function smooth_step(x, δ, height, offset, start_time)
25+
offset + height*(atan((x - start_time)/δ)/π + 0.5)
26+
end
27+
28+
function smooth_triangular(x, δ, f, amplitude, offset, start_time)
29+
offset + amplitude * (1-2acos((1 - δ)sin(2π*(x - start_time)*f))/π) * smooth_step(x, δ, one(x), zero(x), start_time)
30+
end
31+
32+
function smooth_xH(x, δ, tₒ)
33+
0.5*(x-tₒ) * (1+((x-tₒ)/sqrt((x-tₒ)^2+δ^2)))
34+
end
35+
36+
function square(x, f, amplitude, offset, start_time)
37+
offset + (x > start_time) * (amplitude * (4*floor(f*(x - start_time)) - 2*floor(2*(x - start_time)*f) + 1))
38+
end
39+
40+
function triangular(x, f, amplitude, offset, start_time)
41+
p = 1/f # period
42+
offset + (x > start_time) * (4 * amplitude * f * abs(abs((x - p/4 - start_time) % p) - p/2) - amplitude)
43+
end
44+
145
"""
246
Generate constant signal.
347
@@ -22,25 +66,36 @@ Generate sine signal.
2266
# Parameters:
2367
- `frequency`: [Hz] Frequency of sine wave
2468
- `amplitude`: Amplitude of sine wave
25-
- `phase`: [rad] Phase of sine wave
69+
- `phase`: [rad] Phase of sine wave
2670
- `offset`: Offset of output signal
2771
- `start_time`: [s] Output `y = offset` for `t < start_time`
72+
- `smooth`: If `true`, returns a smooth wave. Defaults to `false`
73+
It uses a smoothing factor of `δ=1e-5`
2874
2975
# Connectors:
3076
- `output`
3177
"""
32-
function Sine(;name,
33-
frequency,
78+
function Sine(;name,
79+
frequency,
3480
amplitude=1,
3581
phase=0,
3682
offset=0,
37-
start_time=0)
83+
start_time=0,
84+
smooth=false)
3885

3986
@named output = RealOutput()
4087
pars = @parameters offset=offset start_time=start_time amplitude=amplitude frequency=frequency phase=phase
88+
equation = if smooth == false
89+
offset + ifelse(t < start_time, 0, amplitude* sin(2*pi*frequency*(t - start_time) + phase))
90+
else
91+
δ = 1e-5
92+
smooth_sin(t, δ, frequency, amplitude, phase, offset, start_time)
93+
end
94+
4195
eqs = [
42-
output.u ~ offset + ifelse(t < start_time, 0, amplitude* sin(2*pi*frequency*(t - start_time) + phase))
96+
output.u ~ equation
4397
]
98+
4499
compose(ODESystem(eqs, t, [], pars; name=name), [output])
45100
end
46101

@@ -50,32 +105,43 @@ Generate cosine signal.
50105
# Parameters:
51106
- `frequency`: [Hz] Frequency of sine wave
52107
- `amplitude`: Amplitude of sine wave
53-
- `phase`: [rad] Phase of sine wave
108+
- `phase`: [rad] Phase of sine wave
54109
- `offset`: Offset of output signal
55110
- `start_time`: [s] Output `y = offset` for `t < start_time`
111+
- `smooth`: If `true`, returns a smooth wave. Defaults to `false`
112+
It uses a smoothing factor of `δ=1e-5`
56113
57114
# Connectors:
58115
- `output`
59116
"""
60-
function Cosine(;name,
61-
frequency,
117+
118+
function Cosine(;name,
119+
frequency,
62120
amplitude=1,
63121
phase=0,
64122
offset=0,
65-
start_time=0)
123+
start_time=0,
124+
smooth=false)
66125

67126
@named output = RealOutput()
68127
pars = @parameters offset=offset start_time=start_time amplitude=amplitude frequency=frequency phase=phase
128+
equation = if smooth == false
129+
offset + ifelse(t < start_time, zero(t), amplitude* cos(2*pi*frequency*(t - start_time) + phase))
130+
else
131+
δ = 1e-5
132+
smooth_cos(t, δ, frequency, amplitude, phase, offset, start_time)
133+
end
69134
eqs = [
70-
output.u ~ offset + ifelse(t < start_time, 0, amplitude* cos(2*pi*frequency*(t - start_time) + phase))
135+
output.u ~ equation
71136
]
137+
72138
compose(ODESystem(eqs, t, [], pars; name=name), [output])
73139
end
74140

75141
"""
76142
Generate current time signal.
77143
78-
# Parameters:
144+
# Parameters:
79145
- `offset`: Offset of output signal
80146
- `start_time`: [s] Output `y = offset` for `t < start_time`
81147
@@ -86,8 +152,9 @@ function ContinuousClock(;name, offset=0, start_time=0)
86152
@named output = RealOutput()
87153
pars = @parameters offset=offset start_time=start_time
88154
eqs = [
89-
output.u ~ offset + ifelse(t < start_time, 0, t - start_time)
155+
output.u ~ offset + ifelse(t < start_time, zero(t), t - start_time)
90156
]
157+
91158
compose(ODESystem(eqs, t, [], pars; name=name), [output])
92159
end
93160

@@ -99,22 +166,73 @@ Generate ramp signal.
99166
- `duration`: [s] Duration of ramp (= 0.0 gives a Step)
100167
- `offset`: Offset of output signal
101168
- `start_time`: [s] Output `y = offset` for `t < start_time`
169+
- `smooth`: If `true`, returns a smooth wave. Defaults to `false`
170+
It uses a smoothing factor of `δ=1e-5`
102171
103172
# Connectors:
104173
- `output`
105174
"""
106-
function Ramp(;name,
107-
offset=0,
175+
function Ramp(;name,
108176
height=1,
109-
duration=1,
110-
start_time=0)
177+
duration=1,
178+
offset=0,
179+
start_time=0,
180+
smooth=false)
111181

112182
@named output = RealOutput()
113183
pars = @parameters offset=offset start_time=start_time height=height duration=duration
114-
eqs = [
115-
output.u ~ offset + ifelse(t < start_time, 0,
184+
equation = if smooth == false
185+
offset + ifelse(t < start_time, 0,
116186
ifelse(t < (start_time + duration), (t - start_time) * height / duration, height))
187+
else
188+
δ = 1e-5
189+
smooth_ramp(t, δ, height, duration, offset, start_time)
190+
end
191+
192+
eqs = [
193+
output.u ~ equation
194+
]
195+
196+
compose(ODESystem(eqs, t, [], pars; name=name), [output])
197+
end
198+
199+
"""
200+
Generate smooth square signal.
201+
202+
# Parameters:
203+
- `frequency`: [Hz] Frequency of square wave
204+
- `amplitude`: Amplitude of square wave
205+
- `offset`: Offset of output signal
206+
- `start_time`: [s] Output `y = offset` for `t < start_time`
207+
- `smooth`: If `true`, returns a smooth wave. Defaults to `false`
208+
It uses a smoothing factor of `δ=1e-5`
209+
210+
# Connectors:
211+
- `output`
212+
"""
213+
function Square(; name, frequency=1.0, amplitude=1.0,
214+
offset=0.0, start_time=0.0, smooth=false)
215+
δ = 1e-5
216+
217+
@named output = RealOutput()
218+
pars = @parameters begin
219+
frequency=frequency
220+
amplitude=amplitude
221+
offset=offset
222+
start_time=start_time
223+
end
224+
225+
equation = if smooth == false
226+
square(t, frequency, amplitude, offset, start_time)
227+
else
228+
δ = 1e-5
229+
smooth_square(t, δ, frequency, amplitude, offset, start_time)
230+
end
231+
232+
eqs = [
233+
output.u ~ equation
117234
]
235+
118236
compose(ODESystem(eqs, t, [], pars; name=name), [output])
119237
end
120238

@@ -125,16 +243,26 @@ Generate step signal.
125243
- `height`: Height of step
126244
- `offset`: Offset of output signal
127245
- `start_time`: [s] Output `y = offset` for `t < start_time`
246+
- `smooth`: If `true`, returns a smooth wave. Defaults to `false`
247+
It uses a smoothing factor of `δ=1e-5`
128248
129249
# Connectors:
130250
- `output`
131251
"""
132-
function Step(;name, offset=0, height=1, start_time=0)
252+
function Step(;name, height=1, offset=0, start_time=0, smooth=true)
133253
@named output = RealOutput()
134254
pars = @parameters offset=offset start_time=start_time height=height
255+
equation = if smooth == false
256+
offset + ifelse(t < start_time, zero(t), height)
257+
else
258+
δ = 1e-5
259+
smooth_step(t, δ, height, offset, start_time)
260+
end
261+
135262
eqs = [
136-
output.u ~ offset + ifelse(t < start_time, 0, height)
263+
output.u ~ equation
137264
]
265+
138266
compose(ODESystem(eqs, t, [], pars; name=name), [output])
139267
end
140268

@@ -145,26 +273,77 @@ Generate exponentially damped sine signal.
145273
- `frequency`: [Hz] Frequency of sine wave
146274
- `amplitude`: Amplitude of sine wave
147275
- `damping`: [1/s] Damping coefficient of sine wave
148-
- `phase`: [rad] Phase of sine wave
276+
- `phase`: [rad] Phase of sine wave
149277
- `offset`: Offset of output signal
150278
- `start_time`: [s] Output `y = offset` for `t < start_time`
279+
- `smooth`: If `true`, returns a smooth wave. Defaults to `false`
280+
It uses a smoothing factor of `δ=1e-5`
151281
152282
# Connectors:
153283
- `output`
154284
"""
155-
function ExpSine(;name,
156-
frequency,
285+
function ExpSine(; name,
286+
frequency,
157287
amplitude=1,
158288
damping=0.1,
159289
phase=0,
160290
offset=0,
161-
start_time=0)
291+
start_time=0,
292+
smooth=false)
162293

163294
@named output = RealOutput()
164295
pars = @parameters offset=offset start_time=start_time amplitude=amplitude frequency=frequency phase=phase damping=damping
296+
297+
equation = if smooth == false
298+
offset + ifelse(t < start_time, 0, amplitude * exp(-damping * (t - start_time)) * sin(2*pi*frequency*(t - start_time) + phase))
299+
else
300+
δ = 1e-5
301+
smooth_damped_sin(t, δ, frequency, amplitude, damping, phase, offset, start_time)
302+
end
303+
165304
eqs = [
166-
output.u ~ offset + ifelse(t < start_time, 0, amplitude * exp(-damping * (t - start_time)) * sin(2*pi*frequency*(t - start_time) + phase))
305+
output.u ~ equation
167306
]
307+
308+
compose(ODESystem(eqs, t, [], pars; name=name), [output])
309+
end
310+
311+
"""
312+
Generate smooth triangular signal for frequencies less than or equal to 25 Hz
313+
314+
# Parameters:
315+
- `frequency`: [Hz] Frequency of square wave
316+
- `amplitude`: Amplitude of square wave
317+
- `offset`: Offset of output signal.
318+
- `start_time`: [s] Output `y = offset` for `t < start_time`
319+
- `smooth`: If `true`, returns a smooth wave. Defaults to `false`
320+
It uses a smoothing factor of `δ=1e-5`
321+
322+
# Connectors:
323+
- `output`
324+
"""
325+
function Triangular(; name, amplitude=1.0, frequency=1.0,
326+
offset=0.0, start_time=0.0, smooth=false)
327+
328+
@named output = RealOutput()
329+
pars = @parameters begin
330+
amplitude=amplitude
331+
frequency=frequency
332+
offset=offset
333+
start_time=start_time
334+
end
335+
336+
equation = if smooth == false
337+
triangular(t, frequency, amplitude, offset, start_time)
338+
else
339+
δ = 1e-5
340+
smooth_triangular(t, δ, frequency, amplitude, offset, start_time)
341+
end
342+
343+
eqs = [
344+
output.u ~ equation
345+
]
346+
168347
compose(ODESystem(eqs, t, [], pars; name=name), [output])
169348
end
170349

0 commit comments

Comments
 (0)