Skip to content
LimiterTest.md

LimiterTest ​

Test harness for the Limiter component that constrains signals to specified bounds.

This test component creates a signal chain that feeds a high-amplitude sine wave through an integrator and then into a limiter with bounds at -3 and 3. The limiter constrains the integrated sine wave output to stay within the specified bounds, demonstrating how signal limiting works in practice. The test includes verification of expected output values.

Usage ​

BlockComponents.LimiterTest()

Behavior ​

julia
using BlockComponents #hide
using ModelingToolkit #hide
@named sys = BlockComponents.LimiterTest() #hide
full_equations(sys) #hide
<< @example-block not executed in draft mode >>

Source ​

dyad
"""
Test harness for the Limiter component that constrains signals to specified bounds.

This test component creates a signal chain that feeds a high-amplitude sine wave through
an integrator and then into a limiter with bounds at -3 and 3. The limiter constrains the
integrated sine wave output to stay within the specified bounds, demonstrating how signal
limiting works in practice. The test includes verification of expected output values.
"""
test component LimiterTest
  "Limiter block that constraints signals between -3 and 3"
  limiter = Limiter(y_max = 3, y_min = -3) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 280, "y1": 20, "x2": 380, "y2": 120, "rot": 0}
      }
    }
  }
  "Integrator block that accumulates the input signal"
  integrator = Integrator() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 150, "y1": 20, "x2": 250, "y2": 120, "rot": 0}
      }
    }
  }
  "Sine wave generator with large amplitude to drive the system"
  sine = Sine(amplitude = 4 * π, frequency = 1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
      }
    }
  }
relations
  "Connect sine output to integrator input"
  connect(sine.y, integrator.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  "Connect integrator output to limiter input"
  connect(integrator.y, limiter.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
metadata {
  "Dyad": {
    "icons": {"default": "dyad://BlockComponents/Example.svg"},
    "tests": {
      "case1": {
        "stop": 1,
        "atol": {"limiter.y": 0.000001},
        "expect": {"signals": ["limiter.y"], "final": {"limiter.y": 0}}
      }
    }
  }
}
end
Flattened Source
dyad
"""
Test harness for the Limiter component that constrains signals to specified bounds.

This test component creates a signal chain that feeds a high-amplitude sine wave through
an integrator and then into a limiter with bounds at -3 and 3. The limiter constrains the
integrated sine wave output to stay within the specified bounds, demonstrating how signal
limiting works in practice. The test includes verification of expected output values.
"""
test component LimiterTest
  "Limiter block that constraints signals between -3 and 3"
  limiter = Limiter(y_max = 3, y_min = -3) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 280, "y1": 20, "x2": 380, "y2": 120, "rot": 0}
      }
    }
  }
  "Integrator block that accumulates the input signal"
  integrator = Integrator() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 150, "y1": 20, "x2": 250, "y2": 120, "rot": 0}
      }
    }
  }
  "Sine wave generator with large amplitude to drive the system"
  sine = Sine(amplitude = 4 * π, frequency = 1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
      }
    }
  }
relations
  "Connect sine output to integrator input"
  connect(sine.y, integrator.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  "Connect integrator output to limiter input"
  connect(integrator.y, limiter.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
metadata {
  "Dyad": {
    "icons": {"default": "dyad://BlockComponents/Example.svg"},
    "tests": {
      "case1": {
        "stop": 1,
        "atol": {"limiter.y": 0.000001},
        "expect": {"signals": ["limiter.y"], "final": {"limiter.y": 0}}
      }
    }
  }
}
end


Test Cases ​

julia
using BlockComponents
using DyadInterface: TransientAnalysis, rebuild_sol
using ModelingToolkit: toggle_namespacing, get_defaults, @named
using CSV, DataFrames, Plots

snapshotsdir = joinpath(dirname(dirname(pathof(BlockComponents))), "test", "snapshots")
<< @setup-block not executed in draft mode >>

Test Case case1 ​

julia
@named model_case1 = LimiterTest()
model_case1 = toggle_namespacing(model_case1, false)

model_case1 = toggle_namespacing(model_case1, true)
result_case1 = TransientAnalysis(; model = model_case1, alg = "auto", start = 0e+0, stop = 1e+0, abstol=1e-6, reltol=1e-6)
sol_case1 = rebuild_sol(result_case1)
<< @setup-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.limiter.y])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "LimiterTest_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.limiter.y], width=2, label="Actual value of limiter.y")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of limiter.y")
end
scatter!(plt, [df_case1.t[end]], [0], label="Final Condition for `limiter.y`")
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>