Commit e797b7d1 authored by Bernardo Quaresma Dias's avatar Bernardo Quaresma Dias
Browse files

[INSTMPA-822]

+criação de versão inicial de infraestrutura de composição de blocos de cálculo em diagnósticos de variáveis de processo
parent abfa3e9a
class{ id = "amostras", name = "Amostras", group = "Diagnstico",
bases = {}, description =
[[Classe que modela um conjunto de amostras de uma varivel de processo.]],
attributes = {
{ id = "intervalo_min", name ="Intervalo Mnimo", type = "REAL", access ="", description =
[[Intervalo mnimo entre amostras.]],
},
{ id = "validade", name ="Validade", type = "REAL", access ="", description =
[[Validade em segundos de uma amostra inserida na lista.]],
},
},
code = [====[
function _CLASS:init()
self._samples = {}
end
]====],
methods = {
{ id = "iniciar", name ="Iniciar", description =
[[Inicia atemporizao estabelecendo um tempo limite para sua concluso.]],
parameters = {
},
results = {
},
code = [===[ function(self)
self:init()
end ]===],
},
{ id = "inserir", name ="Inserir", description =
[[Insere elemento na lista de amostras com o valor informado.]],
parameters = {
{ name = "Valor", type = "REAL" },
},
results = {
},
code = [===[ function(self, v)
local t_atual = time()
local amostras = self._samples
local t_ultima = amostras[1] and amostras[1].tempo
if (not t_ultima) or (t_atual - self.intervalo_min > t_ultima) then
local amostra = {
valor = v,
tempo = t_atual
}
table.insert(amostras, 1, amostra)
self:atualizar()
end
end ]===],
},
{ id = "atualizar", name ="Atualizar", description =
[[Atualiza amostras removendo vencidas da lista.]],
parameters = {
},
results = {
},
code = [===[ function(self, v)
if self.validade then
local t_limite = time() - self.validade
local amostras = self._samples
while amostras[#amostras].tempo < t_limite do
table.remove(amostras)
end
end
end ]===],
},
{ id = "validar", name ="Validar", description =
[[Informa se o tempo da ltima amostra maior que a validade configurada ou que o perodo de tempo passado por parmetro.]],
parameters = {
{ name = "Tempo", type = "REAL" },
},
results = {
{ name = "Vlido", type = "BOOLEAN" },
},
code = [===[ function(self, t)
if not (t or self.validade) then
return list[1] and true or false
else
return (time() - list[#list].tempo) > (t or self.validade)
end
end ]===],
},
{ id = "obter_historico", name ="Obter Histrico", description =
[[Obtm o histrico de valores de amostras pelo perodo de tempo passado por parmetro.]],
parameters = {
{ name = "Tempo", type = "REAL" },
},
results = {
{ name = "Histrico", type = "REAL[]" },
},
code = [===[ function(self, t)
local historico = {}
local t_atual = time()
local a = 1
for a, amostra in ipairs(self._samples) do
if t and (t_atual - t > amostra.tempo) then
break
end
historico[#historico+1] = amostra.valor
end
return historico
end ]===],
},
},
}
include('lib-amostras-1_0.mpam')
include('lib-utils-list-1_0.mpam')
class{ id = "bloco_calculo", name = "Bloco de Cálculo", group = "Blocos de Cálculo",
bases = {},
description = [[]],
attributes = {
{ id = "intervalo", name = "Intervalo", type = "REAL", access = "gs", description =
[[Intervalo em que o último resultado ainda pode ser considerado sem disparar uma nova execução.]],
},
},
methods = {
{ id = "apagar", name = "Apagar",
description = [[Apaga resultados de cálculos anteriores.]],
parameters = {
},
results = {
},
code = [===[ function(self)
self._t_ret = nil
self._ret = nil
end ]===],
},
{ id = "executar", name = "Executar", description =
[[Executa o bloco para uma nova amostra respeitando o intervalo configurado.]],
parameters = {
{ name = "Valor", type = "REAL" },
},
results = {
{ name = "Resultado", type = "REAL" },
},
code = [===[ function(self, valor)
local t_atual = time()
if (not (self._t_ret and self.intervalo) )
or (t_atual - self._t_ret >= self.intervalo )
then
self._ret = self:calcular(valor) --[[DEBUG]] print("intervalo", self.intervalo, "valor", valor)
self._t_ret = t_atual
end
return self._ret
end ]===],
},
},
}
class{ id = "bloco_filtro", name = "Bloco Filtro", group = "Blocos de Cálculo",
bases = {"bloco_calculo"},
description = [[Bloco que recebe um valor e calcula o seu valor filtrado desde a última execução.]],
attributes = {
{ id = "t",
name = "T",
type = "REAL",
access = "gs",
description = [[O valor da constante de tempo do processo.]],
},
{ id = "k",
name = "K",
type = "REAL",
access = "gs",
description = [[O valor da constante do processo.]],
},
{ id = "v_init",
name = "Valor Inicial",
type = "REAL",
access = "gs",
description = [[O valor do filtro em sua primeira execução. Se não for definido o primeiro valor será igual à primeira leitura.]],
},
},
code = [====[
function _CLASS:init() --[[DEBUG]] print("bloco_filtro:init")
end
]====],
methods = {
{ id = "iniciar", name = "Iniciar",
description = [[Iniciar a execução do filtro.]],
parameters = {
},
results = {
},
code = [===[ function(self)
self._y_1 = nil
self._t_0 = nil
self._t_1 = nil
self:apagar()
end ]===],
},
{ id = "validar", name = "Validar", description =
[[Informa se o bloco tem amostras o suficiente para realizar uma execução.]],
parameters = {
},
results = {
{ name = "Valido", type = "BOOLEAN" },
},
code = [===[ function(self)
return self._t_ret and (self._t_ret + self.intervalo > time())
end ]===],
},
{ id = "consultar", name = "Consultar", description =
[[Informa o valor do filtro na última execução.]],
parameters = {
},
results = {
{ name = "Resultado", type = "REAL" },
},
code = [===[ function(self)
return self._ret or self.v_init
end ]===],
},
{ id = "executar", name = "Executar", description =
[[Executa o filtro sobre o valor do processo.
O filtro de primeira ordem calcula a seguinte equação sobre o valor do processo:
f(x) = (K*x*dt+T*f[-1])/(T+dt)
Onde K é a constante de ganho adimensional do processo, dt é a diferença de
tempo, em segundos, entre a avaliação anterior e a atual, T é a constante de
tempo do processo em segundos e f[-1] é o valor do filtro calculado na
avaliação anterior.
Se o valor inicial for nulo, o filtro retorna o próprio valor na primeira vez
que é executado.]],
parameters = {
{ name = "Valor", type = "REAL" },
},
results = {
{ name = "Resultado", type = "REAL" },
},
code = [===[ function(self, valor)
local t_atual = time()
self._t_1 = self._t_0
self._t_0 = t_atual
local y
if (self._y_1 == nil) then -- primeira execução
if (self.x_0) then
y = self.v_init
else
y = valor
end
else
local K = self.k
local T = self.t
local dt = self._t_0 - self._t_1
y = (K*valor*dt+T*self._y_1)/(T+dt)
end
self._y_1 = y
return y
end ]===],
},
},
}
class{ id = "bloco_media", name = "Bloco Média", group = "Blocos de Cálculo",
bases = {"bloco_calculo"},
description = [[Bloco que executa função média sobre amostras informadas.]],
attributes = {
{ id = "amostras", name ="Amostras", type = "amostras", access ="g", description =
[[Histórico de valores inseridos.]],
},
{ id = "periodo", name = "Período", type = "REAL", access = "", description =
[[Período de amostras, em segundos, que deve ser considerado.]],
},
},
code = [====[
--function _CLASS:init() end
]====],
methods = {
{ id = "iniciar", name = "Iniciar",
description = [[Iniciar a execução do filtro.]],
parameters = {
},
results = {
},
code = [===[ function(self)
self.amostras:iniciar()
self:apagar()
end ]===],
},
{ id = "validar", name = "Validar", description =
[[Informa se o bloco tem amostras o suficiente para realizar uma execução.]],
parameters = {
},
results = {
{ name = "Valido", type = "BOOLEAN" },
},
code = [===[ function(self)
return self:consultar() and true or false
end ]===],
},
{ id = "consultar", name = "Consultar", description =
[[Informa o valor do filtro na última execução.]],
parameters = {
},
results = {
{ name = "Resultado", type = "REAL" },
},
code = [===[ function(self)
return self._ret
end ]===],
},
{ id = "calcular", name = "Calcular", description =
[[Calcula a média dos valores informados.]],
parameters = {
{ name = "Valor", type = "REAL" },
},
results = {
{ name = "Resultado", type = "REAL" },
},
code = [===[ function(self, valor)
self.amostras:inserir(valor)
local historico = self.amostras:obter_historico(self.periodo)
return average(historico)
end ]===],
},
},
}
class{ id = "tempo_morto", name = "Tempo Morto", group = "Blocos de Cálculo",
bases = {"bloco_calculo"},
description = [[Bloco de cálculo que retorna, ao executaro, o valor com atraso.]],
attributes = {
{ id = "atraso", name = "Atraso", type = "REAL", access = "gs", description =
[[O valor de tempo morto (em segundos).]],
},
{ id = "referencia", name = "Referência", type = "REAL", access = "gs", description =
[[O valor inicial da função até atingir o tempo morto.]],
},
},
methods = {
{ id = "iniciar", name = "Inicializar", description =
[[Inicializa o tempo morto, apagando quaisquer valores históricos que existam.]],
parameters = {
},
results = {
},
code = [===[ function(self)
self._oldest = nil
self._newest = nil
self:apagar()
end ]===],
},
{ id = "calcular", name = "Calcular", description =
[[Aplica o tempo morto ao valor de entrada.
Esta função cria uma defasagem nos valores fornecidos, retornando a referência
durante o tempo morto especificado.
Após passado o tempo morto definido, os valores fornecidos anteriormente
começam a ser retornados. O valor retornado é o valor cujo momento de
inclusão tenha sido o mais próximo, mas não menor, que o tempo morto.
Todos os valores armazenados associados a tempos anteriores ao valor
retornado são automaticamente descartados.
Dado esse critério, caso a execução desta função seja feita em uma
freqüência variável, valores armazenados podem ser descartados sem
nunca serem retornados.]],
parameters = {
{ name = "Valor", type = "REAL" },
},
results = {
{ name = "Resultado", type = "REAL" },
},
code = [===[ function(self, v)
local t_atual = time()
self:inserir(v, t_atual)
return self:consultar()
end ]===],
},
{ id = "inserir", name = "", description = [[]],
parameters = {
{ name = "Valor", type = "REAL" },
{ name = "Tempo", type = "REAL" },
},
results = {
},
code = [===[ function(self, v, t)
local amostra = {
valor = v,
tempo = t,
}
if self._oldest then
self._newest.next = amostra
else
self._oldest = amostra
end
self._newest = amostra
end ]===],
},
{ id = "consultar", name = "", description =
[[Varre as amostras coletadas da mais antiga para a mais recente até atingir o tempo mais próximo do atraso.]],
parameters = {
},
results = {
},
code = [===[ function(self)
local t_atual = time()
if (not self._oldest.tempo) or (t_atual - self._oldest.tempo < self.atraso) then
return self.referencia
else
local amostra = self._oldest.next
while (amostra and ( (t_atual - amostra.tempo) >= self.atraso) ) do
self._oldest = amostra
amostra = amostra.next
end
return self._oldest.valor
end
end ]===],
},
},
}
include('lib-amostras-1_0.mpam')
include('lib-blocos-1_0.mpam')
class{ id = "REAL_POINT_DIAG", name = "Diagnóstico de Ponto Real", group = "Diagnósticos",
bases = { "REAL_POINT" }, description =
[[Classe que associa um ponto real com um conjunto de blocos de cálculo e códigos de diagnóstico para tratamento do seu valor.]],
attributes = {
{ id = "pv", name ="Variável de Processo", type = "REAL_POINT", access ="r", description =
[[Variável de processo sobre a qual diagnósticos serão realizados.]],
},
{ id = "blocos_calculo", name ="Blocos de Cálculo", type = "bloco_calculo[]", access ="g", description =
[[Lista de blocos de cálculo usados para o tratamento do sinal.]],
},
{ id = "codigos", name ="Códigos", type = "STRING[]", access ="g", description =
[[Lista de códigos de diagnósticos que devem ser realizados para a variável em cada leitura.
Em uma leitura simples, apenas o diagnóstico correspondente ao primeiro código é retornado.
Sendo assim, os demais devem ser obtidos explicitamente pelo ]],
},
},
code = [====[
function _CLASS:init()
self._rets = {}
end
function _CLASS:read()
for c, code in ipairs(self.codigos) do
self._rets[c] = self:executar(code)
end
return self._rets[1]
end
]====],
methods = {
{ id = "iniciar", name ="Iniciar", description =
[[Inicia atemporização estabelecendo um tempo limite para sua conclusão.]],
parameters = {
},
results = {
},
code = [===[ function(self)
for b, bloco in ipairs(self.blocos_calculo) do
bloco:iniciar()
end
end ]===],
},
{ id = "consultar", name ="Consultar", description =
[[Consulta o resultado do diagnóstico correspondente ao índice na lista de códigos configurada.]],
parameters = {
{ name = "Índice Código Diagnóstico", type = "INTEGER" },
},
results = {
},
code = [===[ function(self, i)
return self._rets[i]
end ]===],
},
{ id = "executar", name ="Executar", description =
[[Código de sequencia de identificadores de blocos que devem ser executados para atualizar e retornar o diagnóstico da variável de processo.]],
parameters = {
{ name = "Código Diagnóstico", type = "STRING" },
},
results = {
{ name = "Resultado", type = "REAL" },
},
code = [===[ function(self, code)
local blocos
if code then
blocos = {}
for nome in (code or ""):gmatch("([^\+]+)\+?") do
blocos[#blocos+1] = self:obter_bloco(nome)
end
else
blocos = self.blocos_calculo
end
local val = self.pv:read()
for b, bloco in ipairs(blocos) do
val = bloco:executar(val)
end
return val
end ]===],
},
{ id = "obter_bloco", name ="Obter Bloco", description =
[[Retorna o primeiro bloco cujo nome casa com padrão de nome passado por parâmetro.]],
parameters = {
{ name = "Padrão de Nome", type = "STRING" },
},
results = {
{ name = "Bloco", type = "bloco_calculo" },
},
code = [===[ function(self, namepat)
for b, bloco in ipairs(self.blocos_calculo) do
if tostring(bloco):match(namepat) then
return bloco
end
end
end ]===],
},
},
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment