Dúvida - Filtro passa-tudo

Dúvida - Filtro passa-tudo

por Gabriel Sarti Massukado -
Número de respostas: 11

Olá! Estou com uma dúvida sobre o como aplicar o filtro passa-tudo...

Esse filtro deve ser aplicado apenas na tabela de 64 amostras que será devolvida pelo ofelia.perform() (não alterando os valores que estão salvos durante o algoritmo) ou deve ser aplicado nos 64 valores da tabela de amostras que são atualizados em cada iteração do ofelia.perform()?
Obrigado!

Em resposta à Gabriel Sarti Massukado

Re: Dúvida - Filtro passa-tudo

por Gabriel Sarti Massukado -
Outra dúvida que me surgiu foi que, ao fazer o processamento polifônico, não é mais possível retornar a tabela com as 64 amostras que serão tocadas a cada iteração da tabela de eventos, pois o return faria com que o loop que itera pela tabela de eventos fosse interrompido... Estou entendendo algo errado?
Em resposta à Gabriel Sarti Massukado

Re: Dúvida - Filtro passa-tudo

por Marcelo Queiroz -
O filtro passa-tudo deve ser aplicado dentro do loop KS, ou seja, ele deve afetar a tabela interna do algoritmo (e por consequência também a saída). Se ele fosse aplicado apenas na tabela de 64 amostras, a correção do atraso do loop não aconteceria, e na prática o som não mudaria praticamente nada.

Sobre o que fazer no caso polifônico, o loop que itera sobre os eventos deve sempre somar/mixar cada um dos eventos à saída, sendo que o return da tabela de 64 amostras tem que ocorrer após todos os eventos serem processados. Talvez a lógica deva ser repensada: a cada chamada da função perform devemos produzir o vetor de 64 amostras, que recebe contribuição de vários eventos, com tabelas de tamanhos diferentes, mas que só contribuirão com 64 amostras em cada uma dessas chamadas.
Em resposta à Marcelo Queiroz

Re: Dúvida - Filtro passa-tudo

por Gabriel Sarti Massukado -
Peço desculpas, mas acho que ainda não entendi completamente essas duas últimas partes da segunda fase...

Quando estiver lidando com o filtro passa-tudo, os valores de x( n) e x(n-1) devem ser aqueles que foram tratados apenas pelo filtro passa-baixas, enquanto y( n) será o novo valor de x( n) e y(n-1) será o valor de x(n-1) tratado pelo passa-tudo, isso está correto? Caso esteja, como exatamente eu posso lidar com o caso inicial, quando o valor de x(n-1) não foi tratado por nenhum dos filtros?
Além disso, a duração D também tem sua fórmula alterada quando alteramos a forma como calculamos L?
Novamente, obrigado!
Em resposta à Gabriel Sarti Massukado

Re: Dúvida - Filtro passa-tudo

por Marcelo Queiroz -

Não peça desculpas quando a falta de clareza é minha ou do enunciado...

Normalmente os filtros são representados por expressões do tipo y[n] = F(x,y) onde F(x,y) é uma combinação linear de valores da entrada x e da saída passada y. Usarmos x para a entrada do filtro e y para a saída é apenas uma notação tradicional, e devemos levar isso em consideração especialmente quando os filtros forem encadeados, como nesse caso onde a saída do passa-baixas serve de entrada para o passa-tudo. Se preferir, re-escreva as equações assim:

y[n]=[(1-S)x[n]+Sx[n-1]]

z[n]=Cy[n]+y[n-1]-Cz[n-1]

Nesse par de equações que correspondem à conexão [passa-baixas]→[passa-tudo], x[n] é o sinal que estava na tabela KS, y é o mesmo sinal filtrado apenas pelo passa-baixas e z é o sinal filtrado pelos dois filtros. Perceba que existe a necessidade de guardar valores anteriores em cada uma das equações. Na página 287 do Moore dá pra ver uma possível implementação em C dessa sequência de passos, com as respectivas variáveis temporárias para armazenar os valores anteriores necessários.

 

Em resposta à Marcelo Queiroz

Re: Dúvida - Filtro passa-tudo

por Gabriel Sarti Massukado -
Professor, por mais que eu acredite que entendi como o filtro funciona, ainda não consegui implementá-lo corretamente...
Mesmo tendo feito as partes de controle do timbre e da duração percebida com sucesso, todas as implementações que tentei fazer para aplicar o filtro resultam ou em sons extremamente distorcidos ou em apenas "clicks" - com algumas poucas frequências soando próximas do que eu acho que deveriam soar (apenas 3 das teclas do teclado, pelo que percebi).
Atualmente, tentei usar um vetor para os valores z[n], para garantir que eles não estavam conflitando com os de y[n], mas ainda assim não consegui bons resultados.
Alguém tem alguma ideia do que pode estar causando isso?
Obrigado!
Em resposta à Gabriel Sarti Massukado

Re: Dúvida - Filtro passa-tudo

por Edgar Bernardi Righi -
Olá. Eu tive o mesmo problema. Isso acontece pois o filtro passa tudo está "estourando". O coeficiente C tem que ser obrigatoriamente menor que um, senão a amostra seguinte fica sempre maior que a anterior e assim sucessivamente e por fim satura. Verifique se o seu delta é sempre positivo. Quando ele é negativo, C acaba ficando maior que um. Calcule delta em módulo. Use a função print(string.format("delta=%f C=%f",delta,C)) para debugar. Outro problema que tive é que de início eu usei bhaskara para encontrar as soluções literais (em função de cosseno) da equação quadrática. Isso não funciona, às vezes eu obtinha soluções negativas para o valor de S. Em uma análise mais profunda, eu vi que em alguns ângulos tinha que ter uma solução especial. O jeito é calcular em número mesmo. Aí o valor de S sempre dá duas soluções positivas e é só pegar a menor delas. Espero ter ajudado e não ter dito nada errado... Eu cheguei até a me desesperar por causa desses problemas.
Em resposta à Edgar Bernardi Righi

Re: Dúvida - Filtro passa-tudo

por Marcelo Queiroz -

Bom dia!

Acredito que o caminho seja realmente colocar print's para todos os parâmetros calculados e verificar manualmente se eles estão certos. Você também pode colocar "sanity checks" no meio do código para verificar algumas propriedades importantes:

1) S sempre deve estar entre [0,1/2]. Não é difícil provar que aquela equação quadrática sempre terá duas raízes reais entre [0...1], sendo a menor delas o S correto (veja um rascunho da prova no final desta mensagem). Se está aparecendo algum S<0 ou S>1, é um bug. E esse S pode sim ser obtido por Bhaskara, foi exatamente assim que eu implementei (Edgar, não entendi o que você quis dizer com "calcular em número mesmo").

2) O delta sempre tem que estar entre [0,1], e consequentemente o C também estará sempre entre [0,1] (o argumento também está no final da mensagem). O filtro passa tudo nunca seria capaz de introduzir atrasos negativos (adiantamentos do sinal), pois ele é causal (só conhece amostras do passado).

Argumentos:

1) Escreva a equação de 2o grau como aS^2+bS+c=0 e note que b=-a. Para mostrar que sempre há duas raízes reais, basta verificar que o discriminante é >0: b^2-4ac=a^2-4ac=a(a-4c); por um lado, a>0 para qualquer ω>0; por outro lado, 1>G1>G0 implica 0<c=1-G1^2<1-G0^2=1-cos^2(ω/2)=0.5-0.5cos(ω)=a/4, logo a-4c>a-4(a/4)=0. Para mostrar que as duas raízes reais estão entre [0,1], basta ver que as raízes são (-b±sqrt(discriminante))/(2a)=(a±sqrt(discriminante))/(2a)=0.5±sqrt(discriminante)/(2a) e mostrar que sqrt(discriminante)/(2a)<=0.5 ou equivalentemente discriminante<=a^2; mas discriminante=a^2-4ac com a e c positivos.

2) Ao calcular L=floor(R/F-S) temos automaticamente L<=R/F-S<=L+1 e portanto o atraso que falta introduzir é Δ=R/F−(L+S)>=0. Por outro lado, R/F-S<=L+1 implica Δ=R/F−(L+S)<=1. Para ver que C=(1-Δ)/(1+Δ) também está entre [0...1] basta ver que o numerador está entre [0...1] e o denominador é >=1.

 

Em resposta à Marcelo Queiroz

Re: Dúvida - Filtro passa-tudo

por Edgar Bernardi Righi -
No meu código estava L=floor(R/F-S+0.5) aí o delta realmente dá negativo em alguns valores. Na versão do enunciado de ontem de manhã voltou L=floor(R/F-S+0.5) ao invés de L=floor(R/F-S) ... Achei que tinha desfeito a correção do enunciado e tinha que deixar assim.
Em resposta à Edgar Bernardi Righi

Re: Dúvida - Filtro passa-tudo

por Gabriel Sarti Massukado -
Agradeço as respostas de vocês e enchi meu código de mais prints do que antes, mas ainda não consegui descobrir o que está errado.
Printando os valores, vi que nenhum deles estava fora do intervalo que deveria, mas eu percebi que meu código sempre determina que g0 >= g1 é verdadeiro. Conferi todos os valores dos argumentos recebidos e estou calculando g0 = math.cos(pi*F/R) e g1 = 10^(-3/(F*D)), como está indicado no enunciado... Esse comportamento é esperado?
Tentei até utilizar condicionais para caso algum valor ultrapassasse seu intervalo, fosse atribuído a ele o limite do intervalo, mas o comportamento continuou exatamente igual.
Estou muito confuso que estou trabalhando nisso desde quarta-feira e não consigo entender porque o controle da frequência fundamental não funciona ):
Em resposta à Gabriel Sarti Massukado

Re: Dúvida - Filtro passa-tudo

por Edgar Bernardi Righi -
Você conseguiu entregar? Primeiro, você definiu pi antes? Pois deveria ser math.cos(math.pi*F/R).. Se sim desconsidere. Fora isso, para o cálculo de g1, D deve ser em SEGUNDOS e não em amostras! Eu cometi esse erro uma vez. Se vc calcular em amostras, g0 sempre será maior que g1. Esse comportamento que você teve não é normal. Também, verifique as variáveis globais e locais... se outra variável no código não está mudando algum valor local... No processamento polifônico, as vezes eu tinha uns comportamentos esquisitos, que eram causados pela configuração de delay em ms no diálogo Media->Audio Settings->Delay (msec). No linux estava 200ms e funcionava ok. No macOS, algumas notas ficavam distorcidas, aí eu notei que estava em 5ms, aumentei para 200ms e ficou perfeito.
Em resposta à Edgar Bernardi Righi

Re: Dúvida - Filtro passa-tudo

por Gabriel Sarti Massukado -
Acabei entregando parcialmente mesmo... Acho que era isso do cálculo de D em segundos, o que também explicaria porque meu fade-out estava um pouco estranho...
Agradeço muito a ajuda mesmo assim, pois graças a vocês consegui consertar algumas coisas no trabalho! (: