Ecuaciones en diferencias
Código auxiliar
# Cargo paquetitosusing DSP, FFTW, Statistics, WAVfunction wavread_mono(file) x, sr = wavread(file) return mean(x; dims=2)[:], srend# Y armo un par de funciones auxiliaresstem(args...; kwargs...) = sticks(args...; marker=:circle, leg=false, kwargs...)zeropolegain(pr) = DSP.ZeroPoleGain(pr)zeropolegain(z, p, g) = DSP.ZeroPoleGain(z, p, g)polynomialratio(zpg) = DSP.PolynomialRatio(zpg)function polynomialratio(b, a) n = max(length(a), length(b)) return DSP.PolynomialRatio(padright(b, n), padright(a, n))endgetpoles(zpg) = DSP.ZeroPoleGain(zpg).pgetzeros(zpg) = DSP.ZeroPoleGain(zpg).zgetgain(zpg) = DSP.ZeroPoleGain(zpg).kgetnumcoefs(pr) = trimlastzeros!(reverse(DSP.PolynomialRatio(pr).b.coeffs))getdencoefs(pr) = trimlastzeros!(reverse(DSP.PolynomialRatio(pr).a.coeffs))function trimlastzeros!(a) !iszero(a[end]) && return a pop!(a) return trimlastzeros!(a)endDSP.filt(zpg::DSP.ZeroPoleGain, r...; kwargs...) = filt(polynomialratio(zpg), r...; kwargs...)function zplane(zs, ps; kwargs...) scatter(real.(zs), imag.(zs); marker = (:black, :circle), label="Cero", kwargs...) scatter!( real.(ps), imag.(ps); marker = (:red, :xcross), label="Polo", kwargs...) ts = range(0,stop=2pi;length=100) plot!(cos.(ts), sin.(ts); aspect_ratio = 1, kwargs...)endfunction zplane(zpg; kwargs...) zs = getzeros(zpg) ps = getpoles(zpg) isempty(zs) && isempty(ps) && (append!(ps, 0)) return zplane(zs, ps; kwargs...)endzplane(pr::DSP.PolynomialRatio; kwargs...) = zplane(DSP.ZeroPoleGain(pr); kwargs...)# Deltad(n) = n == 0 ? 1. : 0. # Escalónu(n) = n >= 0 ? 1. : 0. using PlotsPlots.default(:legend, false)# Pad vector with zeros on the right until its length is `n`padright(x, n) = copyto!(zeros(eltype(x), n), x)"""Función módulo pero con offset (opcional)Manda a `t` al intervalo [from, from+length)sumándole o restándole algún múltiplo de `len`"""cshift(t, len, from=0) = mod(t - from, len) + from# Espectrogramausing IterToolsfunction stft(x; overlap, window, nfft, rest...) nwin = length(window) overlap < nwin res = [ fft(padright(xseg .* window, nfft)) for xseg in partition(x, nwin, nwin - overlap)] return [ res[i][j] for j in 1:nfft, i in eachindex(res)]endfunction specgram(x; overlap=0.5, window=hamming(div(length(x), 16)), nfft=length(window), rest...) window isa Integer && (window = rect(window)) overlap isa AbstractFloat && (overlap = round(Int, length(window) * overlap)) return stft(x; overlap=overlap, window=window, nfft=nfft)end specplot(x::AbstractMatrix; kwargs...) = "You are entering a Matrix (2D Array). I need a Vector (1D Array)."function specplot(x::AbstractVector; fs=1, onesided=false, xaxis="Tiempo (s)", yaxis="Frecuencia (Hz)", kws...) mat = specgram(x; kws...) fmax = fs if onesided mat = mat[1:div(size(mat, 1) + 2, 2), :] fmax = fs/2 end times = range(0; length=size(mat, 2), stop=length(x)/fs) # aprox freqs = range(0; length=size(mat, 1), stop=fmax) # Reubico las frecuencias negativas arriba de todo if !onesided freqs = cshift.(freqs, fs, -fs/2) ord = sortperm(freqs) mat = mat[ord, :] freqs = freqs[ord] end return heatmap(times, freqs, log.(abs.(mat) .+ eps()); xaxis=xaxis, yaxis=yaxis, seriescolor=:bluesreds, legend=true, kws...) return times, freqs, mat endfunction specplot(x :: AbstractVector{<:AbstractFloat}; kws...) return specplot(convert.(Complex, x); onesided=true, kws...)endAlgunas funciones para trabajar con sistemas definidos por ecuaciones en diferencias
Los sistemas LTI definidos por ecuaciones en diferencias tiene una transferencia H(z) racional. Quedan totalmente definidos por los coeficientes del polinomino del numerador y del denominador. Alternativamente, por la lista de polos, ceros, y un valor de ganancia.
Los sistemas FIR (respuesta al impulso finita) expresan la salida como una convolución que ya es una ecuación en diferencias, de orden 0 (sólo aparece y(n)). El denominador de H(z) es 1. No tiene polos (salvo quizás en 0 o infinito).
Si queremos ver la salida de un sistema FIR, usamos la función `conv`.
Los sistemas IIR no se pueden implementar con la función `conv` ya que h(n) es infinita. Pero, los que vienen de ecuaciones en diferencias, sí. La PC implementa la versión inicialmente en reposo, iterando hasta cierto n.
La función que hace esto se llama `filt` (en MATLAB y otros, `filter`).
#=Si se quiere tener la salida inicialmente en reposo para este sistemaa[1] * y(n) + a[2] * y(n-1) +... = b[1] * x(n) + b[2] * x(n-1) + ...frente a una entrada definida pro el vector x (x(n) = 0 para n<0, x(0)=x[1], etc)uno usafilt(b, a, x)La salida tendrá tantos elementos como x=## Caso FIRfilt([0, 1], [1], 1:10)# Caso IIRa = [1, 3.4] # Sin pérdida de generalidad, a(1) puede ser siempre 1b = [3.2, 1.3, 6.7]filt(b, a, 1:3)# Si querés más valores, meté una entrada más larga. Si terminó la entrada, agregar cerosfilt(b, a, padright(1:3, 5))Se puede hacer un diagramita de polos y ceros a partir del vector de polos y de ceros con la función zplane
zs = [-1.34, 0]ps = 0.8 .* exp.(im .* range(0; step=2pi/10, length=10))zplane(zs, ps)# Podemos armar un objeto que representa un filtro IIR a partir de los polos, ceros y gananciagain = 1zpg = zeropolegain(zs, ps, gain);# y recuperar los zerosgetzeros(zpg)# o polosgetpoles(zpg)# o gananciagetgain(zpg)# o tb podemos armar un objeto en términos de los vectores de coeficientes a y b definidos como para filtpr = polynomialratio(b, a);# y recuperar numeradorgetnumcoefs(pr)# o denominadorgetdencoefs(pr)# Cualquiera de estas se pueden usar con zplanezplane(zpg)zplane(pr)# y cualquiera permite extraer polos, cerosgetzeros(pr), getpoles(pr)# o coeficientes del polinomio numerador y denominadorgetnumcoefs(zpg), getdencoefs(zpg)# filt acepta estos objetos tambiénfilt(pr, 1:3), filt(b, a, 1:3), filt(zpg, 1:3)# También podés usar estos objetos en la función freqz, que# devuelve la respuesta en frecuencia del sistema estable# evaluada en cierto omegón (ojo que el estable puede no ser el# inicialmente en reposo)w = pi/4freqz(pr, w)# No hace más que la cuentita de evaluar H(z=exp(im*w))cuentita(w) = sum(b .* exp(-im*w) .^ (0 : length(b) - 1)) / sum(a .* exp(-im*w) .^ (0 : length(a) - 1))cuentita(w)fs = range(0; stop=pi, length=300)plot(fs, abs.(freqz(pr, fs)))