Skip to content
LIBRARY
Math.Tests.Ln.md

Math.Tests.Ln

Computes the natural logarithm of constant and time-varying inputs.

Connects a constant source with value e to a Ln block and verifies that ln(e) = 1. A second Ln block is driven by a sine wave (offset 2, amplitude 1.5) that stays strictly positive (0.5..3.5) as required by the logarithm domain while varying over time.

Usage

BlockComponents.Math.Tests.Ln()

Behavior

julia
using BlockComponents #hide
using ModelingToolkit #hide
@named sys = BlockComponents.Math.Tests.Ln() #hide
let eqs = full_equations(sys); Base.length(eqs) > 25 ? nothing : eqs end #hide
<< @example-block not executed in draft mode >>

Source

dyad
"""
Computes the natural logarithm of constant and time-varying inputs.

Connects a constant source with value e to a Ln block and verifies that
ln(e) = 1. A second Ln block is driven by a sine wave (offset 2,
amplitude 1.5) that stays strictly positive (0.5..3.5) as required by the
logarithm domain while varying over time.
"""
test component Ln
  "Constant source providing the input value e"
  c1 = BlockComponents.Sources.Constant(k = 2.718281828459045) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 10, "x2": 120, "y2": 110, "rot": 0}
      },
      "tags": []
    }
  }
  "Sine source kept strictly positive for the log domain"
  sine = BlockComponents.Sources.Sine(amplitude = 1.5, frequency = 1, offset = 2) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 140, "x2": 120, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  "Ln block under test"
  ln_block = BlockComponents.Math.Ln() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 190, "y1": 10, "x2": 290, "y2": 110, "rot": 0}
      },
      "tags": []
    }
  }
  "Second Ln block driven by the sine source"
  ln_block_2 = BlockComponents.Math.Ln() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 200, "y1": 140, "x2": 300, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
relations
  connect(c1.y, ln_block.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(sine.y, ln_block_2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
metadata {
  "Dyad": {
    "icons": {"default": "dyad://BlockComponents/Example.svg"},
    "tests": {
      "case1": {"stop": 1, "expect": {"signals": ["ln_block.y", "ln_block_2.y", "sine.y"]}}
    }
  }
}
end
Flattened Source
dyad
"""
Computes the natural logarithm of constant and time-varying inputs.

Connects a constant source with value e to a Ln block and verifies that
ln(e) = 1. A second Ln block is driven by a sine wave (offset 2,
amplitude 1.5) that stays strictly positive (0.5..3.5) as required by the
logarithm domain while varying over time.
"""
test component Ln
  "Constant source providing the input value e"
  c1 = BlockComponents.Sources.Constant(k = 2.718281828459045) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 10, "x2": 120, "y2": 110, "rot": 0}
      },
      "tags": []
    }
  }
  "Sine source kept strictly positive for the log domain"
  sine = BlockComponents.Sources.Sine(amplitude = 1.5, frequency = 1, offset = 2) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 140, "x2": 120, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
  "Ln block under test"
  ln_block = BlockComponents.Math.Ln() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 190, "y1": 10, "x2": 290, "y2": 110, "rot": 0}
      },
      "tags": []
    }
  }
  "Second Ln block driven by the sine source"
  ln_block_2 = BlockComponents.Math.Ln() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 200, "y1": 140, "x2": 300, "y2": 240, "rot": 0}
      },
      "tags": []
    }
  }
relations
  connect(c1.y, ln_block.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(sine.y, ln_block_2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
metadata {
  "Dyad": {
    "icons": {"default": "dyad://BlockComponents/Example.svg"},
    "tests": {
      "case1": {"stop": 1, "expect": {"signals": ["ln_block.y", "ln_block_2.y", "sine.y"]}}
    }
  }
}
end


Test Cases

julia
using BlockComponents
using DyadInterface: TransientAnalysis, rebuild_sol, ODEAlg
using ModelingToolkit: toggle_namespacing, get_initial_conditions, @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 = BlockComponents.Math.Tests.Ln()
model_case1 = toggle_namespacing(model_case1, false)

model_case1 = toggle_namespacing(model_case1, true)
result_case1 = TransientAnalysis(; model = model_case1, alg = ODEAlg.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.ln_block.y])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "BlockComponents.Math.Tests.Ln_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.ln_block.y], width=2, label="Actual value of ln_block.y")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of ln_block.y")
end
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.ln_block_2.y])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "BlockComponents.Math.Tests.Ln_case1_sig1.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.ln_block_2.y], width=2, label="Actual value of ln_block_2.y")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of ln_block_2.y")
end
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.sine.y])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "BlockComponents.Math.Tests.Ln_case1_sig2.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.sine.y], width=2, label="Actual value of sine.y")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of sine.y")
end
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>