diff --git a/REQUIRE b/REQUIRE index 49e794c12..366f591bb 100644 --- a/REQUIRE +++ b/REQUIRE @@ -3,3 +3,4 @@ Plots 0.7.4 Polynomials LaTeXStrings Requires +Formatting diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index d463e62fb..a00b02608 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -32,3 +32,4 @@ pages: - Synthesis: 'lib/synthesis.md' - 'Time and Frequency response': 'lib/timefreqresponse.md' - Plotting: 'lib/plotting.md' + - Display: 'lib/display.md' diff --git a/docs/src/index.md b/docs/src/index.md index 1dee196f2..60f975d1d 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -20,12 +20,12 @@ Depth = 1 ## Functions ```@contents -Pages = ["lib/constructors.md", "lib/plotting.md"] +Pages = ["lib/constructors.md", "lib/plotting.md", "lib/display.md"] ``` ## Documentation Index ```@index -Pages = ["lib/constructors.md", "lib/plotting.md", "lib/syntheis.md", "lib/timefreqresponse.md", "lib/analysis.md"] +Pages = ["lib/constructors.md", "lib/plotting.md", "lib/syntheis.md", "lib/timefreqresponse.md", "lib/analysis.md", "lib/display.md"] Depth = 1 ``` diff --git a/docs/src/lib/display.md b/docs/src/lib/display.md new file mode 100644 index 000000000..084fc0ee6 --- /dev/null +++ b/docs/src/lib/display.md @@ -0,0 +1,10 @@ +```@index +Pages = ["display.md"] +``` + +# Displaying Transfer Functions + +```@docs +print +show +``` diff --git a/src/ControlSystems.jl b/src/ControlSystems.jl index 926d5f4bb..dc4fd343a 100644 --- a/src/ControlSystems.jl +++ b/src/ControlSystems.jl @@ -65,9 +65,12 @@ export LTISystem, sigma, # utilities numpoly, - denpoly + denpoly, + # display + show, + print -using Plots, LaTeXStrings, Requires +using Plots, LaTeXStrings, Requires, Formatting import Base: +, -, *, /, (./), (==), (.+), (.-), (.*), (!=), isapprox, convert, promote_op include("types/lti.jl") diff --git a/src/types/polys.jl b/src/types/polys.jl index 517e02d66..91e96a9ff 100644 --- a/src/types/polys.jl +++ b/src/types/polys.jl @@ -49,10 +49,11 @@ end Base.print(io::IO, p::Poly) = print_poly(io, p) -function print_poly{T}(io::IO, p::Poly{T}, var=:x) +function print_poly{T}(io::IO, p::Poly{T}, var=:x, precision::Int=-1) + pformat = precision >= 0 ? string(".", precision, "g") : "g" n = length(p) if n == 1 - print(io, p[1]) + print(io, format(p[1], conversion=pformat)) else for j = 1:n pj = p[j] @@ -63,11 +64,14 @@ function print_poly{T}(io::IO, p::Poly{T}, var=:x) else real(pj) < 0 ? print(io," - ") : print(io," + ") end + exp = n-j #Print pj if pj is the last coefficient, or pj is not identically 1 if j == n || abs(magpj - 1) > 2*eps(T) - print(io, magpj) + print(io, format(magpj, conversion=pformat)) + if exp > 0 + print(io, "*") + end end - exp = n-j if exp > 0 print(io, var) if exp > 1 diff --git a/src/types/sisotf.jl b/src/types/sisotf.jl index 802d40091..672dbd300 100644 --- a/src/types/sisotf.jl +++ b/src/types/sisotf.jl @@ -18,10 +18,10 @@ function minreal(sys::SisoRational, eps::Real=sqrt(eps())) return SisoRational(minreal(SisoZpk(sys), eps)) end -function print_siso(io::IO, t::SisoRational, var=:s) +function print_siso(io::IO, t::SisoRational, var=:s, precision::Int=-1) # Convert the numerator and denominator to strings - numstr = sprint(print_poly, t.num, var) - denstr = sprint(print_poly, t.den, var) + numstr = sprint(print_poly, t.num, var, precision) + denstr = sprint(print_poly, t.den, var, precision) # Figure out the length of the separating line len_num = length(numstr) diff --git a/src/types/sisozpk.jl b/src/types/sisozpk.jl index 957832d29..be6b26600 100644 --- a/src/types/sisozpk.jl +++ b/src/types/sisozpk.jl @@ -105,19 +105,19 @@ function evalfr(sys::SisoZpk, s::Number) end end -function print_siso(io::IO, t::SisoZpk, var=:s) +function print_siso(io::IO, t::SisoZpk, var=:s, precision::Int=-1) zpolys = zp2polys(t.z) ppolys = zp2polys(t.p) # Convert the numerator and denominator to strings if length(zpolys) < 2 - numstr = ( length(zpolys) == 0 ) ? "1.0" : sprint(print_poly, zpolys[1], var) + numstr = ( length(zpolys) == 0 ) ? "1.0" : sprint(print_poly, zpolys[1], var, precision) else - numstr = reduce(*,"",["("*sprint(print_poly, z, var)*")" for z in zpolys]) + numstr = reduce(*,"",["("*sprint(print_poly, z, var, precision)*")" for z in zpolys]) end if length(ppolys) < 2 - denstr = ( length(ppolys) == 0 ) ? "1.0" : sprint(print_poly, ppolys[1], var) + denstr = ( length(ppolys) == 0 ) ? "1.0" : sprint(print_poly, ppolys[1], var, precision) else - denstr = reduce(*,"",["("*sprint(print_poly, p, var)*")" for p in ppolys]) + denstr = reduce(*,"",["("*sprint(print_poly, p, var, precision)*")" for p in ppolys]) end # Figure out the length of the separating line len_num = length(numstr) @@ -131,7 +131,8 @@ function print_siso(io::IO, t::SisoZpk, var=:s) denstr = "$(repeat(" ", div(dashcount - len_den, 2)))$denstr" end - gainstr = string(t.k) + pformat = precision >= 0 ? string(".", precision, "g") : "g" + gainstr = format(t.k, conversion=pformat) #Add spaces to account for gain string numstr = " "^(length(gainstr))*numstr denstr = " "^(length(gainstr))*denstr diff --git a/src/types/transferfunction.jl b/src/types/transferfunction.jl index 6913730d1..cfab53e68 100644 --- a/src/types/transferfunction.jl +++ b/src/types/transferfunction.jl @@ -461,9 +461,36 @@ end ## Display Functions ## ##################################################################### -Base.print(io::IO, t::TransferFunction) = show(io, t) +@doc """`print(io::IO, t::TransferFunction, precision::Int=-1)` -function Base.show(io::IO, t::TransferFunction) +Print a string representation of the transfer function: + +`io`: the `IO` stream to print to + +`t`: the transfer function + +`precision`: the precision to round each number to (default is 5) + +Other uses: + +`print(t::TransferFunction, precision::Int=-1)`: prints to `STDOUT`""" -> +Base.print(io::IO, t::TransferFunction, precision::Int=-1) = show(io, t, precision) +Base.print(t::TransferFunction, precision::Int=-1) = show(t, precision) + +@doc """`show(io::IO, t::TransferFunction, precision::Int=-1)` + +Print a string representation of the transfer function: + +`io`: the `IO` stream to print to + +`t`: the transfer function + +`precision`: the precision to round each number to (default is 5) + +Other uses: + +`show(t::TransferFunction, precision::Int=-1)`: prints to `STDOUT`""" -> +function Base.show(io::IO, t::TransferFunction, precision::Int=-1) # Compose the name vectors inputs = format_names(t.inputnames, "Input ", "?") outputs = format_names(t.outputnames, "Output ", "?") @@ -474,7 +501,7 @@ function Base.show(io::IO, t::TransferFunction) if !issiso(t) println(io, inputs[i], " to ", outputs[o]) end - print_siso(io, t.matrix[o, i], tftype) + print_siso(io, t.matrix[o, i], tftype, precision) if !(i == t.nu && o == t.ny) print(io, "\n") end @@ -492,3 +519,4 @@ function Base.show(io::IO, t::TransferFunction) print(io, "\nDiscrete-time transfer function model") end end +Base.show(t::TransferFunction, precision::Int=-1) = show(STDOUT, t, precision) diff --git a/test/test_transferfunction.jl b/test/test_transferfunction.jl index daa78e6de..31690e2ce 100644 --- a/test/test_transferfunction.jl +++ b/test/test_transferfunction.jl @@ -75,21 +75,115 @@ tf(vecarray(1, 2, [0], [0]), vecarray(1, 2, [1], [1]), 0.005) @test C_222[1,1:2] == C_221 @test size(C_222[1,[]]) == (1,0) -# Printing -res = ("TransferFunction:\nInput 1 to Output 1\ns^2 + 2.0s + 3.0\n-----------"* - "------\ns^2 + 8.0s + 15.0\n\nInput 1 to Output 2\ns^2 + 2.0s + 3.0\n-"* - "----------------\ns^2 + 8.0s + 15.0\n\nInput 2 to Output 1\n s + "* - "2.0\n-----------------\ns^2 + 8.0s + 15.0\n\nInput 2 to Output 2\n "* - " s + 2.0\n-----------------\ns^2 + 8.0s + 15.0\n\nContinuous-time"* - " transfer function model") +# Printing (default, specific precision, zpk) +res = ("TransferFunction:\n"* + "Input 1 to Output 1\n"* + "s^2 + 2*s + 3\n"* + "--------------\n"* + "s^2 + 8*s + 15\n"* + "\n"* + "Input 1 to Output 2\n"* + "s^2 + 2*s + 3\n"* + "--------------\n"* + "s^2 + 8*s + 15\n"* + "\n"* + "Input 2 to Output 1\n"* + " s + 2\n"* + "--------------\n"* + "s^2 + 8*s + 15\n"* + "\n"* + "Input 2 to Output 2\n"* + " s + 2\n"* + "--------------\n"* + "s^2 + 8*s + 15\n"* + "\n"* + "Continuous-time transfer function model") @test sprint(show, C_222) == res -res = ("TransferFunction:\nInput 1 to Output 1\nz^2 + 2.0z + 3.0\n-----------"* - "------\nz^2 - 0.2z - 0.15\n\nInput 1 to Output 2\nz^2 + 2.0z + 3.0\n-"* - "----------------\nz^2 - 0.2z - 0.15\n\nInput 2 to Output 1\n z + "* - "2.0\n-----------------\nz^2 - 0.2z - 0.15\n\nInput 2 to Output 2\n "* - " z + 2.0\n-----------------\nz^2 - 0.2z - 0.15\n\nSample Time: 0.005 "* - "(seconds)\nDiscrete-time transfer function model") +res = ("TransferFunction:\n"* + "Input 1 to Output 1\n"* + " z^2 + 2*z + 3\n"* + "------------------\n"* + "z^2 - 0.2*z - 0.15\n"* + "\n"* + "Input 1 to Output 2\n"* + " z^2 + 2*z + 3\n"* + "------------------\n"* + "z^2 - 0.2*z - 0.15\n"* + "\n"* + "Input 2 to Output 1\n"* + " z + 2\n"* + "------------------\n"* + "z^2 - 0.2*z - 0.15\n"* + "\n"* + "Input 2 to Output 2\n"* + " z + 2\n"* + "------------------\n"* + "z^2 - 0.2*z - 0.15\n"* + "\n"* + "Sample Time: 0.005 (seconds)\n"* + "Discrete-time transfer function model") @test sprint(show, D_222) == res +res = ("TransferFunction:\n"* + "Input 1 to Output 1\n"* + " s^2 + 2*s + 3\n"* + "-----------------\n"* + "s^2 + 8*s + 2e+01\n"* + "\n"* + "Input 1 to Output 2\n"* + " s^2 + 2*s + 3\n"* + "-----------------\n"* + "s^2 + 8*s + 2e+01\n"* + "\n"* + "Input 2 to Output 1\n"* + " s + 2\n"* + "-----------------\n"* + "s^2 + 8*s + 2e+01\n"* + "\n"* + "Input 2 to Output 2\n"* + " s + 2\n"* + "-----------------\n"* + "s^2 + 8*s + 2e+01\n"* + "\n"* + "Continuous-time transfer function model") +@test sprint(show, C_222, 1) == res +res = ("TransferFunction:\n"* + "Input 1 to Output 1\n"* + " z^2 + 2*z + 3\n"* + "-----------------\n"* + "z^2 - 0.2*z - 0.1\n"* + "\n"* + "Input 1 to Output 2\n"* + " z^2 + 2*z + 3\n"* + "-----------------\n"* + "z^2 - 0.2*z - 0.1\n"* + "\n"* + "Input 2 to Output 1\n"* + " z + 2\n"* + "-----------------\n"* + "z^2 - 0.2*z - 0.1\n"* + "\n"* + "Input 2 to Output 2\n"* + " z + 2\n"* + "-----------------\n"* + "z^2 - 0.2*z - 0.1\n"* + "\n"* + "Sample Time: 0.005 (seconds)\n"* + "Discrete-time transfer function model") +@test sprint(show, D_222, 1) == res +res = ("TransferFunction:\n"* + " s - 1.12345\n"* + "4.45678--------------------------\n"* + " (s - 3.67891)(s - 2.54321)\n"* + "\n"* + "Continuous-time transfer function model") +@test sprint(show, zpk([1.12345], [2.54321;3.67891], 4.45678)) == res +res = ("TransferFunction:\n"* + " s - 1.1\n"* + "4.5------------------\n"* + " (s - 3.7)(s - 2.5)\n"* + "\n"* + "Continuous-time transfer function model") +@test sprint(show, zpk([1.12345], [2.54321;3.67891], 4.45678), 2) == res # Type stability Continuous-time @test eltype(fill(tf("s"),2)) <: TransferFunction