text:
using Colors, CSV, DataFrames, Loess, PGFPlotsX
sdbout = tempname()
regs = CSV.File("regioner.csv", delim=';') |> DataFrame |>
	df -> zip(df[:reg], df[:text]) |> Dict
ages = CSV.File("aldrar.csv", delim=';') |> DataFrame |>
	df -> zip(df[:age], df[:text]) |> Dict
sexes = Dict(1 => "män", 2 => "kvinnor")
cas = Dict(:circ => Dict(:text => "cirkulation", :expr => "I00-I99|F01"),
	:tum => Dict(:text => "tumör", :expr => "C00-D48"))

function propyrs_allreg(age, ca1, ca2)
	run(pipeline(`./propyrs_allreg.sh "[12]" "$(age)" "$(cas[ca1][:expr])" "$(cas[ca2][:expr])"`,
		stdout=sdbout))
	df = CSV.File(sdbout, header=[:year, :reg, :sex, :ca1n, :ca2n, :rat],
		delim=';') |> DataFrame
	Dict(:meta => Dict(:age => age, :ca1 => ca1, :ca2 => ca2),
		:df => df)
end

propyr_regs_sex_df(inframe, year, sex) =
	sort(inframe[(inframe[:year].==year) .& (inframe[:sex].==sex), [:reg, :ca1n, :ca2n, :rat]],
		:rat)

function propyrs_reg_sex(indict, reg, sex)
	meta = copy(indict[:meta])
	meta[:reg] = reg
	meta[:sex] = sex
	Dict(:meta => meta, :df => propyrs_reg_sex_df(indict[:df], reg, sex))
end

function propyrs_reg_sex_df(inframe, reg, sex)
	df = inframe[(inframe[:reg].==reg) .& (inframe[:sex].==sex), [:year, :ca1n, :ca2n, :rat]]
	yearvec = Vector{Float64}(df[:year])
	ratvec = Vector{Float64}(df[:rat])
	lo = loess(yearvec, ratvec)
	df[:rat_lo] = predict(lo, yearvec)
	df
end

function propyrs_regs_sex_plot(indict, regs, sex)
	ca1lab = cas[indict[:meta][:ca1]][:text]
	ca2lab = cas[indict[:meta][:ca2]][:text]
	agelab = ages[indict[:meta][:age]]
	sexlab = sexes[sex]
	sax = @pgf Axis({"yticklabel style"={"/pgf/number format/use comma"},
                       "xticklabel style"={"/pgf/number format/set thousands separator={}"},
                       "legend style"={"font=\\tiny"},
                       legend_pos="outer north east", ylabel="$(ca1lab)/$(ca2lab)",
                       "xtick distance"=5, "ytick distance"=.2,
                       title="Antal dödsfall $(ca1lab)/$(ca2lab) $(sexlab) $(agelab) Sverige",
                       xmajorgrids, ymajorgrids})
	plotcolors = distinguishable_colors(length(regs)+1, [RGB(1,1,1)])[2:end]
	for (i, reg) in enumerate(regs)
		rd = propyrs_reg_sex(indict, reg, sex)
		propyrs_reg_plot(rd, sax, plotcolors[i])
	end
	sax
end

function propyrs_reg_plot(indict, p, plotcolor)
	inframe = indict[:df]
	@pgf push!(p, PlotInc({"only marks", mark_options = "solid", color = plotcolor},
		Table([inframe[:year], inframe[:rat]])),
		LegendEntry("$(regs[indict[:meta][:reg]])"),
		PlotInc({no_markers, color = plotcolor},
		Table([inframe[:year], inframe[:rat_lo]])),
		LegendEntry("loess"))
end

max_stars_repo_name: klpn/static-dust

max_issues_repo_name: klpn/static-dust

max_forks_repo_name: klpn/static-dust


text:
export partition, translate_partition, align_partitions

"""
    partition(n::Integer, p::Integer, i::Integer)

Divide the integers from `1` to `n` into `p` evenly sized partitions, and return a `UnitRange`
making up the integers of the `i`-th partition.
"""
function partition(n::Integer, p::Integer, i::Integer)
    0 < n || throw(ArgumentError("n must be positive, but is $n"))
    0 < p <= n || throw(ArgumentError("p must be in [1, $n], but is $p"))
    0 < i <= p || throw(ArgumentError("i must be in [1, $p], but is $i"))
    (div((i-1)*n, p)+1):div(i*n, p)
end

"""
    translate_partition(n::Integer, p::Integer, q::Integer, i::Integer)

Find `j` such that the `j`-th out of `q` partitions contains the first element contained in the
`i`-th out of `p` partitions.
"""
function translate_partition(n::Integer, p::Integer, q::Integer, i::Integer)
    0 < n || throw(ArgumentError("n must be positive, but is $n"))
    0 < p <= n || throw(ArgumentError("p must be in [1, $n], but is $p"))
    0 < q <= n || throw(ArgumentError("q must be in [1, $n], but is $q"))
    0 < i <= p || throw(ArgumentError("i must be in [1, $p], but is $i"))
    ceil(Int, first(partition(n, p, i)) / n * q)
end

"""
    align_partitions(n::Integer, p::Integer, q::Integer, i::Integer)

Find the largest `j` smaller than or equal to `translate_partition(n, p, q, i)` such that the first
element of the `j`-th out of `q` partitions is equal to the first element of the `i`-th out of `p`
partitions.
"""
function align_partitions(n::Integer, p::Integer, q::Integer, i::Integer)
    0 < n || throw(ArgumentError("n must be positive, but is $n"))
    0 < p <= n || throw(ArgumentError("p must be in [1, $n], but is $p"))
    0 < q <= n || throw(ArgumentError("q must be in [1, $n], but is $q"))
    0 < i <= p || throw(ArgumentError("i must be in [1, $p], but is $i"))
    j = translate_partition(n, p, q, i)
    i = translate_partition(n, q, p, j)
    while first(partition(n, q, j)) != first(partition(n, p, i))
        j -= 1
        i = translate_partition(n, q, p, j)
    end
    j
end

ext: jl


text:
using Unityper
using Test

@testset "Unityper.jl" begin
    @time include("compactify.jl")
end


text:
# ---
# title: Axis tweaking
# cover: assets/axis_tweaking.png
# description: Setting axis attributes
# author: "[Pietro Vertechi](https://github.com/piever)"
# ---

using AlgebraOfGraphics, CairoMakie
set_aog_theme!() #src

# To tweak one or more axes, simply use the `axis` keyword when plotting. For example

df = (x=rand(100), y=rand(100), z=rand(100))
layers = linear() + mapping(color=:z)
plt = data(df) * layers * mapping(:x, :y)
draw(plt, axis=(aspect=1,))

#

fg = draw(plt, axis=(aspect=1, xticks=0:0.1:1, yticks=0:0.1:1, ylabel="custom label"))

# save cover image #src
mkpath("assets") #src
save("assets/axis_tweaking.png", fg) #src


text:
## utility functions ##

function stepup!{T<:AbstractFloat}(sortedPValues::Vector{T}, multiplier::Function, n::Integer = length(sortedPValues))
    sortedPValues[n] *= multiplier(0, n)
    for i in 1:(n-1)
        sortedPValues[n-i] = min(sortedPValues[n-i+1], sortedPValues[n-i] * multiplier(i, n))
    end
    return sortedPValues
end

# multiplier stepdown
function stepdown!{T<:AbstractFloat}(sortedPValues::Vector{T}, multiplier::Function, n::Integer = length(sortedPValues))
  stepfun(p::T, i::Int, n::Int) = p*multiplier(i,n)
  general_stepdown!(sortedPValues, stepfun, n)
  return sortedPValues
end

function general_stepdown!{T<:AbstractFloat}(sortedPValues::Vector{T}, stepfun::Function, n::Integer = length(sortedPValues))
    sortedPValues[1] = stepfun(sortedPValues[1], 1, n)
    for i in 2:n
        sortedPValues[i] = max(sortedPValues[i-1], stepfun(sortedPValues[i],i, n))
    end
    return sortedPValues
end

function reorder{T<:Number}(values::Vector{T})
    newOrder = sortperm(values)
    oldOrder = sortperm(newOrder)
    return newOrder, oldOrder
end

function validPValues{T<:AbstractFloat}(x::Vector{T})
    if !isin(x)
        throw(DomainError())
    end
end

function isin(x::Real, lower::Real = 0., upper::Real = 1.)
    x >= lower && x <= upper
end

function isin{T<:Real}(x::Vector{T}, lower::Real = 0., upper::Real = 1.)
    ex = extrema(x)
    ex[1] >= lower && ex[2] <= upper
end

function isotonicregression(y::Array{Float64,1},w::Array{Float64,1})
  #todo: ignore zero weights
  y=copy(y)
  w=copy(w)
  m = length(y)
  cnts = ones(Int64,m)
  i = 2
  # ... not most efficient way but could be fun to (ab)use iterator protocol
  while (!done(y,i))
    if y[i]<y[i-1]
      y[i-1]=(w[i]*y[i]+w[i-1]*y[i-1])/(w[i]+w[i-1])
      w[i-1]=w[i]+w[i-1]
      cnts[i-1] += cnts[i]
      deleteat!(y,i)
      deleteat!(w,i)
      deleteat!(cnts,i)
      i = max(i-2,1)
    end
    i += 1
  end
  yisotonic = vcat([y[idx]*ones(Float64,cnt) for (idx,cnt) in enumerate(cnts)]...)
end

function isotonicregression(y::Array{Float64,1})
  isotonicregression(y, ones(Float64, length(y)))
end

function isotonic_regression(y::Vector{Float64}, weights::Vector{Float64})
    n = length(y)
    if n <= 1
        return y
    end
    if n != length(weights)
        throw(DimensionMismatch("Lengths of values and weights mismatch"))
    end
    @inbounds begin
        n -= 1
        while true
            i = 1
            is_pooled = false
            while i <= n
                k = i
                while k <= n && y[k] >= y[k+1]
                    k += 1
                end
                if y[i] != y[k]
                    numerator = 0.0
                    denominator = 0.0
                    for j in i:k
                        numerator += y[j] * weights[j]
                        denominator += weights[j]
                    end
                    m = numerator / denominator
                    for j in i:k
                        y[j] = m
                    end
                    is_pooled = true
                end
                i = k + 1
            end
            if !is_pooled
               break
            end
        end
    end
    return y
end

function isotonic_regression(y::Vector{Float64})
    isotonic_regression(y, ones(y))
end

function grenander(pv::Vector{Float64})
    pv_sorted = sort(pv)
    ## ecdf that handles duplicated values
    pv_sorted_unique, counts = rle(pv_sorted)
    ecdf_value = cumsum(counts)
    ecdf_value = ecdf_value ./ ecdf_value[end]

    Δx = diff(pv_sorted_unique)
    Δy = diff(ecdf_value)

    f = Δy ./ Δx
    f = -isotonic_regression(-f, Δx)
    F  = ecdf_value[1] + vcat(0, cumsum(f .* Δx))
    f = push!(f, f[end])

    return pv_sorted_unique, f, F
end


text:
# Autogenerated wrapper script for SDL2_ttf_jll for x86_64-apple-darwin
export libsdl2_ttf

using Bzip2_jll
using FreeType2_jll
using Glib_jll
using Graphite2_jll
using libpng_jll
using PCRE_jll
using SDL2_jll
JLLWrappers.@generate_wrapper_header("SDL2_ttf")
JLLWrappers.@declare_library_product(libsdl2_ttf, "@rpath/libSDL2_ttf-2.0.0.dylib")
function __init__()
    JLLWrappers.@generate_init_header(Bzip2_jll, FreeType2_jll, Glib_jll, Graphite2_jll, libpng_jll, PCRE_jll, SDL2_jll)
    JLLWrappers.@init_library_product(
        libsdl2_ttf,
        "lib/libSDL2_ttf.dylib",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
using CompScienceMeshes
using BEAST

using Test
using LinearAlgebra

faces = meshrectangle(1.0, 1.0, 0.5, 3)
srt_bnd_faces = sort.(boundary(faces))
edges = submesh(skeleton(faces,1)) do edge
    !(sort(edge) in srt_bnd_faces)
end

srt_bnd_nodes = sort.(skeleton(boundary(faces),0))
@test length(srt_bnd_nodes) == 8
nodes = submesh(skeleton(faces,0)) do node
    !(sort(node) in srt_bnd_nodes)
end
@test length(nodes) == 1

Conn = connectivity(nodes, edges, sign)

X = raviartthomas(faces, cellpairs(faces,edges))
@test numfunctions(X) == 8

divX = divergence(X)
Id = BEAST.Identity()
DD = assemble(Id, divX, divX)
@test rank(DD) == 7
L = divX * Conn
for sh in L.fns[1]
    @test isapprox(sh.coeff, 0, atol=1e-8)
end


text:
# Interface definition for Soapy SDR devices.

using Base.Meta

# General design rules about the API:
# The caller must free non-const array results.

const LL_DISCLAIMER =
    """
    NOTE: This function is part of the lowlevel libsoapysdr interface.
    For end-users in Julia, the higher-level Julia APIs are preferred
    """

const CHANNEL_ARGS =
    """
    `device` a pointer to a device instance
    `direction` the channel direction RX or TX
    `channel` the channel number to get info for
    """

# Forward declaration of device handle
mutable struct SoapySDRDevice
end

# Forward declaration of stream handle
mutable struct SoapySDRStream
end

struct SoapyDeviceError
    msg::String
end

macro check_return(expr)
    quote
        val = $(esc(expr))
        if val < 0
            throw(SoapySDRAPIError(val))
        end
        val
    end
end

# for API calls without integer status return codes
macro check_error(expr)
    quote
        val = $(esc(expr))
        if SoapySDRDevice_lastStatus() == -1
            throw(SoapyDeviceError(unsafe_string(SoapySDRDevice_lastError())))
        end
        val
    end
end

"""
    SoapySDRDevice_lastStatus()

Get the last status code after a Device API call.
The status code is cleared on entry to each Device call.
When an device API call throws, the C bindings catch
the exception, and set a non-zero last status code.
Use lastStatus() to determine success/failure for
Device calls without integer status return codes.

$LL_DISCLAIMER
"""
function SoapySDRDevice_lastStatus()
    ccall((:SoapySDRDevice_lastStatus, lib), Cint, ())
end

"""
Get the last error message after a device call fails.
When an device API call throws, the C bindings catch
the exception, store its message in thread-safe storage,
and return a non-zero status code to indicate failure.
Use lastError() to access the exception's error message.
"""
function SoapySDRDevice_lastError()
    ccall((:SoapySDRDevice_lastError, lib), Cstring, ())
end

"""
Enumerate a list of available devices on the system.
param args device construction key/value argument filters
param [out] length the number of elements in the result.
return a list of arguments strings, each unique to a device
"""
function SoapySDRDevice_enumerate()
    sz = Ref{Csize_t}()
    kwargs = @check_error ccall((:SoapySDRDevice_enumerate, lib), Ptr{SoapySDRKwargs}, (Ptr{Nothing}, Ref{Csize_t}), C_NULL, sz)
    return (kwargs, sz[])
end

"""
Enumerate a list of available devices on the system.
Markup format for args: "keyA=valA, keyB=valB".
param args a markup string of key/value argument filters
param [out] length the number of elements in the result.
return a list of arguments strings, each unique to a device
"""
function SoapySDRDevice_enumerateStrArgs(args)
    sz = Ref{Csize_t}()
    kwargs = ccall((:SoapySDRDevice_enumerateStrArgs, lib), Ptr{SoapySDRKwargs}, (Cstring, Ref{Csize_t}), args, sz)
    return (kwargs, sz[])
end

"""
    SoapySDRDevice_make(args)

Make a new Device object given device construction args.
The device pointer will be stored in a table so subsequent calls
with the same arguments will produce the same device.
For every call to make, there should be a matched call to unmake.
param args device construction key/value argument map
return a pointer to a new Device object.

$LL_DISCLAIMER
"""
function SoapySDRDevice_make(args)
    return @check_error ccall((:SoapySDRDevice_make, lib), Ptr{SoapySDRDevice}, (Ptr{SoapySDRKwargs},), args)
end

"""
Make a new Device object given device construction args.
The device pointer will be stored in a table so subsequent calls
with the same arguments will produce the same device.
For every call to make, there should be a matched call to unmake.

param args a markup string of key/value arguments
return a pointer to a new Device object or null for error
"""
function SoapySDRDevice_makeStrArgs(args) # have not checked
    ccall((:SoapySDRDevice_makeStrArgs, lib), Ptr{SoapySDRDevice}, (Cstring,), args)
end

# Unmake or release a device object handle.
# param device a pointer to a device object
# return 0 for success or error code on failure
function SoapySDRDevice_unmake(device) # have not checked
    ccall((:SoapySDRDevice_unmake, lib), Cint, (Ptr{SoapySDRDevice},), device)
end

######################
## PARALLEL SUPPORT ##      # have not checked any of these
######################

"""
Create a list of devices from a list of construction arguments.
This is a convenience call to parallelize device construction,
and is fundamentally a parallel for loop of make(Kwargs).
param argsList a list of device arguments per each device
param length the length of the argsList array
return a list of device pointers per each specified argument
"""
function SoapySDRDevice_make_list(argsList, length::Cint)
    ccall((:SoapySDRDevice_make_list, lib), Ptr{Ptr{SoapySDRDevice}}, (Ptr{Cint}, Cint), argsList, length)
end

"""
Unmake or release a list of device handles
and free the devices array memory as well.
This is a convenience call to parallelize device destruction,
and is fundamentally a parallel for loop of unmake(Device *).
param devices a list of pointers to device objects
param length the length of the devices array
return 0 for success or error code on failure
"""
function SoapySDRDevice_unmake_list(devices, length::Cint)
    ccall((:SoapySDRDevice_unmake_list, lib), Cint, (Ptr{Ptr{SoapySDRDevice}}, Cint), devices, length)
end

########################
## Identification API ##
########################

"""
A key that uniquely identifies the device driver.
This key identifies the underlying implementation.
Serveral variants of a product may share a driver.
param device a pointer to a device instance
"""
function SoapySDRDevice_getDriverKey(device)
    ccall((:SoapySDRDevice_getDriverKey, lib), Cstring, (Ptr{SoapySDRDevice},), device)
end

"""
A key that uniquely identifies the hardware.
This key should be meaningful to the user
to optimize for the underlying hardware.
param device a pointer to a device instance
"""
function SoapySDRDevice_getHardwareKey(device)
    ccall((:SoapySDRDevice_getHardwareKey, lib), Cstring, (Ptr{SoapySDRDevice},), device)
end

"""
Query a dictionary of available device information.
This dictionary can any number of values like
vendor name, product name, revisions, serials...
This information can be displayed to the user
to help identify the instantiated device.

param device a pointer to a device instance
"""
function SoapySDRDevice_getHardwareInfo(device)
    ccall((:SoapySDRDevice_getHardwareInfo, lib), SoapySDRKwargs, (Ptr{SoapySDRDevice},), device)
end

##################
## Channels API ##
##################

"""
Set the frontend mapping of available DSP units to RF frontends.
This mapping controls channel mapping and channel availability.

param device a pointer to a device instance
param direction the channel direction RX or TX
param mapping a vendor-specific mapping string
return an error code or 0 for success
"""
function SoapySDRDevice_setFrontendMapping(device, direction, mapping)
    #SOAPY_SDR_API int SoapySDRDevice_setFrontendMapping(SoapySDRDevice *device, const int direction, const char *mapping);
    ccall((:SoapySDRDevice_setFrontendMapping, lib), Cint, (Ptr{SoapySDRDevice}, Cint, Cstring), device, direction, mapping)
end

"""
Get the mapping configuration string.

param device a pointer to a device instance
param direction the channel direction RX or TX
return the vendor-specific mapping string
"""
function SoapySDRDevice_getFrontendMapping(device, direction)
    #SOAPY_SDR_API char *SoapySDRDevice_getFrontendMapping(const SoapySDRDevice *device, const int direction);
    ccall((:SoapySDRDevice_getFrontendMapping, lib), Cstring, (Ptr{SoapySDRDevice}, Cint), device, direction)
end

"""
Get a number of channels given the streaming direction

param device a pointer to a device instance
param direction the channel direction RX or TX
return the number of channels
"""
function SoapySDRDevice_getNumChannels(device, direction)
    ccall((:SoapySDRDevice_getNumChannels, lib), Csize_t, (Ptr{SoapySDRDevice}, Cint), device, direction)
end

"""
    SoapySDRDevice_getChannelInfo(device, direction, channel)

Get channel info given the streaming direction
$CHANNEL_ARGS

Returns channel information

$LL_DISCLAIMER
"""
function SoapySDRDevice_getChannelInfo(device, direction, channel);
    return @check_error ccall((:SoapySDRDevice_getChannelInfo, lib), SoapySDRKwargs, (Ptr{SoapySDRDevice}, Cint, Csize_t), device, direction, channel)
end

"""
Find out if the specified channel is full or half duplex.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
return true for full duplex, false for half duplex
"""
function SoapySDRDevice_getFullDuplex(device, direction, channel)
    #SOAPY_SDR_API bool SoapySDRDevice_getFullDuplex(const SoapySDRDevice *device, const int direction, const size_t channel);
    ccall((:SoapySDRDevice_getFullDuplex, lib), Cint, (Ptr{SoapySDRDevice}, Cint, Csize_t), device, direction, channel)
end

#################
## ANTENNA API ##
#################

"""
Get a list of available antennas to select on a given chain.

$CHANNEL_ARGS

returns a list of available antenna names

$LL_DISCLAIMER
"""
function SoapySDRDevice_listAntennas(device, direction, channel)
    num_antennas = Ref{Csize_t}()
    names = @check_error ccall((:SoapySDRDevice_listAntennas, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, num_antennas)
    return (names, num_antennas[])
end

##############
## GAIN API ##
##############

"""
List available amplification elements.
Elements should be in order RF to baseband.
param: device a pointer to a device instance
param: direction the channel direction RX or TX
param: channel an available channel
param: [out] length the number of gain names

return a list of gain string names
"""
function SoapySDRDevice_listGains(device, direction, channel)
    num_gains = Ref{Csize_t}()
    names = @check_error ccall((:SoapySDRDevice_listGains, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, num_gains)
    names, num_gains[]
end

function SoapySDRDevice_getGainElement(device, direction, channel, name)
    return @check_error ccall((:SoapySDRDevice_getGainElement, lib), Cdouble, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring),
        device, direction, channel, name)
end

"""
Set the value of a amplification element in a chain.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param name the name of an amplification element
param value the new amplification value in dB
return an error code or 0 for success
"""
function SoapySDRDevice_setGainElement(device, direction, channel, name, val)
    # note: the C API does not match the C++ API. c++ returns void here w/o error code
    @check_error ccall((:SoapySDRDevice_getGainElement, lib), Cvoid, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring, Cdouble),
        device, direction, channel, name, val)
    return nothing
end

#=
TODO

"""
Get the overall value of the gain elements in a chain.

$CHANNEL_ARGS

Returns the value of the gain in dB
"""
function SoapySDRDevice_getGain(device, direction, channel)
    return @check_error ccall((:SoapySDRDevice_getGain, lib), Cdouble, (Ptr{SoapySDRDevice}, Cint, Csize_t),
        device, direction, channel)
end
=#

"""
Get the overall range of possible gain values

$CHANNEL_ARGS

Returns the range of possible gain values for this channel in dB
"""
function SoapySDRDevice_getGainRange(device, direction, channel)
    range = @check_error ccall((:SoapySDRDevice_getGainRange, lib), SoapySDRRange, (Ptr{SoapySDRDevice}, Cint, Csize_t),
        device, direction, channel)
    return range
end

"""
    SoapySDRDevice_getGainElementRange(device, direction, channel, name)

    Get the range of possible gain values for a specific element.

$CHANNEL_ARGS
* `name` the name of an amplification element

Returns the range of possible gain values for the specified amplification element in dB

$LL_DISCLAIMER
"""
function SoapySDRDevice_getGainElementRange(device, direction, channel, name)
    range = @check_error ccall((:SoapySDRDevice_getGainElementRange, lib), SoapySDRRange, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring),
        device, direction, channel, name)
    return range
end

###################
## FREQUENCY API ##
###################

"""
Set the center frequency of the chain.
 - For RX, this specifies the down-conversion frequency.
 - For TX, this specifies the up-conversion frequency.
The default implementation of setFrequency() will tune the "RF"
component as close as possible to the requested center frequency.
Tuning inaccuracies will be compensated for with the "BB" component.
The args can be used to augment the tuning algorithm.
 - Use "OFFSET" to specify an "RF" tuning offset,
   usually with the intention of moving the LO out of the passband.
   The offset will be compensated for using the "BB" component.
 - Use the name of a component for the key and a frequency in Hz
   as the value (any format) to enforce a specific frequency.
   The other components will be tuned with compensation
   to achieve the specified overall frequency.
 - Use the name of a component for the key and the value "IGNORE"
   so that the tuning algorithm will avoid altering the component.
 - Vendor specific implementations can also use the same args to augment
   tuning in other ways such as specifying fractional vs integer N tuning.
param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param frequency the center frequency in Hz
param args optional tuner arguments
return an error code or 0 for success
"""
function SoapySDRDevice_setFrequency(device, direction, channel, frequency, kwargs)
    ccall((:SoapySDRDevice_setFrequency, lib), Int, (Ref{SoapySDRDevice}, Cint, Csize_t, Cdouble, Ptr{SoapySDRKwargs}), device, direction, channel, frequency, kwargs)
end

################
## STREAM API ##
################

"""
Query a list of the available stream formats.

$CHANNEL_ARGS

Returns a list of allowed format strings.

$LL_DISCLAIMER
"""
function SoapySDRDevice_getStreamFormats(device, direction, channel)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getStreamFormats, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    ptr, len[]
end

"""
Get the hardware's native stream format for this channel.
This is the format used by the underlying transport layer,
and the direct buffer access API calls (when available).

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param [out] fullScale the maximum possible value
return the native stream buffer format string
"""
function SoapySDRDevice_getNativeStreamFormat(device, direction, channel)
    #SOAPY_SDR_API char *SoapySDRDevice_getNativeStreamFormat(const SoapySDRDevice *device, const int direction, const size_t channel, double *fullScale);
    fullscale = Ref{Cdouble}()
    fmt = @check_error ccall((:SoapySDRDevice_getNativeStreamFormat, lib), Cstring, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Cdouble}), device, direction, channel, fullscale)
    return fmt, fullscale[]
end

"""
Query the argument info description for stream args.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param [out] length the number of argument infos
return a list of argument info structures
"""
function SoapySDRDevice_getStreamArgsInfo(device, direction, channel)
    len = Ref{Csize_t}()
    #SOAPY_SDR_API SoapySDRArgInfo *SoapySDRDevice_getStreamArgsInfo(const SoapySDRDevice *device, const int direction, const size_t channel, size_t *length);
    ptr = @check_error ccall((:SoapySDRDevice_getStreamArgsInfo, lib), Ptr{SoapySDRArgInfo}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    ptr, len[]
end

"""
Initialize a stream given a list of channels and stream arguments.
The implementation may change switches or power-up components.
All stream API calls should be usable with the new stream object
after setupStream() is complete, regardless of the activity state.

The API allows any number of simultaneous TX and RX streams, but many dual-channel
devices are limited to one stream in each direction, using either one or both channels.
This call will return an error if an unsupported combination is requested,
or if a requested channel in this direction is already in use by another stream.

When multiple channels are added to a stream, they are typically expected to have
the same sample rate. See SoapySDRDevice_setSampleRate().

 * `device` a pointer to a device instance
 * `direction` the channel direction (`SOAPY_SDR_RX` or `SOAPY_SDR_TX`)
 * `format` A string representing the desired buffer format in read/writeStream()

 The first character selects the number type:
   - "C" means complex
   - "F" means floating point
   - "S" means signed integer
   - "U" means unsigned integer

 The type character is followed by the number of bits per number (complex is 2x this size per sample)

  Example format strings:
   - "CF32" -  complex float32 (8 bytes per element)
   - "CS16" -  complex int16 (4 bytes per element)
   - "CS12" -  complex int12 (3 bytes per element)
   - "CS4" -  complex int4 (1 byte per element)
   - "S32" -  int32 (4 bytes per element)
   - "U8" -  uint8 (1 byte per element)

 * `channels` a list of channels or empty for automatic
 * `numChans` the number of elements in the channels array
 * `args` stream args or empty for defaults

Recommended keys to use in the args dictionary:
    - "WIRE" - format of the samples between device and host

Returns the opaque pointer to a stream handle.

# NOTE:
    The returned stream is not required to have internal locking, and may not be used
    concurrently from multiple threads.
"""
function SoapySDRDevice_setupStream(device, direction, format, channels, numChans, kwargs)
    return @check_error ccall((:SoapySDRDevice_setupStream, lib), Ptr{SoapySDRStream}, (Ptr{SoapySDRDevice}, Cint, Cstring, Ptr{Csize_t}, Csize_t, Ptr{SoapySDRKwargs}),
        device, direction, format, channels, numChans, kwargs)
end

"""
Activate a stream.
Call activate to prepare a stream before using read/write().
The implementation control switches or stimulate data flow.

The timeNs is only valid when the flags have SOAPY_SDR_HAS_TIME.
The numElems count can be used to request a finite burst size.
The SOAPY_SDR_END_BURST flag can signal end on the finite burst.
Not all implementations will support the full range of options.
In this case, the implementation returns SOAPY_SDR_NOT_SUPPORTED.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param flags optional flag indicators about the stream
param timeNs optional activation time in nanoseconds
param numElems optional element count for burst control
return 0 for success or error code on failure
"""
function SoapySDRDevice_activateStream(device, stream, flags, timeNs, numElems)
    @check_return ccall((:SoapySDRDevice_activateStream, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Cint, Clonglong, Csize_t), device, stream, flags, timeNs, numElems)
    return nothing
end

"""
Get the stream's maximum transmission unit (MTU) in number of elements.
The MTU specifies the maximum payload transfer in a stream operation.
This value can be used as a stream buffer allocation size that can
best optimize throughput given the underlying stream implementation.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
return the MTU in number of stream elements (never zero)
"""
function SoapySDRDevice_getStreamMTU(device, stream)
    mtu = ccall((:SoapySDRDevice_getStreamMTU, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}), device, stream)
    return mtu
end

"""
Read elements from a stream for reception.
This is a multi-channel call, and buffs should be an array of void *,
where each pointer will be filled with data from a different channel.

**Client code compatibility:**
The readStream() call should be well defined at all times,
including prior to activation and after deactivation.
When inactive, readStream() should implement the timeout
specified by the caller and return SOAPY_SDR_TIMEOUT.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param buffs an array of void* buffers num chans in size
param numElems the number of elements in each buffer
param [out] flags optional flag indicators about the result
param [out] timeNs the buffer's timestamp in nanoseconds
param timeoutUs the timeout in microseconds
return the number of elements read per buffer or error code
"""
function SoapySDRDevice_readStream(device, stream, buffs, numElems, timeoutUs)
    flags = Ref{Cint}()
    timeNs = Ref{Clonglong}()
    nelems = @check_return ccall((:SoapySDRDevice_readStream, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Ptr{Cvoid}, Csize_t, Ptr{Cint}, Ptr{Clonglong}, Clong),
        device, stream, buffs, numElems, flags, timeNs, timeoutUs)
    nelems, flags[], timeNs[]
end

"""
Write elements to a stream for transmission.
This is a multi-channel call, and buffs should be an array of void *,
where each pointer will be filled with data for a different channel.

**Client code compatibility:**
Client code relies on writeStream() for proper back-pressure.
The writeStream() implementation must enforce the timeout
such that the call blocks until space becomes available
or timeout expiration.

* `device` a pointer to a device instance
* `stream` the opaque pointer to a stream handle
* `buffs` an array of void* buffers num chans in size
* `numElems` the number of elements in each buffer
* `flags` optional input flags and output flags
* `timeNs` the buffer's timestamp in nanoseconds
* `timeoutUs` the timeout in microseconds

Returns the number of elements written per buffer, output flags
"""
function SoapySDRDevice_writeStream(device, stream, buffs, numElems, flags, timeNs, timeoutUs)
    flags = Ref{Cint}(flags)
    nelems = @check_return ccall((:SoapySDRDevice_writeStream, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Ptr{Cvoid}, Csize_t, Ptr{Cint}, Clonglong, Clong),
        device, stream, buffs, numElems, flags, timeNs, timeoutUs)
    nelems, flags[]
end

"""
Deactivate a stream.
Call deactivate when not using using read/write().
The implementation control switches or halt data flow.

The timeNs is only valid when the flags have SOAPY_SDR_HAS_TIME.
Not all implementations will support the full range of options.
In this case, the implementation returns SOAPY_SDR_NOT_SUPPORTED.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param flags optional flag indicators about the stream
param timeNs optional deactivation time in nanoseconds
return 0 for success or error code on failure
"""
function SoapySDRDevice_deactivateStream(device, stream, flags, timeNs)
    @check_return ccall((:SoapySDRDevice_deactivateStream, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Cint, Clonglong), device, stream, flags, timeNs)
end

"""
Close an open stream created by setupStream
param device a pointer to a device instance
param stream the opaque pointer to a stream handle
return 0 for success or error code on failure
"""
function SoapySDRDevice_closeStream(device, stream)
    @check_return ccall((:SoapySDRDevice_closeStream, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}), device, stream)
end

"""
Readback status information about a stream.
This call is typically used on a transmit stream
to report time errors, underflows, and burst completion.

**Client code compatibility:**
Client code may continually poll readStreamStatus() in a loop.
Implementations of readStreamStatus() should wait in the call
for a status change event or until the timeout expiration.
When stream status is not implemented on a particular stream,
readStreamStatus() should return SOAPY_SDR_NOT_SUPPORTED.
Client code may use this indication to disable a polling loop.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param chanMask to which channels this status applies
param flags optional input flags and output flags
param timeNs the buffer's timestamp in nanoseconds
param timeoutUs the timeout in microseconds
return 0 for success or error code like timeout
"""
function SoapySDRDevice_readStreamStatus(device, stream, channel_mask, flags, timeNs, timeoutUs)
    #SOAPY_SDR_API int SoapySDRDevice_readStreamStatus(SoapySDRDevice *device,
    #    SoapySDRStream *stream,
    #    size_t *chanMask,
    #    int *flags,
    #    long long *timeNs,
    #    const long timeoutUs);

    flags = Ref{Cint}(flags)

    # we really don't want to throw here since it is a check, so we return the "condition", really an "error code"
    # This sometime varies between implementation and so both the flag and "condition" should be checked in the
    # high level API, though support for this call seems to vary between implementations
    condition = ccall((:SoapySDRDevice_readStreamStatus, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Csize_t, Cint, Clonglong, Clong),
                                                                       device, stream, channel_mask, flags, timeNs, timeoutUs)
    condition, flags[]
end

############################
# Direct buffer access API #
############################

"""
How many direct access buffers can the stream provide?
This is the number of times the user can call acquire()
on a stream without making subsequent calls to release().
A return value of 0 means that direct access is not supported.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
return the number of direct access buffers or 0
"""
function SoapySDRDevice_getNumDirectAccessBuffers(device, stream)
    #SOAPY_SDR_API size_t SoapySDRDevice_getNumDirectAccessBuffers(SoapySDRDevice *device, SoapySDRStream *stream);
    ccall((:SoapySDRDevice_getNumDirectAccessBuffers, lib), Csize_t, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}), device, stream)
end

"""
Get the buffer addresses for a scatter/gather table entry.
When the underlying DMA implementation uses scatter/gather
then this call provides the user addresses for that table.

Example: The caller may query the DMA memory addresses once
after stream creation to pre-allocate a re-usable ring-buffer.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param handle an index value between 0 and num direct buffers - 1
param buffs an array of void* buffers num chans in size
return 0 for success or error code when not supported
"""
function SoapySDRDevice_getDirectAccessBufferAddrs(device, stream, handle, buffs)
    #SOAPY_SDR_API int SoapySDRDevice_getDirectAccessBufferAddrs(SoapySDRDevice *device, SoapySDRStream *stream, const size_t handle, void **buffs);
    ccall((:SoapySDRDevice_getDirectAccessBufferAddrs, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Csize_t, Ptr{Cvoid}), device, stream, handle, buffs)
end

"""
Acquire direct buffers from a receive stream.
This call is part of the direct buffer access API.

The buffs array will be filled with a stream pointer for each channel.
Each pointer can be read up to the number of return value elements.

The handle will be set by the implementation so that the caller
may later release access to the buffers with releaseReadBuffer().
Handle represents an index into the internal scatter/gather table
such that handle is between 0 and num direct buffers - 1.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param handle an index value used in the release() call
param buffs an array of void* buffers num chans in size
param flags optional flag indicators about the result
param timeNs the buffer's timestamp in nanoseconds
param timeoutUs the timeout in microseconds
return the number of elements read per buffer or error code
"""
function SoapySDRDevice_acquireReadBuffer(device, stream, buffs, timeoutUs=100000)
    #SOAPY_SDR_API int SoapySDRDevice_acquireReadBuffer(SoapySDRDevice *device,
    #    SoapySDRStream *stream,
    #    size_t *handle,
    #    const void **buffs,
    #    int *flags,
    #    long long *timeNs,
    #    const long timeoutUs);
    handle = Ref{Csize_t}()
    flags = Ref{Cint}(0)
    timeNs = Ref{Clonglong}(-1)
    bytes = @check_return ccall((:SoapySDRDevice_acquireReadBuffer, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Ref{Csize_t}, Ref{Ptr{Cvoid}}, Ref{Cint}, Ref{Clonglong}, Clong),
                                                                device, stream, handle, buffs, flags, timeNs, timeoutUs)
    bytes, handle[], flags[], timeNs[]
end

"""
Release an acquired buffer back to the receive stream.
This call is part of the direct buffer access API.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param handle the opaque handle from the acquire() call
"""
function SoapySDRDevice_releaseReadBuffer(device, stream, handle)
    #SOAPY_SDR_API void SoapySDRDevice_releaseReadBuffer(SoapySDRDevice *device,
    #    SoapySDRStream *stream,
    #    const size_t handle);
    ccall((:SoapySDRDevice_releaseReadBuffer, lib), Cvoid, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Csize_t), device, stream, handle)
end

"""
Acquire direct buffers from a transmit stream.
This call is part of the direct buffer access API.

The buffs array will be filled with a stream pointer for each channel.
Each pointer can be written up to the number of return value elements.

The handle will be set by the implementation so that the caller
may later release access to the buffers with releaseWriteBuffer().
Handle represents an index into the internal scatter/gather table
such that handle is between 0 and num direct buffers - 1.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param handle an index value used in the release() call
param buffs an array of void* buffers num chans in size
param timeoutUs the timeout in microseconds
return the number of available elements per buffer or error
"""
function SoapySDRDevice_acquireWriteBuffer(device, stream, buffs, timeoutUs=100000)
    #SOAPY_SDR_API int SoapySDRDevice_acquireWriteBuffer(SoapySDRDevice *device,
    #    SoapySDRStream *stream,
    #    size_t *handle,
    #    void **buffs,
    #    const long timeoutUs);
    handle = Ref{Csize_t}()
    bytes = @check_return ccall((:SoapySDRDevice_acquireWriteBuffer, lib), Cint, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Ref{Csize_t}, Ref{Ptr{Cvoid}}, Clong),
                                                    device, stream, handle, buffs, timeoutUs)
    return bytes, handle[]
end

"""
Release an acquired buffer back to the transmit stream.
This call is part of the direct buffer access API.

Stream meta-data is provided as part of the release call,
and not the acquire call so that the caller may acquire
buffers without committing to the contents of the meta-data,
which can be determined by the user as the buffers are filled.

param device a pointer to a device instance
param stream the opaque pointer to a stream handle
param handle the opaque handle from the acquire() call
param numElems the number of elements written to each buffer
param flags optional input flags and output flags
param timeNs the buffer's timestamp in nanoseconds
"""
function SoapySDRDevice_releaseWriteBuffer(device, stream, handle, numElems, flags=0, timeNs=0)
    #SOAPY_SDR_API void SoapySDRDevice_releaseWriteBuffer(SoapySDRDevice *device,
    #    SoapySDRStream *stream,
    #    const size_t handle,
    #    const size_t numElems,
    #    int *flags,
    #    const long long timeNs);
    ccall((:SoapySDRDevice_releaseWriteBuffer, lib), Cvoid, (Ptr{SoapySDRDevice}, Ptr{SoapySDRStream}, Csize_t, Csize_t, Ref{Cint}, Clonglong),
                                                device, stream, handle, numElems, flags, timeNs)
    flags[]
end

### Various channel queries
for (prop, T, may_be_missing, desc) in [
        (:DCOffsetMode, Bool, true, "automatic DC offset corrections mode"),
        (:IQBalanceMode, Bool, true, "automatic IQ balance corrections mode"),
        (:GainMode, Bool, true, "automatic gain control mode"),
        (:FrequencyCorrection, Cdouble, true, "frontend frequency correction"),
        (:Gain, Cdouble, false, "gain in dB"),
        (:Antenna, Cstring, false, "selected antenna"),
        (:Bandwidth, Cdouble, false, "bandwidth in Hz"),
        (:SampleRate, Cdouble, false, "sample rate in Hz"),
    ]

    has_sym = Symbol(string("SoapySDRDevice_has"), prop)
    get_sym = Symbol(string("SoapySDRDevice_get"), prop)
    set_sym = Symbol(string("SoapySDRDevice_set"), prop)

    if may_be_missing
        """
        Does the device suppport $desc

        $CHANNEL_ARGS

        $LL_DISCLAIMER
        """
        @eval function ($has_sym)(device, direction, channel)
            return ccall(($(quot(has_sym)), lib), Bool, (Ref{SoapySDRDevice}, Cint, Csize_t), device, direction, channel)
        end
    end

    """
    Get the $desc.

    $CHANNEL_ARGS

    Returns the $desc.

    $LL_DISCLAIMER
    """
    @eval function ($get_sym)(device, direction, channel)
        return ccall(($(quot(get_sym)), lib), $T, (Ref{SoapySDRDevice}, Cint, Csize_t), device, direction, channel)
    end

    """
    Set the $desc.

    $CHANNEL_ARGS
    * `value` set the $desc to this `value`

    $LL_DISCLAIMER
    """
    @eval function ($set_sym)(device, direction, channel, value)
        return ccall(($(quot(set_sym)), lib), Cint, (Ref{SoapySDRDevice}, Cint, Csize_t, $T), device, direction, channel, value)
    end
end

for (prop, desc) in [
    (:IQBalance, "frontend IQ balance correction"),
    (:DCOffset, "frontend DC offset correction")
]

    has_sym = Symbol(string("SoapySDRDevice_has"), prop)
    get_sym = Symbol(string("SoapySDRDevice_get"), prop)
    set_sym = Symbol(string("SoapySDRDevice_set"), prop)

    """
    Does the device suppport $desc?

    $CHANNEL_ARGS
    $LL_DISCLAIMER
    """
    @eval function ($has_sym)(device, direction, channel)
        return @check_error ccall(($(quot(has_sym)), lib), Bool, (Ref{SoapySDRDevice}, Cint, Csize_t),
            device, direction, channel)
    end

    """
    Get the $desc.

    $CHANNEL_ARGS
    $LL_DISCLAIMER
    """
    @eval function ($get_sym)(device, direction, channel)
        i = Ref{Cdouble}()
        q = Ref{Cdouble}()
        @check_error ccall(($(quot(get_sym)), lib), Cint, (Ref{SoapySDRDevice}, Cint, Csize_t, Ref{Cdouble}, Ref{Cdouble}),
            device, direction, channel, i, q)
        (i[], q[])
    end

    """
    Set the $desc.

    $CHANNEL_ARGS
    $LL_DISCLAIMER
    """
    @eval function ($set_sym)(device, direction, channel, i, q)
        @check_error ccall(($(quot(set_sym)), lib), Cint, (Ref{SoapySDRDevice}, Cint, Csize_t, Cdouble, Cdouble),
            device, direction, channel, i, q)
    end
end

function SoapySDRDevice_getBandwidthRange(device, direction, channel)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getBandwidthRange, lib), Ptr{SoapySDRRange}, (Ref{SoapySDRDevice}, Cint, Csize_t, Ptr{Csize_t}), device, direction, channel, len)
    (ptr, len[])
end

###################
## FREQUENCY API ##
###################

"""
Get the range of overall frequency values.

$CHANNEL_ARGS

Returns a list of frequency ranges in Hz

$LL_DISCLAIMER
"""
function SoapySDRDevice_getFrequencyRange(device, direction, channel)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getFrequencyRange, lib), Ptr{SoapySDRRange}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    (ptr, len[])
end

"""
Get the range of tunable values for the specified element.

$CHANNEL_ARGS

Returns a list of frequency ranges in Hz

$LL_DISCLAIMER
"""
function SoapySDRDevice_getFrequencyRangeComponent(device, direction, channel, name)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getFrequencyRangeComponent, lib), Ptr{SoapySDRRange}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring, Ref{Csize_t}), device, direction, channel, name, len)
    (ptr, len[])
end

"""
Get the range of possible baseband sample rates.

$CHANNEL_ARGS

Returns a list of samples rates in samples per second

$LL_DISCLAIMER
"""
function SoapySDRDevice_getSampleRateRange(device, direction, channel)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getSampleRateRange, lib), Ptr{SoapySDRRange}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    (ptr, len[])
end

"""
Get the list of possible baseband sample rates.

$CHANNEL_ARGS

Returns a list of samples rates in samples per second

$LL_DISCLAIMER
"""
function SoapySDRDevice_listSampleRates(device, direction, channel)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listSampleRates, lib), Ptr{Float64}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    (ptr, len[])
end

"""
List available tunable elements in the chain.
Elements should be in order RF to baseband.

$CHANNEL_ARGS

Returns a list of tunable elements by name

$LL_DISCLAIMER
*/
"""
function SoapySDRDevice_listFrequencies(device, direction, channel)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listFrequencies, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    ptr, len[]
end

function SoapySDRDevice_getFrequency(device, direction, channel)
    return @check_error ccall((:SoapySDRDevice_getFrequency, lib), Cdouble, (Ptr{SoapySDRDevice}, Cint, Csize_t),
        device, direction, channel)
end

function SoapySDRDevice_getFrequencyComponent(device, direction, channel, name)
    return @check_error ccall((:SoapySDRDevice_getFrequencyComponent, lib), Cdouble, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring),
        device, direction, channel, name)
end

function SoapySDRDevice_setFrequencyComponent(device, direction, channel, name, val)
    err = @check_error ccall((:SoapySDRDevice_setFrequencyComponent, lib), Cint, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring, Cdouble),
        device, direction, channel, name, val)
    @assert err == 0
    return nothing
end

##############
## TIME API ##
##############

"""
Get the list of available time sources.

param device a pointer to a device instance
param [out] length the number of sources
return a list of time source names
"""
function SoapySDRDevice_listTimeSources(device)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listTimeSources, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    (ptr, len[])
end

"""
Set the time source on the device

param device a pointer to a device instance
param source the name of a time source
return an error code or 0 for success
"""
function SoapySDRDevice_setTimeSource(device, source)
    ptr = @check_error ccall((:SoapySDRDevice_setTimeSource, lib), Cstring, (Ptr{SoapySDRDevice}, Cstring), device, source)
    ptr
end

"""
Get the time source of the device

param device a pointer to a device instance
return the name of a time source
"""
function SoapySDRDevice_getTimeSource(device)
    ptr = @check_error ccall((:SoapySDRDevice_getTimeSource, lib), Cstring, (Ptr{SoapySDRDevice},), device)
    ptr
end

"""
Does this device have a hardware clock?

param device a pointer to a device instance
param what optional argument
return true if the hardware clock exists
"""
function SoapySDRDevice_hasHardwareTime(device, what)
    @check_error ccall((:SoapySDRDevice_hasHardwareTime, lib), Bool, (Ptr{SoapySDRDevice}, Cstring), device, what)
end

"""
Read the time from the hardware clock on the device.
The what argument can refer to a specific time counter.

param device a pointer to a device instance
param what optional argument
return the time in nanoseconds
"""
function SoapySDRDevice_getHardwareTime(device, what)
    @check_error ccall((:SoapySDRDevice_getHardwareTime, lib), Clonglong, (Ptr{SoapySDRDevice}, Cstring), device, what)
end

"""
Write the time to the hardware clock on the device.
The what argument can refer to a specific time counter.

param device a pointer to a device instance
param timeNs time in nanoseconds
param what optional argument
return 0 for success or error code on failure
"""
function SoapySDRDevice_setHardwareTime(device, timeNs, what)
    @check_error ccall((:SoapySDRDevice_setHardwareTime, lib), Cvoid, (Ptr{SoapySDRDevice}, Clonglong, Cstring), device, timeNs, what)
end

##################
## Clocking API ##
##################
"""
Set the master clock rate of the device.

param device a pointer to a device instance
param rate the clock rate in Hz
return an error code or 0 for success
"""
function SoapySDRDevice_setMasterClockRate(device,rate);
    @check_error ccall((:SoapySDRDevice_setMasterClockRate, lib), Cvoid, (Ptr{SoapySDRDevice}, Cdouble), device, rate)
end

"""
Get the master clock rate of the device.

param device a pointer to a device instance
return the clock rate in Hz
"""
function SoapySDRDevice_getMasterClockRate(device)
    @check_error ccall((:SoapySDRDevice_getMasterClockRate, lib), Cdouble, (Ptr{SoapySDRDevice},), device)
end

"""
Get the range of available master clock rates.

param device a pointer to a device instance
param [out] length the number of ranges
return a list of clock rate ranges in Hz
"""
function SoapySDRDevice_getMasterClockRates(device)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getMasterClockRates, lib), Ptr{SoapySDRRange}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    (ptr, len[])
end

"""
Set the reference clock rate of the device.

param device a pointer to a device instance
param rate the clock rate in Hz
return an error code or 0 for success
"""
function SoapySDRDevice_setReferenceClockRate(device, rate)
    @check_error ccall((:SoapySDRDevice_setReferenceClockRate, lib), Cvoid, (Ptr{SoapySDRDevice}, Cdouble), device, rate)
end

"""
Get the reference clock rate of the device.

param device a pointer to a device instance
return the clock rate in Hz
"""
function SoapySDRDevice_getReferenceClockRate(device)
    @check_error ccall((:SoapySDRDevice_getReferenceClockRate, lib), Cdouble, (Ptr{SoapySDRDevice},), device)
end

"""
Get the range of available reference clock rates.

param device a pointer to a device instance

return a list of clock rate ranges in Hz
"""
function SoapySDRDevice_getReferenceClockRates(device)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getReferenceClockRates, lib), Ptr{SoapySDRRange}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    (ptr, len[])
end

"""
Get the list of available clock sources.

param device a pointer to a device instance

return a list of clock source names
"""
function SoapySDRDevice_listClockSources(device)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listClockSources, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    (ptr, len[])
end

"""
Set the clock source on the device

param device a pointer to a device instance
param source the name of a clock source
return an error code or 0 for success
"""
function SoapySDRDevice_setClockSource(device, source)
    @check_error ccall((:SoapySDRDevice_setClockSource, lib), Cstring, (Ptr{SoapySDRDevice}, Cstring), device, source)
end

"""
Get the clock source of the device

param device a pointer to a device instance
return the name of a clock source
"""
function SoapySDRDevice_getClockSource(device)
    ptr = @check_error ccall((:SoapySDRDevice_getClockSource, lib), Cstring, (Ptr{SoapySDRDevice},), device)
    ptr
end

################
## SENSOR API ##
################

"""
List the available global readback sensors.
A sensor can represent a reference lock, RSSI, temperature.

param device a pointer to a device instance
param [out] length the number of sensor names
return a list of available sensor string names
"""
function SoapySDRDevice_listSensors(device)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listSensors, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    ptr, len[]
end

"""
Get meta-information about a sensor.
Example: displayable name, type, range.

param device a pointer to a device instance
param key the ID name of an available sensor
return meta-information about a sensor
"""
function SoapySDRDevice_getSensorInfo(device, key)
    @check_error ccall((:SoapySDRDevice_getSensorInfo, lib), SoapySDRArgInfo, (Ptr{SoapySDRDevice}, Cstring), device, key)
end

"""
Readback a global sensor given the name.
The value returned is a string which can represent
a boolean ("true"/"false"), an integer, or float.

param device a pointer to a device instance
param key the ID name of an available sensor
return the current value of the sensor
"""
function SoapySDRDevice_readSensor(device, key)
    @check_error ccall((:SoapySDRDevice_readSensor, lib), Cstring, (Ptr{SoapySDRDevice}, Cstring), device, key)
end

"""
List the available channel readback sensors.
A sensor can represent a reference lock, RSSI, temperature.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device

return a list of available sensor string names
"""
function SoapySDRDevice_listChannelSensors(device, direction, channel)
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listSensors, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    (ptr, len[])
end

"""
Get meta-information about a channel sensor.
Example: displayable name, type, range.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param key the ID name of an available sensor
return meta-information about a sensor
"""
function SoapySDRDevice_getChannelSensorInfo(device, direction, channel, key)
    @check_error ccall((:SoapySDRDevice_getChannelSensorInfo, lib), SoapySDRArgInfo, (Ptr{SoapySDRArgInfo}, Cint, Csize_t, Cstring), device, direction, channel, key)
end

"""
Readback a channel sensor given the name.
The value returned is a string which can represent
a boolean ("true"/"false"), an integer, or float.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param key the ID name of an available sensor
return the current value of the sensor
"""
function SoapySDRDevice_readChannelSensor(device, direction, channel, key)
    @check_error ccall((:SoapySDRDevice_readChannelSensor, lib), Cstring, (Ptr{SoapySDRArgInfo}, Cint, Csize_t, Cstring), device, direction, channel, key)
end

#################
## SETTINGSAPI ##
#################

"""
Describe the allowed keys and values used for settings.

param device a pointer to a device instance
param [out] length the number of sensor names
return a list of argument info structures
"""
function SoapySDRDevice_getSettingInfo(device)
    #SOAPY_SDR_API SoapySDRArgInfo *SoapySDRDevice_getSettingInfo(const SoapySDRDevice *device, size_t *length);
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getSettingInfo, lib), Ptr{SoapySDRArgInfo}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    (ptr, len[])
end

"""
Write an arbitrary setting on the device.
The interpretation is up the implementation.

param device a pointer to a device instance
param key the setting identifier
param value the setting value
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeSetting(device, key, value)
    #SOAPY_SDR_API int SoapySDRDevice_writeSetting(SoapySDRDevice *device, const char *key, const char *value);
    @check_error ccall((:SoapySDRDevice_writeSetting, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Cstring), device, key, value)
end

"""
Read an arbitrary setting on the device.

param device a pointer to a device instance
param key the setting identifier
return the setting value
"""
function SoapySDRDevice_readSetting(device, key)
    #SOAPY_SDR_API char *SoapySDRDevice_readSetting(const SoapySDRDevice *device, const char *key);
    @check_error ccall((:SoapySDRDevice_readSetting, lib), Cstring, (Ptr{SoapySDRDevice}, Cstring), device, key)
end

"""
Describe the allowed keys and values used for channel settings.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param [out] length the number of sensor names
return a list of argument info structures
"""
function SoapySDRDevice_getChannelSettingInfo(device, direction, channel)
    #SOAPY_SDR_API SoapySDRArgInfo *SoapySDRDevice_getChannelSettingInfo(const SoapySDRDevice *device, const int direction, const size_t channel, size_t *length);
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_getChannelSettingInfo, lib), Ptr{SoapySDRArgInfo}, (Ptr{SoapySDRDevice}, Cint, Csize_t, Ref{Csize_t}), device, direction, channel, len)
    (ptr, len[])
end

"""
Write an arbitrary channel setting on the device.
The interpretation is up the implementation.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param key the setting identifier
param value the setting value
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeChannelSetting(device, direction, channel, key, value)
    #SOAPY_SDR_API int SoapySDRDevice_writeChannelSetting(SoapySDRDevice *device, const int direction, const size_t channel, const char *key, const char *value);
    @check_error ccall((:SoapySDRDevice_writeChannelSetting, lib), Cint, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring, Cstring), device, direction, channel, key, value)
end

"""
Read an arbitrary channel setting on the device.

param device a pointer to a device instance
param direction the channel direction RX or TX
param channel an available channel on the device
param key the setting identifier
return the setting value
"""
function SoapySDRDevice_readChannelSetting(device, direction, channel, key)
    #SOAPY_SDR_API char *SoapySDRDevice_readChannelSetting(const SoapySDRDevice *device, const int direction, const size_t channel, const char *key);
    @check_error ccall((:SoapySDRDevice_readChannelSetting, lib), Cstring, (Ptr{SoapySDRDevice}, Cint, Csize_t, Cstring), device, direction, channel, key)
end

##############
#Register API
##############

"""
Get a list of available register interfaces by name.

param device a pointer to a device instance
param [out] length the number of interfaces
return a list of available register interfaces
"""
function SoapySDRDevice_listRegisterInterfaces(device)
    #SOAPY_SDR_API char **SoapySDRDevice_listRegisterInterfaces(const SoapySDRDevice *device, size_t *length);
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listRegisterInterfaces, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    (ptr, len[])
end

"""
Write a register on the device given the interface name.
This can represent a register on a soft CPU, FPGA, IC;
the interpretation is up the implementation to decide.

param device a pointer to a device instance
param name the name of a available register interface
param addr the register address
param value the register value
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeRegister(device, name, addr, value)
    #SOAPY_SDR_API int SoapySDRDevice_writeRegister(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned value);
    @check_error ccall((:SoapySDRDevice_writeRegister, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Csize_t, Csize_t), device, name, addr, value)
end

"""
Read a register on the device given the interface name.

param device a pointer to a device instance
param name the name of a available register interface
param addr the register address
return the register value
"""
function SoapySDRDevice_readRegister(device, name, addr)
    #SOAPY_SDR_API unsigned SoapySDRDevice_readRegister(const SoapySDRDevice *device, const char *name, const unsigned addr);
    @check_error ccall((:SoapySDRDevice_readRegister, lib), Csize_t, (Ptr{SoapySDRDevice}, Cstring, Csize_t), device, name, addr)
end

"""
Write a memory block on the device given the interface name.
This can represent a memory block on a soft CPU, FPGA, IC;
the interpretation is up the implementation to decide.

param device a pointer to a device instance
param name the name of a available memory block interface
param addr the memory block start address
param value the memory block content
param length the number of words in the block
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeMemory(device, name, addr, value, length)
    #SOAPY_SDR_API int SoapySDRDevice_writeRegisters(SoapySDRDevice *device, const char *name, const unsigned addr, const unsigned *value, const size_t length);
    @check_error ccall((:SoapySDRDevice_writeMemory, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Csize_t, Csize_t, Ptr{Csize_t}), device, name, addr, value, length)
end

"""
Read a memory block on the device given the interface name.
Pass the number of words to be read in via length;
length will be set to the number of actual words read.

param device a pointer to a device instance
param name the name of a available memory block interface
param addr the memory block start address
param [in,out] length number of words to be read from memory block
return the memory block content
"""
function SoapySDRDevice_readRegisters(device, name, addr, length)
    #SOAPY_SDR_API unsigned *SoapySDRDevice_readRegisters(const SoapySDRDevice *device, const char *name, const unsigned addr, size_t *length);
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_readRegisters, lib), Ptr{Csize_t}, (Ptr{SoapySDRDevice}, Cstring, Csize_t, Ref{Csize_t}), device, name, addr, len)
    (ptr, len[])
end

##############
# GPIO API
##############

"""
Get a list of available GPIO banks by name.

param [out] length the number of GPIO banks
param device a pointer to a device instance
"""
function SoapySDRDevice_listGPIBanks(device)
    #SOAPY_SDR_API char **SoapySDRDevice_listGPIOBanks(const SoapySDRDevice *device, size_t *length);
    len = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listGPIBanks, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, len)
    (ptr, len[])
end

"""
Write the value of a GPIO bank.

param device a pointer to a device instance
param bank the name of an available bank
param value an integer representing GPIO bits
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeGPIO(device, bank, value)
    #SOAPY_SDR_API int SoapySDRDevice_writeGPIO(SoapySDRDevice *device, const char *bank, const unsigned value);
    @check_error ccall((:SoapySDRDevice_writeGPIO, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Csize_t), device, bank, value)
end

"""
Write the value of a GPIO bank with modification mask.

param device a pointer to a device instance
param bank the name of an available bank
param value an integer representing GPIO bits
param mask a modification mask where 1 = modify
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeGPIOMasked(device, bank, value, mask)
    #SOAPY_SDR_API int SoapySDRDevice_writeGPIOMasked(SoapySDRDevice *device, const char *bank, const unsigned value, const unsigned mask);
    @check_error ccall((:SoapySDRDevice_writeGPIOMasked, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Csize_t, Csize_t), device, bank, value, mask)
end

"""
Readback the value of a GPIO bank.

param device a pointer to a device instance
param bank the name of an available bank
return an integer representing GPIO bits
"""
function SoapySDRDevice_readGPIO(device, bank)
    #SOAPY_SDR_API unsigned SoapySDRDevice_readGPIO(const SoapySDRDevice *device, const char *bank);
    @check_error ccall((:SoapySDRDevice_readGPIO, lib), Csize_t, (Ptr{SoapySDRDevice}, Cstring), device, bank)
end

"""
Write the data direction of a GPIO bank.
1 bits represent outputs, 0 bits represent inputs.

param device a pointer to a device instance
param bank the name of an available bank
param dir an integer representing data direction bits
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeGPIODir(device, bank, dir)
    #SOAPY_SDR_API int SoapySDRDevice_writeGPIODir(SoapySDRDevice *device, const char *bank, const unsigned dir);
    @check_error ccall((:SoapySDRDevice_writeGPIODir, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Csize_t), device, bank, dir)
end

"""
Write the data direction of a GPIO bank with modification mask.
1 bits represent outputs, 0 bits represent inputs.

param device a pointer to a device instance
param bank the name of an available bank
param dir an integer representing data direction bits
param mask a modification mask where 1 = modify
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeGPIODirMasked(device, bank, dir, mask)
    #SOAPY_SDR_API int SoapySDRDevice_writeGPIODirMasked(SoapySDRDevice *device, const char *bank, const unsigned dir, const unsigned mask);
    @check_error ccall((:SoapySDRDevice_writeGPIODirMasked, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Csize_t, Csize_t), device, bank, dir, mask)
end

"""
Read the data direction of a GPIO bank.

param device a pointer to a device instance
1 bits represent outputs, 0 bits represent inputs.
param bank the name of an available bank
return an integer representing data direction bits
"""
function SoapySDRDevice_readGPIODir(device, bank)
    #SOAPY_SDR_API unsigned SoapySDRDevice_readGPIODir(const SoapySDRDevice *device, const char *bank);
    @check_error ccall((:SoapySDRDevice_readGPIODir, lib), Csize_t, (Ptr{SoapySDRDevice}, Cstring), device, bank)
end

##############
# I2C API
##############

"""
Write to an available I2C slave.
If the device contains multiple I2C masters,
the address bits can encode which master.
param device a pointer to a device instance
param addr the address of the slave
param data an array of bytes write out
param numBytes the number of bytes to write
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeI2C(device, addr, data, numBytes)
    #SOAPY_SDR_API int SoapySDRDevice_writeI2C(SoapySDRDevice *device, const int addr, const char *data, const size_t numBytes);
    @check_error ccall((:SoapySDRDevice_writeI2C, lib), Cint, (Ptr{SoapySDRDevice}, Csize_t, Cstring, Csize_t), device, addr, data, numBytes)
end

"""
Read from an available I2C slave.
If the device contains multiple I2C masters,
the address bits can encode which master.
Pass the number of bytes to be read in via numBytes;
numBytes will be set to the number of actual bytes read.

param device a pointer to a device instance
param addr the address of the slave
param [in,out] numBytes the number of bytes to read
return an array of bytes read from the slave
"""
function SoapySDRDevice_readI2C(device, addr, numBytes)
    #SOAPY_SDR_API char *SoapySDRDevice_readI2C(SoapySDRDevice *device, const int addr, size_t *numBytes);
    ptr = @check_error ccall((:SoapySDRDevice_readI2C, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Csize_t, Ref{Csize_t}), device, addr, numBytes)
    (ptr, numBytes)
end

##############
# SPI API
##############

"""
Perform a SPI transaction and return the result.
Its up to the implementation to set the clock rate,
and read edge, and the write edge of the SPI core.
SPI slaves without a readback pin will return 0.

If the device contains multiple SPI masters,
the address bits can encode which master.

param device a pointer to a device instance
param addr an address of an available SPI slave
param data the SPI data, numBits-1 is first out
param numBits the number of bits to clock out
return the readback data, numBits-1 is first in
"""
function SoapySDRDevice_transactSPI(device, addr, data, numBits)
    #SOAPY_SDR_API unsigned SoapySDRDevice_transactSPI(SoapySDRDevice *device, const int addr, const unsigned data, const size_t numBits);
    @check_error ccall((:SoapySDRDevice_transactSPI, lib), Csize_t, (Ptr{SoapySDRDevice}, Csize_t, Csize_t, Csize_t), device, addr, data, numBits)
end

##############
# UART API
##############

"""
Enumerate the available UART devices.

param device a pointer to a device instance
param [out] length the number of UART names
return a list of names of available UARTs
"""
function SoapySDRDevice_listUARTs(device)
    #SOAPY_SDR_API char **SoapySDRDevice_listUARTs(const SoapySDRDevice *device, size_t *length);
    length = Ref{Csize_t}()
    ptr = @check_error ccall((:SoapySDRDevice_listUARTs, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Ref{Csize_t}), device, length)
    (ptr, length[])
end

"""
Write data to a UART device.
Its up to the implementation to set the baud rate,
carriage return settings, flushing on newline.

param device a pointer to a device instance
param which the name of an available UART
param data a null terminated array of bytes
return 0 for success or error code on failure
"""
function SoapySDRDevice_writeUART(device, which, data)
    #SOAPY_SDR_API int SoapySDRDevice_writeUART(SoapySDRDevice *device, const char *which, const char *data);
    @check_error ccall((:SoapySDRDevice_writeUART, lib), Cint, (Ptr{SoapySDRDevice}, Cstring, Cstring), device, which, data)
end

"""
Read bytes from a UART until timeout or newline.
Its up to the implementation to set the baud rate,
carriage return settings, flushing on newline.

param device a pointer to a device instance
param which the name of an available UART
param timeoutUs a timeout in microseconds
return a null terminated array of bytes
"""
function SoapySDRDevice_readUART(device, which, timeoutUs)
    #SOAPY_SDR_API char *SoapySDRDevice_readUART(const SoapySDRDevice *device, const char *which, const long timeoutUs);
    @check_error ccall((:SoapySDRDevice_readUART, lib), Ptr{Cstring}, (Ptr{SoapySDRDevice}, Cstring, Csize_t), device, which, timeoutUs)
end

#####################
# Native Access API
#####################

"""
A handle to the native device used by the driver.
The implementation may return a null value if it does not support
or does not wish to provide access to the native handle.

param: device a pointer to a device instance
return: a handle to the native device or null
"""
function SoapySDRDevice_getNativeDeviceHandle(device)
    #SOAPY_SDR_API void* SoapySDRDevice_getNativeDeviceHandle(const SoapySDRDevice *device);
    @check_error ccall((:SoapySDRDevice_getNativeDeviceHandle, lib), Ptr{Cvoid}, (Ptr{SoapySDRDevice}, ), device)
end


text:
"""
Test script for dirBin0Rec0 model: one parameter for total number of links and one for reciprocity
"""

import StaticNets: ErgmDirBin0Rec0(), ergm_par_from_mean_vals,diadProbFromPars , samplSingMatCan, stats_from_mat, get_one_mple, estimate,ErgmDirBin0Rec0, exp_val_stats
using ErgmRcall
using PyPlot
using RCall
using Statistics

using Utilities

ErgmRcall.clean_start_RCall()
ergmTermsString = "edges +  mutual"
R"""options(warn=-1) """
model = ErgmDirBin0Rec0()

##-------------------- Test and COmpare MLE and MPLE estimates
#Compare for a single value of the parameters
N=100
Ldgp = n_pox_dir_links(N)/4
Rdgp = n_pox_pairs(N)/4-100

θ_0, η_0 = Tuple(estimate(model, Ldgp, Rdgp, N))

nSample = 100
diadProb = diadProbFromPars(model, [θ_0, η_0])
A_vec = [samplSingMatCan(model, diadProb, N) for i=1:nSample]
statsVec = reduce(hcat,[stats_from_mat(model, A) for A in A_vec])
pygui(true)

fig, ax = subplots(2,1)
ax[1].hist(statsVec[1,:], 30)
ax[1].vlines(Ldgp, 0, 1, "k")
ax[2].hist(statsVec[2,:], 30)
ax[2].vlines(Rdgp, 0, 1, "k")

parMpleSingle = reduce(hcat, [get_one_mple(A,ergmTermsString) for A in A_vec])
parMleSingle = reduce(hcat,[estimate(model, A) for A in A_vec])
fix, ax = subplots(2,1)
ax[1].hist(parMleSingle[2,isfinite.(parMleSingle[2,:])], density=true, color="b" )
ax[1].hist(parMleSingle[1,isfinite.(parMleSingle[1,:])], density=true, color="b" )
ax[1].vlines(θ_0, 0, 1, "k")
ax[1].vlines(η_0, 0, 1, "k")
ax[1].set_title("mle")
ax[2].hist(parMpleSingle[2,isfinite.(parMpleSingle[2,:])], density=true, color="r" )
ax[2].hist(parMpleSingle[1,isfinite.(parMpleSingle[1,:])], density=true, color="r" )
ax[2].vlines(θ_0, 0, 1, "k")
ax[2].vlines(η_0, 0, 1, "k")
ax[2].set_title("mple")

function mle_pmle_comparison_var_Net_size(model::ErgmDirBin0Rec0, netSizes, linkFun, recFun; nSample=30)
    # compare the two estimators over different  par values for the dgp
    nPars = length(netSizes)
    parMmle = zeros(nPars, 2, nSample)
    parMple = zeros(nPars, 2, nSample)
    parDgp = zeros(nPars, 2)
    model = ErgmDirBin0Rec0()
    for i=1:nPars
        N = netSizes[i]
        θ_0, η_0 = ergm_par_from_mean_vals(model, linkFun(N), recFun(N), N)
        parDgp[i,:] = [θ_0, η_0]
        diadProb = diadProbFromPars(model, [θ_0, η_0])
        A_vec = [samplSingMatCan(model, diadProb, N) for i=1:nSample]
        parMmle[i,:,:] = reduce(hcat,[estimate(model, A) for A in A_vec])
        parMple[i,:,:] = reduce(hcat, [get_one_mple(A,ergmTermsString) for A in A_vec])
    end
    return parDgp, parMmle, parMple
end

# Compare for multiple values of the parameters
netSizes = collect(15:5:40)

parDgp, parMle, parMple = mle_pmle_comparison_var_Net_size(model, netSizes, x->x, x->x/5 )

[parMle[i, :, :] ]

i=1
bias_mle = reduce(hcat, [mean(parDgp[i] .- parMle[i,:,:], dims=2 ) for i=1:length(parMle[:,1,1])] )
bias_mple = reduce(hcat, [mean(parDgp[i] .- parMple[i,:,:], dims=2 ) for i=1:length(parMle[:,1,1])] )
rmse_mle = reduce(hcat, [sqrt.(mean((parDgp[i] .- parMle[i,:,:]).^2, dims=2 )) for i=1:length(parMle[:,1,1])] )
rmse_mple = reduce(hcat, [sqrt.(mean((parDgp[i] .- parMple[i,:,:]).^2, dims=2) ) for i=1:length(parMle[:,1,1])] )

xplot = parDgp[2,:]
fix, ax = subplots(2,2)
ax[1].plot(xplot, bias_mle', "--")
ax[1].set_title("bias mle")
ax[2].plot(xplot, rmse_mle',"-")
ax[2].set_title("rmse mle")
ax[3].plot(xplot, bias_mple', "--")
ax[3].set_title("bias mple")
ax[4].plot(xplot, rmse_mple',"-")
ax[4].set_title("rmse mple")

plot(parMle[2,:], parMple[2,:], ".")
plot(parMle[1,:], parMple[1,:], ".")

##----------------------------- Explore logLikelihoods around the estimates

function pseudo_loglikelihood_ddg(Model::ErgmDirBin0Rec0, A, par)
    θ, η = par
    L, R, N = stats_from_mat(Model, A)

    return L * θ + R*η - sum(log.(1 .+ exp.(2θ .+ (η).*A )) )
end

θ_0 = 1
η_0 = -0.5
par_dgp = [θ_0, η_0]
N = 200
fig, ax = subplots(2,1)
for i=1:3
    A = samplSingMatCan(model, diadProbFromPars(model, [θ_0, η_0]), N)
    mle = estimate(model, A)
    mple = get_one_mple(A,ergmTermsString)
    println(mle.-mple)

    changeStat, response, weights = decomposeMPLEmatrix(get_change_stats(A,ergmTermsString))

    ## Are the two functions similar around the estimates?
    x_vals = LinRange(-0.5,0.5,500)
    par_vec_1 =  [mle .+ [0, x] for x in x_vals]
    par_vec_2 =  [mle .+ [x, 0] for x in x_vals]

    cost_diff_si = (logLikelihood(model, A, mle) - pseudo_loglikelihood_strauss_ikeda(mle, changeStat, response, weights)) ./N^2
    cost_diff_ddg = (logLikelihood(model, A, mle) - pseudo_loglikelihood_ddg(model, A, mle))./N^2

    suptitle("exact vs pseudo log'likelihoods, /constant")
    ax[1].plot(x_vals,[logLikelihood(model, A, par) for par in par_vec_1]./N^2, "-b")
    ax[1].plot(x_vals, -cost_diff_si .+[pseudo_loglikelihood_strauss_ikeda(par, changeStat, response, weights) for par in par_vec_1]./N^2, "--r")
    #ax[1].legend(["log likelihood", "pesudo log likelihood"])
    ax[1].grid()
    ax[2].plot(x_vals,[logLikelihood(model, A, par) for par in par_vec_2]./N^2, "-b")
    ax[2].plot(x_vals,cost_diff_si .+[pseudo_loglikelihood_strauss_ikeda(par, changeStat, response, weights) for par in par_vec_2]./N^2, "--r")
    ax[2].grid()
end

function grad(Model::ErgmDirBin0Rec0, A, par)
    θ, η = par
    L, R, N = stats_from_mat(Model, A)
    z = 1 + 2*exp(θ) + exp(2*θ+η)
    g_θ =  L - (N*(N-1)/2) *(2*exp(θ)+ 2* exp(2*θ+η))/z
    g_η =  R - (N*(N-1)/2) *( exp(2*θ+η))/z
    return [g_θ, g_η]
end

logl(x) = logLikelihood(model, A, x)
pseudologl(x) = pseudo_loglikelihood_strauss_ikeda(x, changeStat, response, weights)

using ForwardDiff
g_logl(x) = ForwardDiff.gradient(logl,x)
g_pseudologl(x) = ForwardDiff.gradient(pseudologl,x)
h_logl(x) = ForwardDiff.hessian(logl,x)
h_pseudologl(x) = ForwardDiff.hessian(pseudologl,x)
# compare gradients
fig, ax = subplots(2,1)
suptitle("exact vs pseudo gradients along theta")
ax[1].plot(x_vals,[g_logl(par) for par in par_vec_1])
ax[1].plot(x_vals,[g_pseudologl(par) for par in par_vec_1])
ax[1].legend(["log likelihood", "pesudo log likelihood"])
ax[1].grid()
ax[2].plot(x_vals,[g_logl(par) for par in par_vec_2])
ax[2].plot(x_vals,[g_pseudologl(par) for par in par_vec_2])
ax[2].grid()
# compare hessians
fig, ax = subplots(2,2)
suptitle("exact vs pseudo hessians along theta move")
h_logl_vec = [h_logl(par) for par in par_vec_1]
h_pseudologl_vec = [h_pseudologl(par) for par in par_vec_1]
ax[1].plot(x_vals,[h[1,1] for h in h_logl_vec])
ax[1].plot(x_vals,[h[1,1] for h in h_pseudologl_vec])
ax[2].plot(x_vals,[h[2,1] for h in h_logl_vec])
ax[2].plot(x_vals,[h[2,1] for h in h_pseudologl_vec])
ax[4].plot(x_vals,[h[2,2] for h in h_logl_vec])
ax[4].plot(x_vals,[h[2,2] for h in h_pseudologl_vec])
ax[1].legend(["log likelihood", "pesudo log likelihood"])
ax[1].grid()
ax[2].grid()
ax[3].grid()
ax[4].grid()

fig, ax = subplots(2,2)
suptitle("exact vs pseudo hessians along eta move")
h_logl_vec = [h_logl(par) for par in par_vec_2]
h_pseudologl_vec = [h_pseudologl(par) for par in par_vec_2]
ax[1].plot(x_vals,[h[1,1] for h in h_logl_vec])
ax[1].plot(x_vals,[h[1,1] for h in h_pseudologl_vec])
ax[2].plot(x_vals,[h[2,1] for h in h_logl_vec])
ax[2].plot(x_vals,[h[2,1] for h in h_pseudologl_vec])
ax[4].plot(x_vals,[h[2,2] for h in h_logl_vec])
ax[4].plot(x_vals,[h[2,2] for h in h_pseudologl_vec])
ax[1].legend(["log likelihood", "pesudo log likelihood"])
ax[1].grid()
ax[2].grid()
ax[3].grid()
ax[4].grid()

# Closed form gradient vs AD gradient
fig, ax = subplots(2,1)
ax[1].plot(x_vals,[g_logl(par)[1] for par in par_vec_1])
ax[1].plot(x_vals,[grad(model, A,par)[1] for par in par_vec_1])
ax[2].plot(x_vals,[g_logl(par)[2] for par in par_vec_1])
ax[2].plot(x_vals,[grad(model, A,par)[2] for par in par_vec_1])

#

max_stars_repo_name: domenicodigangi/SDERGM

max_issues_repo_name: domenicodigangi/SDERGM

max_forks_repo_name: domenicodigangi/SDERGM


text:
# Define shorthand functions depending on the returns to scale
DEA_CRS(X,Y,input) = DEA{CRS}(X,Y,input)
DEA_VRS(X,Y,input) = DEA{VRS}(X,Y,input)
DEA_NIRS(X,Y,input) = DEA{NIRS}(X,Y,input)
DEA_NDRS(X,Y,input) = DEA{NDRS}(X,Y,input)

# DEA is a special case of the DDF where gx or gy is zero depending on the orientation
immutable DEA{T<:RS} <: AbstractDEA{Convex,T}
  D::DDF
  input::Bool

  function DEA{T}(X::Array,Y::Array,input::Bool) where T<:RS
    input ? new(DDF{Convex,T}(X,Y,X,zeros(size(Y))),input) : new(DDF{Convex,T}(X,Y,zeros(size(X)),Y),input)
  end
end

function getdata(DMU::DEA)
	return getdata(DMU.D)
end

function (DMU::DEA)(Xk::Array,Yk::Array)
  if DMU.input
    res = DMU.D(Xk,Yk,Xk,zeros(size(Yk)))
    res.eff = 1 - res.eff
  else
    res = DMU.D(Xk,Yk,zeros(size(Xk)),Yk)
    res.eff = 1 + res.eff
  end
  res.sx = []
  res.sy = []
  return res
end

function (DMU::DEA)()
  res = DMU.D()
  for k in eachindex(res)
    if DMU.input
      res[k].eff = 1 - res[k].eff
    else
      res[k].eff = 1 + res[k].eff
    end
    res[k].sx = []
    res[k].sy = []
  end
  return res
end

max_stars_repo_name: kepiej/NEPA


text:
# This file was generated, do not modify it. # hide
using Gnuplot, Random
Random.seed!(145)
x, y = 1:2:20, 5*rand(10)
xerr = abs.(randn(10))
lcval = 1:10
@gp x y xerr "w xerr t 'test' lc 'black'" xrange= (0,22) yrange = (0,6)
save(term="pngcairo size 600,400", output="./code/plt_errs17.png") # hide

max_stars_repo_name: lazarusA/gnuplot-examples

max_issues_repo_name: lazarusA/gnuplot-examples

max_forks_repo_name: lazarusA/gnuplot-examples


text:
@testset "mmd" begin
    T = Float32
    k = GaussianKernel(1f0)
    x = rand(T, 5, 2) |> gpu
    y = rand(T, 5, 2) |> gpu
    m = mmd(k, x, y)
    @test typeof(m) == T

    gs = Flux.gradient(mmd, k, x, y)

    T = Float64
    k = GaussianKernel(1)
    x = rand(T, 5, 2)
    y = rand(T, 5, 2)
    m = mmd(k, x, y)
    @test typeof(m) == T
end

@testset "mmd2 and variance" begin
    o = ones(Float64, 3, 3)
    z = zeros(Float64, 3, 3)
    @test mmd2_and_variance(o, o, o) == (0, 0)
    @test mmd2_and_variance(z, z, z) == (0, 0)
    @test mmd2_and_variance(o, z, z) == (1, 0)
    @test mmd2_and_variance(z, z, o) == (1, 0)
    @test mmd2_and_variance(o, o, z) == (-1, 0)
    @test mmd2_and_variance(o, z, z) == (1, 0)
    @test mmd2_and_variance(z, o, z) == (-2, 0)

    a = [1 2 3; 4 5 6; 7 8 9]
    b = (a .+ 1)'
    c = (a .+ 2)'
    a = a'
    m, v = mmd2_and_variance(a, b, c)
    @test m ≈ 0
    @test v ≈ -3.1111111

    a = [1 1 1; 1 1 1; 0 1 0]'
    b = [1 1 1; 1 0 1; 0 1 0]'
    c = [0 1 1; 1 0 1; 0 1 0]'
    m, v = mmd2_and_variance(a, b, c)
    @test m ≈ 0.33333333
    @test v ≈ -0.0185185185185

    a = [0.31067363 0.17995522 0.69170826
        0.10956897 0.43168305 0.13072019
        0.98321756 0.66711701 0.4277054]'

    b = [0.6308643 0.72541977 0.26667574
        0.24141601 0.56088218 0.2872887
        0.12801543 0.43956629 0.0703913]'

    c = [0.68779085 0.68050291 0.47736484
        0.49306397 0.07206057 0.10580517
        0.99297355 0.90194579 0.32241892]'

    m, v = mmd2_and_variance(a, b, c)
    @test m ≈ 0.32443064
    @test v ≈ 0.33610499
end


text:
export classic_sta_lta, classic_sta_lta!, delayed_sta_lta, delayed_sta_lta!
export recursive_sta_lta, recursive_sta_lta!, carl_sta_trig, carl_sta_trig!
export z_detect, z_detect!, trigger_onset

@doc """
  classic_sta_lta!(S, sta, lta)

Computes classic STA/LTA.

The length of the STA and LTA are given by `sta` and `lta` in seconds, respectively.

!!! note

    The in-place version (classic_sta_lta!) overwrites the seismic trace with the STA/LTA
    characteristic function.

# Arguments
- `S::GphysData`: GphysData (SeisData, SeisChannel, SeisIO.Nodal.NodalChannel, SeisIO.Quake.EventChannel).
- `sta:Int`: Length of short time average window in seconds
- `lta:Int`: Length of long time average window in seconds
""" classic_sta_lta!
function classic_sta_lta!(S::GphysData, sta::Real, lta::Real)
    for ii in 1:S.n
        classic_sta_lta!(S[ii], sta, lta)
    end
    return nothing
end
function classic_sta_lta!(C::GphysChannel, sta::Real, lta::Real)
    nsta = round(Int64, C.fs * sta)
    nlta = round(Int64, C.fs * lta)
    C.x .= classic_sta_lta(C.x, nsta, nlta)
    return nothing
end

@doc classic_sta_lta!
function classic_sta_lta(S::GphysData, sta::Real, lta::Real)
    U = deepcopy(S)
    classic_sta_lta!(U, sta, lta)
    return U
end
function classic_sta_lta(C::GphysChannel, sta::Real, lta::Real)
    U = deepcopy(C)
    classic_sta_lta!(U, sta, lta)
    return U
end
function classic_sta_lta(A::AbstractArray, nsta::Real, nlta::Real)
    nsta > nlta ? throw(DomainError((nsta, nlta), "Short-term average must be less than long-term average")) : nothing
    nsta < 0 ? throw(DomainError(nsta, "Short-term average must be less greater than zero")) : nothing
    nlta < 0 ? throw(DomainError(nlta, "Long-term average must be greater than zero")) : nothing
    N = size(A,1)
    T = eltype(A)
    nsta > N ? throw(DomainError(nsta, "Short-term average must be less than length of time series")) : nothing
    nlta > N ? throw(DomainError(nlta, "Long-term average must be less than length of time series")) : nothing

    # cumulative sum can be exploited to calculate a moving average
    sta = cumsum(A .^ 2)
    lta = deepcopy(sta)

    # compute the STA and LTA
    sta[nsta + 1:end] = sta[nsta + 1:end] .- sta[1:end-nsta]
    sta ./= nsta
    lta[nlta + 1:end] = lta[nlta + 1:end] .- lta[1:end-nlta]
    lta ./= nlta

    # pad zeros
    sta[1:nlta] .= 0.0

    # avoid division by zero by setting zero values to tiny float
    tinyfloat = eps(T)
    ind = findall(lta .< tinyfloat)
    lta[ind] .= tinyfloat
    return sta ./ lta
end

@doc """
  delayed_sta_lta!(S, sta, lta)

Delayed STA/LTA from Withers, 1998.

!!! note

    The in-place version (delayed_sta_lta!) overwrites the seismic trace with the STA/LTA
    characteristic function.

# Arguments
- `S::GphysData`: GphysData (SeisData, SeisChannel, SeisIO.Nodal.NodalChannel, SeisIO.Quake.EventChannel).
- `sta::Real`: Length of short time average window in seconds
- `lta::Real`: Length of long time average window in seconds
""" delayed_sta_lta!
function delayed_sta_lta!(S::SeisData, sta::Real, lta::Real)
    for ii in 1:S.n
        delayed_sta_lta!(S[ii], sta, lta)
    end
    return nothing
end
function delayed_sta_lta!(C::GphysChannel, sta::Real, lta::Real)
    nsta = round(Int64, C.fs * sta)
    nlta = round(Int64, C.fs * lta)
    C.x .= delayed_sta_lta(C.x, nsta, nlta)
    return nothing
end

@doc delayed_sta_lta!
function delayed_sta_lta(S::GphysData, sta::Real, lta::Real)
    U = deepcopy(S)
    delayed_sta_lta!(U, sta, lta)
    return U
end
function delayed_sta_lta(C::GphysChannel, sta::Real, lta::Real)
   U = deepcopy(C)
   delayed_sta_lta!(U, sta, lta)
   return U
end
function delayed_sta_lta(A::AbstractArray, nsta::Int, nlta::Int)
    nsta > nlta ? throw(DomainError((nsta, nlta), "Short-term average must be less than long-term average")) : nothing
    nsta < 0 ? throw(DomainError(nsta, "Short-term average must be less greater than zero")) : nothing
    nlta < 0 ? throw(DomainError(nlta, "Long-term average must be greater than zero")) : nothing
    N = size(A, 1)
    T = eltype(A)
    nsta > N ? throw(DomainError(nsta, "Short-term average must be less than length of time series")) : nothing
    nlta > N ? throw(DomainError(nlta, "Long-term average must be less than length of time series")) : nothing

    sta = zeros(T, N)
    lta = zeros(T, N)
    sta[1] = A[1] ^ 2 / nsta
    for ii in 2:N
        sta[ii] = (A[ii] ^ 2 + A[max(1, ii - nsta)] ^ 2) / nsta + sta[ii - 1]
        lta[ii] = (A[max(1, ii - nsta - 1)] ^ 2 + A[max(1, ii - nsta - nlta -1)] ^ 2) / nlta + lta[max(1, ii -1)]
    end
    sta[1:min(N,nlta + nsta + 50)] .= 0.0
    lta[1:min(N,nlta + nsta + 50)] .= 1.0 # avoid division by zero
    return sta ./ lta
end

@doc """
  recursive_sta_lta!(S, sta, lta)

Computes recursive STA/LTA.

The length of the STA and LTA are given by `sta` and `sta` in seconds, respectively.

!!! note

    The in-place version (recursive_sta_lta!) overwrites the seismic trace with the STA/LTA
    characteristic function.

# Arguments
- `S::GphysData`: GphysData (SeisData, SeisChannel, SeisIO.Nodal.NodalChannel, SeisIO.Quake.EventChannel).
- `sta:Int`: Length of short time average window in seconds
- `lta:Int`: Length of long time average window in seconds

See also: [`classic_sta_lta`](@ref), [`carl_sta_trig`](@ref), [`delayed_sta_lta`](@ref) [`z_detect`](@ref)
""" recursive_sta_lta!
function recursive_sta_lta!(S::GphysData, sta::Real, lta::Real)
    for ii in 1:S.n
        recursive_sta_lta!(S[ii], sta, lta)
    end
    return nothing
end
function recursive_sta_lta!(C::GphysChannel, sta::Real, lta::Real)
    nsta = round(Int64, C.fs * sta)
    nlta = round(Int64, C.fs * lta)
    C.x .= recursive_sta_lta(C.x, nsta, nlta)
    return nothing
end

@doc recursive_sta_lta!
function recursive_sta_lta(S::GphysData, sta::Real, lta::Real)
    U = deepcopy(S)
    recursive_sta_lta!(U, sta, lta)
    return U
end
function recursive_sta_lta(C::GphysChannel, sta::Real, lta::Real)
    U = deepcopy(C)
    recursive_sta_lta!(U, sta, lta)
    return U
end
function recursive_sta_lta(A::AbstractArray, nsta::Int, nlta::Int)
    nsta > nlta ? throw(DomainError((nsta, nlta), "Short-term average must be less than long-term average")) : nothing
    nsta < 0 ? throw(DomainError(nsta, "Short-term average must be less greater than zero")) : nothing
    nlta < 0 ? throw(DomainError(nlta, "Long-term average must be greater than zero")) : nothing
    N = size(A,1)
    T = eltype(A)
    nsta > N ? throw(DomainError(nsta, "Short-term average must be less than length of time series")) : nothing
    nlta > N ? throw(DomainError(nlta, "Long-term average must be less than length of time series")) : nothing

    # compute short time average (STA) and long term average (LTA)
    # given by Evans and Allen
    csta = 1.0 / nsta
    clta = 1.0 / nlta
    sta = 0.0
    lta = 1e-99 # avoid zero division
    charfct = zeros(eltype(A), size(A))
    icsta = 1.0 - csta
    iclta = 1.0 - clta

    for ii in 2:N
        sq = A[ii] ^ 2
        sta = csta * sq + icsta * sta
        lta = clta * sq + iclta * lta
        charfct[ii] = sta / lta

        if ii < nlta
            charfct[ii] = 0.0
        end
    end
    return charfct
end

@doc """
  carl_sta_trig!(S, sta, lta, ratio, quiet)

Computes the CarlSTAtrig characteristic function.

eta = star - (ratio * ltar) - abs(sta - lta) - quiet

!!! note

    The in-place version (carl_sta_trig!) overwrites the seismic trace with the STA/LTA
    characteristic function.

# Arguments
- `S::GphysData`: GphysData (SeisData, SeisChannel, SeisIO.Nodal.NodalChannel, SeisIO.Quake.EventChannel).
- `sta::Real`: Length of short time average window in seconds
- `lta::Real`: Length of long time average window in seconds
- `ratio::AbstractFloat`: as `ratio` gets smaller, carl_sta_trig gets more sensitive
- `Quiet::AbstractFloat`: as `quiet` gets smaller, carl_sta_trig gets more sensitive
""" carl_sta_trig!
function carl_sta_trig!(S::GphysData, sta::Real, lta::Real, ratio::Real, quiet::Real)
    for ii in 1:S.n
        carl_sta_trig!(S[ii],sta, lta, ratio, quiet)
    end
    return nothing
end
function carl_sta_trig!(C::GphysChannel, sta::Real, lta::Real, ratio::Real, quiet::Real)
    nsta = round(Int64, C.fs * sta)
    nlta = round(Int64, C.fs * lta)
    C.x .= carl_sta_trig(C.x, nsta, nlta, ratio, quiet)
    return nothing
end

@doc carl_sta_trig!
function carl_sta_trig(S::GphysData, sta::Real, lta::Real, ratio::Real, quiet::Real)
    U = deepcopy(S)
    carl_sta_trig!(U, sta, lta, ratio, quiet)
    return U
end
function carl_sta_trig(C::GphysChannel, sta::Real, lta::Real, ratio::Real, quiet::Real)
    U = deepcopy(C)
    carl_sta_trig!(U, sta, lta, ratio, quiet)
    return U
end
function carl_sta_trig(A::AbstractArray, nsta::Int, nlta::Int, ratio::Real, quiet::Real)
    nsta > nlta ? throw(DomainError((nsta,nlta), "Short-term average must be less than long-term average")) : nothing
    nsta < 0 ? throw(DomainError(nsta, "Short-term average must be less greater than zero")) : nothing
    nlta < 0 ? throw(DomainError(nlta, "Long-term average must be greater than zero")) : nothing
    N = size(A,1)
    T = eltype(A)
    nsta > N ? throw(DomainError(nsta, "Short-term average must be less than length of time series")) : nothing
    nlta > N ? throw(DomainError(nlta, "Long-term average must be less than length of time series")) : nothing
    sta = zeros(T,N)
    lta = deepcopy(sta)
    star = deepcopy(sta)
    ltar = deepcopy(sta)
    pad_sta = zeros(T, nsta)
    pad_lta = zeros(T, nlta)

    # compute the short time average (STA)
    for ii in 1:nsta
        sta .+= vcat(pad_sta, A[ii:N - nsta - 1 + ii])
    end
    sta ./= nsta

    # compute the long time average (LTA)
    for ii in 1:nlta
        lta .+= vcat(pad_lta, sta[ii:N - nlta - 1 + ii])
    end
    lta ./= nlta
    lta = vcat(T(0), lta[1:end-1])

    # compute star, average of abs diff between trace and lta
    for ii in 1:nsta
        star .+= vcat(pad_sta, abs.(A[ii:N - nsta - 1 + ii] .- lta[ii:N - nsta - 1 + ii]))
    end
    star ./= nsta

    # compute ltar, long term average over star
    for ii in 1:nlta
        ltar .+= vcat(pad_lta, star[ii:N - nlta - 1 + ii])
    end
    ltar ./= nlta

    eta = star .- (T(ratio) .* ltar) .- abs.(sta .- lta) .- T(quiet)
    eta[1:nlta] .= T(-1.0)
    return eta
end

@doc """
  z_detect!(S, sta)

Z-detector from Withers, 1998.

!!! note

    The in-place version (delayed_sta_lta!) overwrites the seismic trace with the STA/LTA
    characteristic function.

# Arguments
- `S::GphysData`: GphysData (SeisData, SeisChannel, SeisIO.Nodal.NodalChannel, SeisIO.Quake.EventChannel).
- `sta::Real`: Length of short time average window in seconds
""" z_detect!
function z_detect!(S::GphysData, sta::Real)
    for ii in 1:S.n
        z_detect!(S[ii], sta)
    end
    return nothing
end
function z_detect!(C::GphysChannel, sta::Real)
    nsta = round(Int64, C.fs * sta)
    C.x .= z_detect(C.x, nsta)
    return nothing
end

@doc z_detect!
function z_detect(S::GphysData, sta::Real)
    U = deepcopy(S)
    z_detect!(U, sta)
    return U
end
function z_detect(C::GphysChannel, sta::Real)
   U = deepcopy(C)
   z_detect!(U, sta)
   return U
end
function z_detect(A::AbstractArray, nsta::Int)
    nsta < 0 ? throw(DomainError(nsta, "Short-term average must be less greater than zero")) : nothing
    N = size(A, 1)
    T = eltype(A)
    nsta > N ? throw(DomainError(nsta, "Short-term average must be less than length of time series")) : nothing

    # Z-detector given by Swindell and Snell, 1977
    sta = zeros(T, N)
    A2 = A .^ 2

    # replace this with convolution
    for ii in 1:nsta
        sta[ii:N - nsta - 1 + ii] .+= A2[ii:N - nsta - 1 + ii]
    end
    return (sta .- mean(sta)) ./ std(sta)
end

@doc """
  trigger_onset(charfct, thresh1, thresh2; max_len=1e99, max_len_delete=false)

Calculate trigger on and off times.

Given `thresh1` and `thresh2` calculate trigger on and off times from
characteristic function.

# Arguments
- `charfct::AbstractArray`: Characteristic function of e.g. STA/LTA trigger.
- `thresh1::Real`: Value above which trigger (of characteristic function)
    is activated (higher threshold).
- `thresh2::Real`: Value below which trigger (of characteristic function)
    is deactivated (lower threshold).
# Keywords
- `max_len::Int`: Maximum length of triggered event in samples. A new
    event will be triggered as soon as the signal reaches again above thresh1.
- `max_len_delete::Bool`: Do not write events longer than max_len into report file.
""" trigger_onset
function trigger_onset(charfct::AbstractArray, thresh1::Real, thresh2::Real;
    max_len::Int=10^10, max_len_delete::Bool=false,
)
    thresh2 > thresh1 ? throw(DomainError(thresh1, "thresh1 $thresh1 must be greater than thresh2 $thresh2")) : nothing
    ind1 = findall(charfct .> thresh1)
    if length(ind1) == 0
        return Array{Int64}(undef,0,0)
    end
    ind2 = findall(charfct .> thresh2)

    on = [ind1[1]]
    off = [-1]

    # determine the indices where charfct falls below off-threshold
    ind2_ = Array{Bool}(undef,length(ind2))
    ind2_[1:end-1] .= diff(ind2) .> 1
    # last occurence is missed by diff, add it manually
    ind2_[end] = true
    append!(off,ind2[ind2_])
    append!(on,ind1[findall(diff(ind1) .> 1) .+ 1])
    # include last pick if trigger is on or drop it
    if max_len_delete
        # drop it
        append!(off,max_len)
        append!(on,on[end])
    else
        # include it
        append!(off,ind2[end])
    end

    pick = []
    while on[end] > off[1]
        while on[1] <= off[1]
            deleteat!(on,1)
        end
        while off[1] < on[1]
            deleteat!(off,1)
        end
        if off[1] - on[1] > max_len
            if max_len_delete
                deleteat!(on,1)
                continue
            end
            prepend!(off,on[1] + max_len)
        end
        push!(pick,[on[1],off[1]])
    end
    return permutedims(hcat(pick...))
end


text:
include("../src/autograd.jl")

import .autograd: Variable, backward, zero_grad

a = Variable(2, true)
b = Variable(5, true)
c = a + b
d = a * b

# println("c = ", c.value)
# backward(c)
# println("∇a = ", a.grad )

# zero_grad(b)

# println("d = ", d.value)
# backward(d)
# println("∇b = ", b.grad)

e = c * d
backward(e)

println(a.grad)

max_stars_repo_name: brymer-meneses/Autograd

max_issues_repo_name: brymer-meneses/Autograd

max_forks_repo_name: brymer-meneses/Autograd