Skip to content
TriangularTest.md

TriangularTest

A test component that integrates a triangular signal over time.

This component connects a triangular wave generator to an integrator to demonstrate signal processing and integration. The triangular signal has amplitude 1, frequency 2 Hz, starts at time 0.5 seconds with an offset of 0.7. The output of the integrator represents the accumulated area under the triangular wave over time. The test case validates the behavior by checking both the initial signal value and the final integrated value after 5 seconds of simulation.

Usage

TriangularTest()

Behavior

signal.y(t)=integrator.u(t)dintegrator.x(t)dt=integrator.kintegrator.u(t)integrator.y(t)=integrator.x(t)signal.y(t)=ifelse(signal.start_time<t,signal.amplitude+4signal.amplitudesignal.frequency|12signal.period+|mod(14signal.periodsignal.start_time+t,signal.period)||,signal.offset)

Source

dyad
# A test component that integrates a triangular signal over time.
#
# This component connects a triangular wave generator to an integrator to demonstrate signal
# processing and integration. The triangular signal has amplitude 1, frequency 2 Hz, starts at
# time 0.5 seconds with an offset of 0.7. The output of the integrator represents the accumulated
# area under the triangular wave over time. The test case validates the behavior by checking both
# the initial signal value and the final integrated value after 5 seconds of simulation.
test component TriangularTest
  # Integrator component that accumulates the input signal
  integrator = Integrator()
  # Triangular waveform generator with configurable parameters
  signal = Triangular(amplitude=1, frequency=2, start_time=0.5, offset=0.7)
relations
  # Connects the triangular signal output to the integrator input
  connect(signal.y, integrator.u)
metadata {
  "Dyad": {
    "tests": {
      "case1": {
        "stop": 5,
        "atol": {"integrator.x": 0.001},
        "expect": {
          "initial": {"signal.y": 0.7},
          "signals": ["signal.y", "integrator.x"],
          "final": {"signal.y": 0, "integrator.x": 0.37664775}
        }
      }
    }
  }
}
end
Flattened Source
dyad
# A test component that integrates a triangular signal over time.
#
# This component connects a triangular wave generator to an integrator to demonstrate signal
# processing and integration. The triangular signal has amplitude 1, frequency 2 Hz, starts at
# time 0.5 seconds with an offset of 0.7. The output of the integrator represents the accumulated
# area under the triangular wave over time. The test case validates the behavior by checking both
# the initial signal value and the final integrated value after 5 seconds of simulation.
test component TriangularTest
  # Integrator component that accumulates the input signal
  integrator = Integrator()
  # Triangular waveform generator with configurable parameters
  signal = Triangular(amplitude=1, frequency=2, start_time=0.5, offset=0.7)
relations
  # Connects the triangular signal output to the integrator input
  connect(signal.y, integrator.u)
metadata {
  "Dyad": {
    "tests": {
      "case1": {
        "stop": 5,
        "atol": {"integrator.x": 0.001},
        "expect": {
          "initial": {"signal.y": 0.7},
          "signals": ["signal.y", "integrator.x"],
          "final": {"signal.y": 0, "integrator.x": 0.37664775}
        }
      }
    }
  }
}
end


Test Cases

This is setup code, that must be run before each test case.

julia
using BlockComponents
using ModelingToolkit, OrdinaryDiffEqDefault
using Plots
using CSV, DataFrames

snapshotsdir = joinpath(dirname(dirname(pathof(BlockComponents))), "test", "snapshots")
"/home/actions-runner-10/.julia/packages/BlockComponents/77kIK/test/snapshots"

Test Case case1

julia
@mtkbuild model_case1 = TriangularTest()
u0_case1 = []
prob_case1 = ODEProblem(model_case1, u0_case1, (0, 5))
sol_case1 = solve(prob_case1)
retcode: Success
Interpolation: 3rd order Hermite
t: 36-element Vector{Float64}:
 0.0
 9.999999999999999e-5
 0.0010999999999999998
 0.011099999999999997
 0.11109999999999996
 0.40724934087707937
 0.4998871231471219
 0.6192054161174637
 0.6785535881612494
 0.7629743248675664

 3.9562471838916724
 4.0767966191622795
 4.312842005802552
 4.418866556520492
 4.532323288840804
 4.767349573757548
 4.875154867465846
 4.9897118715790825
 5.0
u: 36-element Vector{Vector{Float64}}:
 [0.0]
 [6.999999999999998e-5]
 [0.0007699999999999996]
 [0.007769999999999996]
 [0.07776999999999995]
 [0.2850745386139555]
 [0.34992098620298523]
 [0.4148277272697794]
 [0.4623074983265873]
 [0.4820525249620402]

 [0.3761584667697886]
 [0.3920921139591759]
 [0.4783472826389373]
 [0.3978789222454089]
 [0.3757275596479829]
 [0.4998229171753308]
 [0.4389929810990218]
 [0.3770711349747602]
 [0.3766477526291389]
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.signal.y])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TriangularTest_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.signal.y], width=2, label="Actual value of signal.y")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of signal.y")
end
scatter!(plt, [df_case1.t[1]], [0.7], label="Initial Condition for `signal.y`")
scatter!(plt, [df_case1.t[end]], [0], label="Final Condition for `signal.y`")

plt

julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.integrator.x])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TriangularTest_case1_sig1.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.integrator.x], width=2, label="Actual value of integrator.x")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of integrator.x")
end
scatter!(plt, [df_case1.t[end]], [0.37664775], label="Final Condition for `integrator.x`")

plt