Friday 21 June 2019

Média móvel do buffer circular


Eu usei-o para um log in-memory com um tamanho restrito. Por exemplo, o aplicativo escreveria entradas de log enquanto processava solicitações de usuários. Sempre que ocorreu uma exceção (que seria perigosa para o processamento), os registros de registro atualmente na memória seriam despejados junto com ele. O benefício de um buffer circular é que você não precisa de infinitas quantidades de memória, já que as entradas antigas são substituídas automaticamente. O desafio é que você precisa encontrar um tamanho adequado para sua usecase. No exemplo acima, seria muito lamentável quando o registro de log com as informações mais importantes sobre a exceção já tivesse sido substituído. Algumas aplicações de sistemas têm ferramentas para permitir que você extraia o conteúdo atual do buffer na demanda e não apenas quando seria extrair automaticamente (se alguma vez). Eu acredito ETW e o registro de estresse do CLRs. Entre muitos outros sistemas, o kernel ou o tracelogging de alto desempenho, são implementados dessa forma. O conceito de usar esses buffers para registro de rastreamento na memória é realmente bastante comum (para não dizer que este é o único uso - certamente não), porque é muito mais rápido do que registros escritos em um banco de dados arquivado que talvez você nunca esteja interessado a menos que Ocorre erro. E em uma nota relacionada, ele conserva o espaço no disco rígido. Os buffers circulares são bons para fluxos de dados em série em sistemas embarcados. Os microcontroladores muitas vezes têm um UART para lidar com um byte em série que entra, estes precisam ser armazenados em ordem e tratados mais tarde (os bytes geralmente chegam a uma taxa mais rápida do que eles podem ser manipulados). O buffer efetivamente divide a resposta cronológica necessária (quando os bytes entram, em microssegundos) para a resposta não cronológica crítica para toda a mensagem (por exemplo, exibir a mensagem que veio em milissegundos), por exemplo: 1) Sobre O recebimento de um byte do UART pode gerar uma interrupção para a qual o software responde tomando rapidamente o byte recebido e empurrando-o para o final do buffer. 2) As rotinas de software de fundo podem então verificar regularmente se o buffer possui algo nele e esvaziá-lo conforme necessário. Como o tamanho do buffer circular pode ser definido antes da compilação, o tamanho é limitado. Isso ajuda a melhorar a eficiência espacial e deve eliminar a corrupção da memória em um trade off para quantos bytes podem ser recebidos antes que os dados comecem a se perder. Eu sei que isso é trapaça, mas a wikipedia tem uma ótima explicação. Um buffer circular, buffer cíclico ou buffer de anel é uma estrutura de dados que usa um único buffer de tamanho fixo como se fosse conectado de ponta a ponta. Esta estrutura se presta facilmente ao armazenamento de dados de córregos. Um exemplo que possivelmente poderia usar um buffer circular de substituição é com multimídia. Se o buffer for usado como o buffer limitado no problema produtor-consumidor, provavelmente é desejado para o produtor (por exemplo, um gerador de áudio) substituir dados antigos se o consumidor (por exemplo, a placa de som) não conseguir acompanhar momentaneamente. Outro exemplo é o método de síntese de guia de onda digital que usa buffers circulares para simular eficientemente o som de cordas vibratórias ou instrumentos de sopro. No que diz respeito à comparação com as listas de dupla ligação, eu imagino que realmente depende do que você está usando a lista. A implementação de buffers cirulares parece ser mais complexa, por favor (novamente) consulte a página wiki, isso explica implementação, considerações etc. e também mostra código de exemplo. Respondeu 31 de março 10 às 14: 25 Eu sei que isso é realizável com o aumento de acordo com: Mas eu realmente gostaria de evitar o uso de impulso. Eu mencionei e não encontrei nenhum exemplo adequado ou legível. Basicamente eu quero acompanhar a média móvel de um fluxo contínuo de um fluxo de números de ponto flutuante usando os 1000 números mais recentes como amostra de dados. Qual é a maneira mais fácil de alcançar isso, experimentei usar uma matriz circular, uma média móvel exponencial e uma média móvel mais simples e descobriu que os resultados da matriz circular adequavam minhas necessidades. 12 de junho 12 às 4:38 Se suas necessidades são simples, você pode tentar usar uma média móvel exponencial. Simplificando, você faz uma variável de acumulador e, à medida que seu código examina cada amostra, o código atualiza o acumulador com o novo valor. Você escolhe um alfa constante que está entre 0 e 1 e calcula isso: você precisa apenas encontrar um valor de alfa onde o efeito de uma determinada amostra dura apenas cerca de 1000 amostras. Hmm, na verdade, não tenho certeza de que isso é adequado para você, agora que eu já coloquei aqui. O problema é que 1000 é uma janela bastante longa para uma média móvel exponencial. Não tenho certeza se houver um alfa que espalhe a média nos últimos 1000 números, sem fluxo inferior no cálculo do ponto flutuante. Mas se você quisesse uma média menor, como 30 números ou mais, esta é uma maneira muito fácil e rápida de fazê-lo. Respondeu 12 de junho 12 às 4:44 1 na sua postagem. A média móvel exponencial pode permitir que o alfa seja variável. Assim, isso permite que ele seja usado para calcular médias base de tempo (por exemplo, bytes por segundo). Se o tempo desde a última atualização do acumulador for superior a 1 segundo, você deixa alfa ser 1.0. Caso contrário, você pode deixar alpha be (usecs desde a última atualização1000000). Ndash jxh 12 de junho 12 às 6:21 Basicamente eu quero acompanhar a média móvel de um fluxo contínuo de um fluxo de números de ponto flutuante usando os 1000 números mais recentes como uma amostra de dados. Observe que as atualizações abaixo atualizam o total como elementos como adicionados, evitando a trajetória O (N) cara para calcular a soma - necessária para a média - na demanda. Total é feito um parâmetro diferente de T para suportar, e. Usando um longo tempo quando totalizando 1000 long s, um int para char s, ou um duplo para float total s. Isso é um pouco falho em que numsamples poderia ultrapassar o INTMAX - se você se importar, você poderia usar um sinal não assinado por muito tempo. Ou use um membro extra de dados do bool para gravar quando o recipiente é preenchido pela primeira vez ao andar de bicicleta numsamples em torno da matriz (melhor então renomeado algo inócuo como pos). Respondeu 12 de junho 12 às 5:19 um assume que quotvoid operator (T sample) quot é realmente quotvoid operatorltlt (T sample) quot. Ndash oPless Jun 8 14 às 11:52 oPless ahhh. Bem manchado. Na verdade, eu quis dizer que ele seria um operador vazio () (amostra T), mas é claro que você poderia usar qualquer notação que você gostasse. Vou consertar, obrigado. Ndash Tony D 8 de junho 14 às 14: 27 Uma das principais aplicações para a placa Arduino é a leitura e registro de dados do sensor. Por exemplo, um monitora a pressão a cada segundo do dia. Como altas taxas de amostragem muitas vezes geram picos nos gráficos, um também quer ter uma média das medidas. Como as medidas não são estáticas no tempo, o que muitas vezes precisamos é uma média em execução. Esta é a média de um determinado período e muito valioso quando se faz análise de tendências. A forma mais simples de uma média em execução pode ser feita por código que se baseia na média anterior: se não quiser usar matemática de ponto flutuante - como isso ocupa memória e diminui a velocidade - pode-se fazer o mesmo completamente no domínio inteiro. A divisão por 256 no código da amostra é um shift-right 8, que é mais rápido do que dizer divisão por e. 100. Isso é verdade para cada poder de 2 como divisor e um só deve cuidar a soma dos pesos é igual à potência de 2. E é claro que se deve cuidar que não haja transbordamento intermediário (considere usar sem assinatura longa) Se você precisar Uma média de corrida mais precisa, in concreto das últimas 10 medidas, você precisa de uma matriz (ou lista vinculada) para mantê-las. Esta matriz funciona como um buffer circular e com cada nova medida, a mais antiga é removida. A média de corrida é calculada como a soma de todos os elementos divididos pelo número de elementos na matriz. O código para a média em execução será algo assim: Desvantagem deste código é que a matriz para manter todos os valores pode se tornar bastante grande. Se você tem uma medida por segundo e quer uma média corrente por minuto, você precisa de uma série de 60, uma média por hora precisaria de uma matriz de 3600. Isso não poderia ser feito dessa maneira em um Arduino, pois ele só possui 2K de RAM. No entanto, ao construir uma média de 2 estágios, pode ser abordado bastante bem (aviso: não para todas as medidas). No código psuedo: Como uma nova matriz estática interna é necessária para cada função runningAverage, isso grita para ser implementado como uma classe. Biblioteca RunningAverage A biblioteca runningAverage faz uma classe da função acima para que ela possa ser usada várias vezes em um esboço. Desacopla a função add () e avg () para ser um pouco mais flexível, e. Pode-se chamar a média várias vezes sem adicionar nada. Observe que todas as instâncias da classe adicionam sua própria matriz para armazenar medidas, e isso aumenta o uso da memória. A interface da classe é mantida tão pequena quanto possível. Nota: com a versão 0.2 os nomes dos métodos são todos mais descritivos. Um pequeno esboço mostra como ele pode ser usado. Um gerador aleatório é usado para imitar um sensor. Na configuração (), o myRA é limpo para que possamos começar a adicionar novos dados. Em loop () primeiro, um número aleatório é gerado e convertido em um flutuador para ser adicionado ao myRA. Em seguida, o runningAverage é impresso na porta serial. Pode-se também exibi-lo em algum LCD ou enviar por ethernet, etc. Quando são adicionados 300 itens, o myRA está limpo para começar de novo. Para usar a biblioteca, faça uma pasta nas suas LISTAS SKETCHBOOKPATH com o nome RunningAverage e coloque o. h e. cpp lá. Opcionalmente, faça um subdiretório de exemplos para colocar o aplicativo de exemplo. 2017-01-30: versão inicial 2017-02-28: destrutor faltando fixo no arquivo. h 2017-02-28: construtor padrão removido 2017--. TrimValue () Yuval Naveh adicionou trimValue (encontrado na web) 2017-11-21: refatorado 2017-12-30: adicionado fillValue () refatorado para publicação 2017-07-03: código de proteção de memória adicionado - se a matriz interna não puder ser alocada tamanho Torna-se 0. Isso é para resolver o problema descrito aqui - forum. arduino. ccindex. phptopic50473.msg1790086msg1790086 - Teste extensivamente. Classe Template RunningAverage. h RunningAverage. cpp

No comments:

Post a Comment