Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Sistema de Control de Flujos A Lazo Cerrado Mediante Controlador Lineal Basado en Imagenes PDF
Sistema de Control de Flujos A Lazo Cerrado Mediante Controlador Lineal Basado en Imagenes PDF
Facultad de Ingenierı́a
TESIS DE GRADO
Presentada por:
Pablo Daniel Roca
Octubre de 2013
Resumen
El presente trabajo estudia los sistemas de control de flujos a lazo cerrado de naturaleza predic-
tiva. En particular, se centra el estudio en la definición de un sistema basado en imágenes que
controle el flujo de un fluido en el experimento prototipo del escurrimiento sobre un cilindro, con
posibilidad de implementación en tiempo real. Se elige este escenario por tratarse de una expe-
riencia de oscilación autosostenida por el flujo, y por lo tanto, con caracterı́sticas fuertemente
no lineales que deben ser sobrellevadas por el controlador lineal en desarrollo.
Se define un sistema que estabiliza la estela del cilindro utilizando el procesamiento de
imágenes. A tal fin, se realiza una simulación numérica sobre el flujo del fluido a través del
cilindro. Se inyectan trazadores pasivos en el escurrimiento y se utilizan imágenes para medir la
concentración e identificar el modelo AutoRegressive with eXtra inputs (ARX) que caracteriza al
sistema fı́sico. Se implementa un algoritmo Generalized Predictive Controller (GPC) que calcula
la actuación necesaria para estabilizar la estela a través del agregado de cantidad de movimiento
tangencial a las paredes del cilindro mediante la inyección de plasma.
El algoritmo de control es ejecutado desde el código de simulación que queda a la espera de
una respuesta para continuar con el procesamiento. Para ello, se crean interfaces de comunicación
entre el simulador (Fortran) y el controlador (C++ y Matlab). Tanto el diseño de la experiencia
como el desarrollo de los algoritmos se realiza con el objetivo de ser utilizados en un entorno
de ejecución real en trabajos futuros. Se realizan algunos avances en el uso de General-Purpose
Computing on Graphics Processing Units (GPGPU) mediante CUDA C/C++ sobre sectores del
código que requieren alto paralelismo a fin de aumentar la performance en posibles escenarios
de tiempo real.
La efectividad del sistema de control y del algoritmo creado son comprobadas mediante di-
versas simulaciones numéricas para distintos escenarios. Los datos experimentales son analizados
y expuestos junto a posibilidades de mejora para trabajos futuros.
Palabras clave: control, fluidos, lazo cerrado, feedback, ARX, GPC, cilindro, estela, identifica-
ción de sistemas, simulación, controlador lineal, no-linealidades
1
Índice general
1 Introducción 8
2.1 Introducción 12
2.6 Conclusiones 35
3.1 Introducción 37
3.6 Conclusiones 58
4 Ensayo Experimental 59
4.1 Introducción 60
Apéndices 112
E Publicaciones 127
E.1 Anales de la AFA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
E.2 Physics of Fluids . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7
Parte 1
Introducción
8
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
El control del movimiento de fluidos es una disciplina de gran importancia para la industria
y la ciencia. Los objetivos de la teorı́a clásica de control como el seguimiento de un valor de
referencia o el rechazo frente a perturbaciones son considerados en aplicaciones especı́ficas de
fluidodinámica como la reducción del arrastre o la supresión de inestabilidades que guardan gran
interés por su uso práctico.
El presente trabajo introduce avances en el ámbito del control de la dinámica de los fluidos
presentando un sistema de control automático lineal que pueda ser utilizado en sistemas no
lineales y que posibilite su uso fuera de condiciones de laboratorio. A tal fin, se utilizan conceptos
de teorı́a de control e identificación de sistemas que en conjunto permiten definir un algoritmo
genérico, independiente de la experiencia.
Se escoge al escurrimiento sobre un cilindro como caso de estudio para realizar las simula-
ciones pertinentes debido a su importancia como experiencia prototipo para diversos fenómenos
de fluidodinámica. Asimismo, su naturaleza de oscilador autosostenido asegura la existencia
de marcadas no-linealidades que permiten verificar la bondad del controlador lineal propuesto.
Mediante consideraciones generales de control de fluidos, se establece el objetivo de control y
esquema de actuación particulares para dicho escenario. Se propone la inyección de filamentos
de un trazador pasivo, como el humo, que permite demarcar la estela del cilindro y detectar sus
cambios mediante el diagnóstico por imágenes. El objetivo de control establece que el escalar
inyectado adopte un patrón determinado que garantice la disminución de fluctuaciones cercanas
al cilindro.
Si bien existen trabajos de control de fluidos orientados a experiencias de control con retroali-
mentación (también conocido como control a lazo cerrado) utilizando imágenes, la obtención de
información se realiza mediante técnicas de Particle Image Velocimetry (PIV) donde se calcula
la velocidad instantánea de partı́culas entre dos imágenes sucesivas. En contraposición, el me-
canismo propuesto permite obtener la información del estado instantáneo del sistema mediante
una única imagen. Se reduce ası́ el tiempo de transferencia de datos necesarios para la toma de
decisiones y la necesidad de incurrir en calibración de complicados sistemas de cámara, lasers
potentes para iluminar la zona ni técnicas complejas de inyección de trazadores. Esto amplı́a la
posibilidad de uso en experiencias reales.
El controlador desarrollado utiliza técnicas de lazo cerrado estudiadas en Teorı́a de Control
para permitir un ajuste automático de la actuación. Este esquema requiere una representación
matemática adecuada, en este caso mediante la identificación del sistema con un modelo de
caja negra. Ya establecidos el marco de control y modelizada la experiencia se aplican técnicas
de generación de plasma en las paredes del cilindro para controlar la estela. Este método es
estudiado en el campo del control de fluidos por los beneficios potenciales de su rápido tiempo
de respuesta y carencia de componentes mecánicos.
9
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
particularidades del modelo a simular y se especifican los algoritmos diseñados para la identifi-
cación del sistema y su control.
La Parte 4 incluye el detalle de la simulación numérica de la experiencia, la definición del
mallado, la identificación del sistema, el desarrollo del controlador y su integración con el si-
mulador. Los resultados de la aplicación de control son expuestos y analizados para validar la
efectividad del controlador. Luego, se realizan distintas pruebas con escenarios no ideales, es
decir con la existencia de ruido, para analizar robustez del algoritmo. De la misma forma se
verifica la adaptabilidad del controlador realizando simulaciones con cambios en las condiciones
de entrada que definen la dinámica de la experiencia.
Por último, la Parte 5 resume las conclusiones del estudio realizado y sintetiza las perspectivas
futuras y posibilidades de mejora.
Los distintos apéndices incluyen el código fuente utilizado para la identificación de siste-
ma y el algoritmo de control ası́ como las aplicaciones y scripts auxiliares empleadas para el
análisis de la información. Se incluyen además avances experimentales en sistemas de control
adaptativos, empleo de cámaras digitales y paralelización en General-Purpose Computing on
Graphics Processing Units (GPGPU) sobre identificación de sistemas. Aunque estos casos no
forman parte del controlador utilizado, muestran grandes ventajas de implementación e incre-
mentos de performance importantes respecto de los algoritmos usuales y, por lo tanto, deben
ser tenidos en cuenta en experiencias real-time del sistema de control. Como agregado, se in-
cluyen las publicaciones presentadas en la los Anales de la Asociación Fı́sica Argentina (AFA)
y American Institute of Physics para la revista Physics of Fluids producto de la investigación
realizada durante el presente trabajo.
10
Parte 2
11
2.1 Introducción
12
2.2 Teorı́a de Control
2.2.1. Fundamentos
El término control posee dos acepciones básicas: comprobar algún suceso o dominarlo. En
la Teorı́a de Control, el primer significado se entiende como la actividad de verificar o validar
que cierta representación matemática de un suceso fı́sico tiene un comportamiento satisfactorio
frente a la realidad. La segunda acepción implica la capacidad de actuar o llevar a cabo ciertas
decisiones para garantizar el comportamiento del suceso en cuestión. En otras palabras, controlar
supone la aplicación de cierto plan para conseguir un orden determinado.
La teorı́a de control involucra el trabajo interdisciplinario de matemáticos con especialistas en
diversas ramas de la ingenierı́a tales como la mecánica, electrónica, aeronáutica e informática.
Se estudia la forma de influir sobre la dinámica de distintos sistemas mediante técnicas de
medición, comparación, cálculo y corrección. Los conceptos básicos de la teorı́a de control como
retroalimentación, fluctuaciones y optimización pueden encontrarse en situaciones cotidianas y
fenómenos naturales que, lejos de los planteos matemáticos y complejidades ingenieriles, resultan
simples e intuitivos [21, 1].
El concepto de retroalimentación (o feedback ) es utilizado en la teorı́a de la evolución de
las especies, propuesta por C. Darwing (1805-1882), para explicar el mecanismo de selección a lo
largo de perı́odos largos de tiempo que resulta responsable de la evolución. De la misma forma,
el feedback resulta importante en modelos estadı́sticos de epidemiologı́a y población como el
propuesto por V. Volterra (1860-1940) para explicar las variaciones en la población de peces a
lo largo del tiempo y su relación con la cantidad de predadores con los que comparten el hábitat
[8]. Dicho modelo, que es uno de los primeros intentos exitosos de explicación de población
biológica, presenta un mecanismo natural de feedback para mantener el equilibrio de ambas
especies y determinar como inciden los cambios de población de una sobre la tasa de crecimiento
de la otra.
Otro concepto clave de la teorı́a de control es la necesidad de fluctuaciones que refiere a la
dificultad de imponer un estado deseado de forma brusca. Por el contrario, resulta más eficiente
aceptar los cambios graduales y oscilaciones que presentan el sistema en estudio. Por ejemplo,
el conductor de un vehı́culo en movimiento conoce los riesgos de un frenado brusco y opta en su
lugar por reducir la velocidad aplicando el freno de forma incremental hasta detener el vehı́culo.
Los primeros registros de esta idea pertenecen al ingeniero mecánico H.R. Hall al identificar al
modelo de control de presión en máquinas de vapor como una aplicación de la ley económica de
oferta y demanda [29]:
“Es curioso el hecho que mientras economistas polı́ticos reconocen que por la acción de
la ley de oferta y demanda deben existir fluctuaciones, esto no es generalmente reconocido por
mecánicos en sus esfuerzos de controlar el motor a vapor. El objetivo de los ingenieros mecánicos,
como el de los economistas polı́ticos, no debe ser el deshacerse de todas las fluctuaciones [...] sino
disminuirlas tanto como sea posible, aún dejándolas lo sufientemente altas como para mantener
13
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
su poder regulatorio.”
Por último, el concepto de optimización resulta clave para entender el objetivo del control.
Esta idea es estudiada como rama matemática cuya metodologı́a base es definir las variables del
problema, un funcional que se desea maximizar o minimizar expresado en dichas variables y las
técnicas que permitan encontrar la condición óptima para el planteo. Este esquema es aplicado
en actividades diarias como ajustar el gas de una cocina para mantenerlo al mı́nimo necesario
que garantice el hervor del agua o determinar la cantidad de riego que requiere un cultivo para
conseguir la humedad necesaria sin desperdiciar agua.
Dado que las primeras aplicaciones formales de control se centran en problemas de ingenierı́a,
la terminologı́a empleada hereda palabras utilizadas en la industria. A continuación se definen
conceptos básicos de amplio uso en la teorı́a de control [47] que son referidos en el presente
trabajo:
Proceso: conjunto progresivo de operaciones o cambios tanto naturales como artificiales que
se suceden de alguna forma y cuyos efectos determinan un resultado o fin. Se puede decir
que toda sucesión de operaciones que desea ser controlada es un proceso.
Planta: dispositivo fı́sico, pieza de algún equipamiento o conjunto de máquinas que opera con
algún objetivo particular que se desea controlar.
Actuador: elemento fı́sico de la planta que frente a una señal indicada por el controlador puede
operar sobre la fı́sica que rige el proceso.
Variables Manipuladas: cantidad o condición que puede ser modificada por el controlador
y cuyos cambios rigen la operación del actuador. También se las conoce como señales
de entrada del proceso o, simplemente, entradas. Se trata de variables independientes
del proceso que pueden incidir en las variables dependientes, que usualmente se desean
controlar.
Perturbaciones: señales que perjudican la señal de salida de un sistema. Pueden ser generadas
dentro del sistema (internas) o fuera del mismo (externas).
Pasivo: no emplean energı́a externa al proceso bajo estudio. Las posibilidades de modificaciones
sobre el controlador son, por lo general, limitadas.
Activo: utilizan energı́a externa para activar los actuadores y controlar el proceso por lo que
son más versátiles.
Predeterminado: los parámetros de actuación son fijos e independientes del estado del
proceso. Admite ajustes mediante cambios manuales aplicados por el humano.
Reactivo: la actuación es definida por un algoritmo de control que reacciona frente a
mediciones realizadas sobre variables del proceso y del entorno.
El sistema de control puede utilizar sensores dispuestos en la planta para tener información
sobre las variables controladas o fuera de ella para adquirir datos que permitan modelar las
perturbaciones que recibe el sistema. Por ejemplo, en un sistema de control de temperatura
para un horno de cocina, suponiendo que la variable controlada es la temperatura del centro
del horno, un sensor de temperatura colocado en las paredes internas puede proveer (o aproxi-
mar) dicho valor. Por el contrario, un sensor de temperatura colocado en el exterior del horno
provee información importante sobre las perturbaciones que sufre el sistema. En escenarios de
control pasivo o predeterminado esta información no es usada por el controlador pero resulta
indispensable para plantear un control reactivo.
Al emplear algoritmos en controladores reactivos se utiliza el concepto de ciclo (bucle o loop)
para referirse a los pasos repetitivos que ejecuta el controlador estando en régimen. En este
contexto, si se utilizan valores presentes o pasados de las variables controladas para calcular la
actuación de los próximos pasos se habla de un ciclo de control con feedback. Por el contrario, si se
utiliza información sobre las perturbaciones externas (que posiblemente aún no hayan afectado
a la planta) se trata de un ciclo de control con prealimentación (feedforward ). El primer caso es
el más común y recibe la denominación de control a lazo cerrado (closed-loop control ) debido al
dibujo esquemático que lo representa (Fig. 2.2.2). En contraposición, se suele hablar de control
por lazo abierto (open-loop control ) para los casos de control predeterminado, donde no existe
lazo.
Esto da lugar a una clasificación de acuerdo al ciclo de control que se resume a continuación:
Lazo Abierto (open-loop): guarda relación con el control activo predeterminado en el sentido
de que una vez definida la actuación se requiere la intervención humana para modificarla
(Fig. 2.2.1).
Lazo Cerrado (closed-loop): también conocido como ciclo con retroalimentación (feedback )
ya que utiliza información sobre el estado del sistema para plantear acciones correctivas
respecto de los valores de referencia deseados (Fig. 2.2.2).
Con Prealimentación (feedforward ) se emplea información del entorno del sistema para ajus-
tar la actuación y anticipar los efectos de las perturbaciones sobre la planta (Fig. 2.2.3).
Figura 2.2.1: Esquema de control a lazo abierto. No se utiliza información sobre el estado del sistema para
determinar la actuación.
Figura 2.2.2: Esquema de control a lazo cerrado. Se utiliza feedback del sistema bajo estudio para determinar las
diferencias que existen respecto de los valores de referencia esperados. Con este error respecto de lo esperado, el
controlador calcula los valores de entrada que deberı́an corregir la salida.
Figura 2.2.3: Controlador feedforward. Se utiliza información sobre las perturbaciones para prealimentar al con-
trolador y actuar de forma anticipada a que los efectos sean notorios en la salida del sistema.
N. Wiener (1894-1964) quien introduce el término en 1948 como resultado de diversos trabajos
en ciencia cognitiva pero influenciado por los avances de la época en técnicas de comunicación,
mecánica estadı́stica y computación junto a su relación con procesos de aprendizaje, lenguajes,
información, sistemas auto-organizados entre otros campos de la ciencia. Al afirmar que las
máquinas eran sistemas capaces de aprender (o learning machines) al igual que los animales
[68] se amplı́a el horizonte de aplicaciones para la teorı́a de control. Los nuevos ámbitos de
aplicación -entre los que se encuentra la inteligencia artificial, automatismo, ciencias de la visión,
teorı́a de la conversación o neurociencia- otorgan grandes expectativas a futuro aún en nuestros
dı́as. La computación toma un rol fundamental en este nuevo campo que frente a necesidad
de precisión numérica, manejo de volúmenes importantes de datos y velocidad en el cálculo,
evoluciona cambiando sus expectativas de uso de una compleja máquina calculadora hacia el
ámbito natural para sistemas de propósito especı́fico.
Figura 2.2.4: Esquema de un controlador a lazo cerrado PID. Se puede observar el efecto individual del error, su
integral y su derivada en el dominio del tiempo sobre la actuación del controlador.
donde x(t) es el vector de variables internas del sistema también conocido como vector de
estado, u(t) es el vector de las variables manipuladas e y(t) es el vector de variables controladas.
Las matrices A, B y C describen las interconexiones en la dinámica del sistema. Usando esta
representación, Kalman formalizó las nociones de controlabilidad y observabilidad empleándolas
en la propuesta de una ley de control con feedback de la forma:
u(t) = −K ẋ(t)
dondeR la matriz de feedback, K, debe ser determinada para minimizar cierta función objetivo
∞
J = 0 (xT Qx + uT Ru)dt siendo Q y R matrices de pesos constantes. Una vez determinada
K, se asume que no varı́a y por este motivo se habla de feedback estático. Este esquema de
controlador es conocido como Linear Quadratic Gaussian (LQG) y establece las bases para los
nuevos algoritmos de esta etapa de la Teorı́a de Control.
esquema clásico de control PID. Los motivos principales para la investigación de nuevas técnicas
se pueden encontrar en las necesidades económicas fijadas por la industria y de difı́cil aplicación
en los algoritmos de control clásicos:
Posibilidad de trabajo tan cercano a las restricciones como sea posible (usualmente vincu-
lado con la maximización del empleo de recursos industriales)
Ventana temporal del proceso que toma en cuenta las variables controladas y manipuladas
dentro de cierto horizonte de predicción.
Los nuevos algoritmos de control provenientes de la inversión industrial entregan peso teórico
en los conceptos de predicción y suceden al LQG con mayor éxito. El primer caso es provisto por
J. Richalet (1936-) con Model Predictive Heuristic Control (MPHC o también conocido como
IDCOM debido al primer sistema de software que lo adoptó) que utiliza un modelo discreto
de respuesta al impulso finito para describir la relación entre entradas y salidas. Este modelo
es conocido como Finite Impulse Response (FIR) y relaciona y(t) con u(t) mediante ciertos
coeficientes de peso, hi , que deben ser determinados. La representación matemática en tiempo
discreto de dicho modelo es:
XN
y(k) = hi u(k − i)
i=1
El modelo elegido vincula cierto paso del tiempo k de la salida únicamente con la entrada
de hasta N pasos de tiempo previos. La determinación de las hi se realiza mediante algoritmos
de estimación que requieren un ajuste constante mediante comparación con mediciones reales
de la planta[51]. Se utiliza al ciclo de control como punto para corregir un modelo que requiere
revalidación continua por ser “inevitablemente imperfecto” [53].
Quizás el aporte conceptual más importante de este tipo de control es la trayectoria de
referencia (Fig. 2.2.5) que define el camino deseado para los estados futuros de la planta. Este
camino, es interpretado como el comportamiento deseado de la planta convergiendo al valor de
referencia final. Calculando la trayectoria deseada se puede determinar la actuación necesaria
para cada paso y entender la necesidad de un mecanismo de fluctuación para evitar cambios
bruscos del estado y sus complicaciones. Por último, este esquema enfatiza la relación Acción
→ Comportamiento que, incorporando experiencia de campo y conocimientos sobre el proceso
en estudio, se puede extender a Comportamiento Deseado → Acción → Comportamiento
[53].
Figura 2.2.5: Posible trayectoria de referencia para la variable controlada (CV) en su camino para alcanzar la
referencia final (Set-point). Se asume que se posee la información pasada y del paso de tiempo actual (n) que
permite predecir la salida del proceso h pasos hacia el futuro gracias a un modelo matemático preestablecido (Sm ).
Definiendo el grado de aceptación para la diferencia de error entre el proceso y el Set-point ((n)) o la variación
del proceso (∆p) h pasos en el futuro, se puede calcular el valor de variable manipulada (MV) necesario (basada
en Richalet, 2009) [53].
En los años subsiguientes aparecen nuevos sistemas de control entre los que se destacan Dy-
namic Matrix Control (DMC) y Shell Multivariable Optimizing Control (SMOC) por los avances
conceptuales que aplicaron al MPHC. El DMC, introducido en 1980, mantiene un esquema si-
milar al MPHC pero modela al sistema mediante la respuesta al escalón en lugar del impulso y
provee tratamiento de restricciones a las variables controlada (aunque no es incluido de forma
orgánica sino agregado ad-hoc) [44]. El esquema SMOC, presentado en 1988 como un “puente
entre modelos en espacio de estados y los algoritmos MPC”, permite incluir restricciones sobre
variables de salida agregándolas a la función objetivo. En efecto, esto es posible para restriccio-
nes débiles (también llamadas soft) y para el establecimiento de un valor de referencia (setpoint)
donde se minimiza la violación penalizando en la función objetivo, pero no para restricciones
duras (hard ) que requieren un tratamiento particular (Fig. 2.2.6).
Figura 2.2.6: Tipos de restricciones en las salidas. Tomando el caso de una única salida, se gráfica su magnitud
(eje vertical) a lo largo del tiempo (eje horizontal) junto con los valores restringidos (zonas rayadas). Se puede
observar el efecto directo de las restricciones la salida para el caso hard y el impacto en la función objetivo para
los casos soft y setpoint (basado en Qin, 2003) [51].
A pesar del éxito de las nuevas generaciones de controladores predictivos ninguno de ellos
podı́a ser catalogado como de propósito general y ser aplicados tanto en situaciones de planta
simples como en sistemas complejos. En particular, éstos últimos suelen requerir el ajuste fino de
los parámetros del controlador que resulta muy sensible frente a los supuestos sobre el orden del
modelo y el tiempo de respuesta al control (o dead-time). En particular, el dead-time representa
la demora entre una modificación en la variable manipulada y la aparición de los primeros efectos
en la variable controlada.
En 1987 se introduce el Generalized Predictive Controller (GPC) [14, 15] que se centra en
calcular los valores de actuación futuros tales que luego de cierto tiempo no sufran variaciones,
es decir se estabilicen en torno de cierto valor definitivo de actuación. Para ello se predicen las
salidas futuras en respuesta a las entradas calculadas a través de una función objetivo y un
horizonte de tiempo que limita las variaciones.
Esta técnica trajo beneficios en términos de robustez y simplicidad de cálculo, a la vez que
proveyó un mecanismo de auto-ajuste (o self-tuning) que permite al algoritmo sobreponerse a
errores en supuestos sobre orden o dead-time. GPC utiliza el modelo Controlled Auto-Regressive
and Integrated Moving-Average(CARIMA) que vincula valores actuales y pasados de entradas
y salidas según:
El área de control de fluidos es una disciplina de gran crecimiento durante los últimos años
debido a su importancia en el ámbito académico y de ciencia aplicada. La maduración relativa
de las distintas disciplinas cientı́ficas contribuyó en esta rama proveyendo conocimientos clave
y descubrimientos que permiten predecir un futuro muy promisorio [7].
En busca de una definición general del control de fluidos, es posible citar a J. Flatt (1961)
que brinda una descripción para el control en fenómenos de capa lı́mite que se puede extender
fácilmente a otros escenarios:
“El control de capa lı́mite incluye cualquier mecanismo o proceso a través del cual la capa
lı́mite del flujo de un fluido es forzada a comportarse de forma diferente de como normalmente
se hubiera desarrollado [...]”
“Un objeto A∗ es un modelo del objeto A para el observador B, si B puede emplear A∗ para
responder cuestiones que le interesan acerca de A.”
De esta definición se desprende una importante reflexión: el detalle del modelo respecto del
objeto depende del detalle de las observaciones que se pretendan realizar. Aún más, el grado de
exactitud del modelo respecto del objeto modelado dependerá de las necesidades del estudio.
Es conocido que el estudio de fenómenos fı́sicos requiere el uso intensivo de herramientas
matemáticas. En este contexto, el empleo de modelos matemáticos para representar sistemas
24
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
donde las funciones φi (x) representan los n modos espaciales y las ai (t) indican los coeficientes
temporales de cada modo. Los φi (x) son obtenidos mediante la resolución de un problema
de autovalores sobre un conjunto de observaciones de u(x, t) y definen una base ortogonal de
vectores.
El conjunto de ecuaciones del modelo de orden reducido es obtenida al utilizar los n elemen-
tos de la base en una una proyección de Galerkin sobre las ecuaciones de Navier-Stokes. Este
procedimiento provee un sistema de ecuaciones diferenciales ordinarias, compuesto de tantas
ecuaciones como modos retenidos luego del análisis inicial. Sin embargo, el sistema obtenido
puede divergir prematuramente o durante el perı́odo de entrenamiento por la anulación del fac-
tor de amortiguamiento que ofrecen los modos más altos y que fue suprimido por el truncado de
modos. Aunque este comportamiento presenta grandes restricciones, existen algunas estrategias
para evitarlo [3].
Los modos de POD usualmente exhiben múltiples frecuencias y resulta difı́cil asociar su
estructura espacial con las caracterı́sticas observables del flujo. Como consecuencia, distintos
autores se han preguntado sobre la correlación de dichos modos con magnitudes fı́sicas medibles.
Dado que los modos POD no pueden ser asociados a estructuras coherentes del flujo en todos los
casos, la base de funciones utilizadas para la proyección puede no ser lo suficientemente amplia
para expresar las diversas condiciones del flujo. Se conocen esfuerzos recientes en mejorar la
calidad de la base y remediar esta limitación [58].
Otro inconveniente de este esquema es la limitación para incluir estı́mulos externos, tanto los
asociados como actuaciones de control como aquellos que resultan de perturbaciones autónomas
y fuerzan el estado del flujo. Dentro de las bondades del esquema POD sobresale la posibilidad
de definir fácilmente la función objetivo del control. Cuando se desea minimizar las fluctuaciones
del flujo, es posible plantear la minimización del total de energı́a asociada a las fluctuaciones
sobre un sector del flujo. Esa magnitud es determinada con los coeficientes temporales de los
modos (llamados chronos) [10].
Alternativamente, existen los Modelos de Orden Reducido (Reduced Order Models o ROM)
que consideran los llamados modos globales, pero esta estrategia no presenta buenos resultados
para todas las situaciones [5]. Uno de los requerimientos más restrictivos de los esquemas ROM
es la necesidad de disponer del campo de velocidades del flujo para generar el modelo. Desde el
punto de vista de las aplicaciones prácticas, la obtención del campo de velocidades en tiempo
real constituye un gran impedimento. Es por ello que este tipo de modelos se limita a simula-
ciones numéricas o experiencias en túneles de viento equipados con sistemas de Particle Image
Velocimetry (PIV) de mayor o menor complejidad. Incluso en estos casos existen problemas
asociados con la robustez del modelo frente a cambios en el dominio.
AR
Una de las metodologı́as de identificación de sistemas más utilizadas se basa en relaciones
auto-regresivas (AutoRegressive o AR) entre los valores el estado del sistema en el tiempo actual
y pasados. El ejemplo más simple de un modelo AR consta de la siguiente relación entre variables:
p
X
y(k) = αi y(k − i)
i=1
ARX
Otro ejemplo de modelo autorregresivo contempla la existencia de entradas externas al sis-
tema que condicionan el comportamiento de las variables observables del problema fı́sico en
estudio. Las entradas actúan como variables independientes del problema mientras que las sali-
das son dependientes o ligadas. En estos casos se habla de un modelo AutoRegresive with eXtra
inputs (ARX) que en contextos de econometrı́a se conoce como AutoRegresive with eXogenous
variables [42]. Se plantea la siguiente relación entre variables para este tipo de modelos:
donde u(k) representa la variable externa independiente (en los sistemas bajo estudio será la
variable de control), Na y Nb son los lı́mites de auto-regresión para los coeficientes ai y bi
respectivamente. En este modelo se admite la dependencia de y(k) respecto de u(k) para el
tiempo actual y tiempos pasados. Esta dependencia resulta evidente al despejar la salida del
tiempo actual (y(k)) y observar que para predecir dicho valor, es necesario contar con valores
previos de y, valores previos de u y el valor de u en el tiempo actual (u(k)).
Los ejemplos anteriores contemplan la existencia de variables de entrada y salida únicas; se
trata de sistemas SISO. Para modelos complejos, donde se define para cada paso de tiempo un
vector de estado que incluye los valores de una o más variables observables junto con una o más
variables de control, nos encontramos con sistemas MIMO. En este último caso, las variables u e
y se transforman en vectores (un componente de u por cada entrada y un componente de y por
cada salida, para cada paso de tiempo). Sin cambios en la ecuación, se la puede extender a la
forma matricial para representar ese esquema si entendemos a u(k), y(k) como vectores columna
y ai , bi matrices con dimensiones apropiadas.
Por último, los coeficientes ai y bi se pueden agrupar utilizando una notación reducida:
A(q)y(k) = B(q)u(k)
donde se definen las matrices de polinomios
A(q) = I + a1 q −1 + · · · + aNa q −Na B(q) = b0 + b1 q −1 + · · · + bNb q −Nb
siendo q −1 el operador de corrimiento:
q −n f (k) = f (k − n)
En todos los casos se debe entender la existencia de un término de error e en cualquiera de
los lados de la igualdad que corrige las incertezas que provoca el modelo de caja negra. Este
modelo matemático admite una representación por bloques que se puede observar en la Fig.
2.3.1.
ARMAX
Una extensión del modelo ARX se obtiene al considerar los efectos del ruido blanco y mo-
delarlo con una media móvil. En este caso se plantea el mismo tratamiento que el recibido por
las entradas de control donde se entrega distinto peso al ruido originado en el tiempo actual
frente a tiempos pasados. Dicho peso se modela mediante una matriz de coeficientes (en este
caso C(q)) y utilizando conocimientos previos sobre el orden de magnitud del ruido que acepta
la experiencia. Este esquema se conoce como AutoRegressive with Moving Average and eXtra
inputs (ARMAX) y se define mediante la siguiente relación entre variables:
A(q)y(k) = B(q)u(k) + C(q)e(k)
donde e(k) representa el valor de error o ruido para el tiempo k. Un posible diagrama de bloques
para este esquema puede observarse en la Fig. 2.3.2.
En este caso decimos que el modelo contempla la dinámica de los errores y que estos poseen
un origen común con las entradas u para afectar luego a la salida medida y según puede verse en
el diagrama. Existen otros modelos de la misma naturaleza lineal y auto-regresiva que plantean
una fuente de errores en la medición de y. También resulta factible la modelización de errores en
ambos extremos del proceso con el agregado de una nueva variable de error y su correspondiente
matriz de coeficientes. Es importante remarcar que al aumentar la complejidad del modelo
a utilizar resulta más difı́cil definir la configuración de parámetros apropiada para reflejar al
fenómeno en estudio. Por estos motivos es conveniente utilizar el modelo más simple que otorgue
buenos resultados, escalando de forma progresiva en complejidad de ser necesario.
Este último caso permite obtener la relación contemplada por los modelos ARX y ARMAX
entre los parámetros de entrada y la salida. Es conveniente hacer uso de un amplio espectro
de frecuencia en la actuación de entrenamiento para asegurar que las mediciones recolectadas
son significativas de la relación entre entradas y salidas. El empleo de pulsos en la actuación
sumada a la suposición de linealidad del sistema deberı́a permitir una correcta predicción en
base a entrada de señales diversas, sin embargo no hay un criterio universalmente aceptado para
fijar caracterı́sticas del pulso como duración, amplitud, tiempo de descanso anterior y posterior,
etc.
En todos los casos se trata de experiencias con controladores lineales con resultados
exitosos. Sin embargo, se debe remarcar que las experiencias sobre las que fueron comprobados
no guardan un carácter no-lineal fuerte, por tratarse de sistemas amplificadores de ruido, o tales
efectos son disminuidos por los rangos de amplitud o velocidad utilizados. Como agregado, los
efectos de excluir ciertas no-linealidades del modelo matemático del problema afectan el ajuste
de los parámetros al igual que la definición de una función objetivo como se describe en [30].
Por otro lado, se conocen casos exitosos de controladores no-lineales que implican dis-
tintos grados de complejidad. Como caso de baja complejidad se puede mencionar el control
mediante oscilaciones del cilindro para cancelar las estabilidades de su estela [64], donde se apli-
ca una ley de control no-lineal sobre las mediciones del sensor. Si bien se obtuvieron buenos
resultados, se trata de un esquema particular al caso bajo estudio y de difı́cil extensión a otras
experiencias. Como ejemplo de mayor complejidad se conocen aplicaciones exitosas de redes
neuronales aplicadas mediante rotaciones del cilindro [26]. En esta situación se utilizan estruc-
turas de decisión que no se pueden relacionar con las magnitudes fı́sicas conocidas del problema,
agregando una complicación extra para adaptar el sistema a otras experiencias.
Trabajo Interdisciplinario
Durante siglos, el trabajo cientı́fico basó su progreso en la especialización bajo diversas dis-
ciplinas. La especialización permitió aislar las distintas problemáticas y conseguir una mejor
preparación de los investigadores en cuanto a técnicas y conocimientos particulares. Pero a me-
dida que las ramas cientı́ficas se hicieron más y más complejas, el enfoque de trabajo se tornó más
estrecho y aislado de las otras. Esta tendencia que permitió enormes avances cientı́ficos duran-
te el siglo XX, resolviendo preguntas de gran complejidad e interés, se encuentra en retroceso
dando lugar al auge del trabajo interdisciplinario. Sin embargo, el cambio de enfoque requiere
modificaciones en los hábitos de trabajo y mentalidad de los investigadores que no siempre son
aceptadas. En algunos casos se trata de complicaciones en la implementación mientra que en
otras son preconceptos o barreras mentales donde frases como “fuera de mi área” resultan por
demás frecuentes [7].
Este nuevo enfoque no sólo favorece la rama de control de fluidos sino que sin él serı́a impo-
sible pensar en un crecimiento sostenido de la misma. Las nuevas competencias requieren cono-
cimientos de áreas tales como la fluidomecánica, matemática, ingenierı́a de control, electrónica
y computación que deben cooperar y coordinar esfuerzos. En este sentido, es necesario reforzar
la necesidad de un enfoque amplio, del trabajo interdisciplinario y de un lenguage común entre
las partes.
Aspectos Computacionales
Uno de los aspectos computacionales más importantes del control de fluidos recae en la
gran capacidad de procesamiento que requieren tanto las simulaciones como las experiencias de
laboratorio. En efecto, la discretización de la dinámica de un fluido se expresa con la presión y
el campo de velocidades instantáneo para los puntos que lo conforman. Esto implica una gran
cantidad de valores para describir cada experiencia que fijan de forma indirecta los tiempos de
cómputo necesarios. En este contexto, la discretización temporal y espacial elegidas determinan
las dimensiones del problema mediante un muestreo con cierta peridicidad y la recolección de
cierta cantidad de puntos. En estas condiciones, resulta importante evaluar los requisitos de
procesamiento de los algoritmos de control aplicados.
2.4.1. Discretización
La teorı́a de fluidodinámica tiene sus bases en el estudio de funciones continuas en el tiempo.
Gran parte de su bibliografı́a y avance teórico se sustenta en formulaciones de tiempo continuo
que contrastan con el enfoque de tiempo discreto propuesto en Teorı́a de Control [61].
Lejos de pretender un análisis detallado del impacto que posee la discretización de señales
continuas y el efecto que tiene sobre su espectro en frecuencias [49, 48], es importante entender
32
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
34
2.6 Conclusiones
35
Parte 3
36
3.1 Introducción
En este capı́tulo son presentados los conceptos básicos sobre la experiencia del escurrimiento
sobre un cilindro en 2D, elegida como experimento prototipo para comprobar el algoritmo de
control. Se introduce una caracterización básica sobre las zonas del flujo alrededor del cilindro y
el fenómeno de desprendimiento de vórtices en su estela. Asimismo, se ejemplifican algunos de
los mecanismos de actuación más utilizados para reducir la turbulencia y desprendimiento de
vórtices en el cilindro, a saber: actuación por rotación e inyección de plasma. Luego de lograr
el entendimiento necesario sobre la fı́sica del sistema, se analizan brevemente ciertos casos de
aplicación de control para esta experiencia, haciendo hincapié en los cuerpos romos (o bluff
bodies).
Luego, se define la estructura del sistema en estudio indicando dimensiones y condiciones de
simetrı́a que serán utilizadas en la simulación pertinente. En este contexto se establece la posición
de los inyectores de humo, los actuadores de plasma y los sensores visuales sobre la estela del
cilindro. Conociendo las caracterı́sticas de actuación y sensado previstas para la experiencia,
se definen las variables de entrada y salida que regirán el problema junto con el algoritmo de
identificación del sistema ARX que las vincula en un modelo matemático.
Por último, se define el algoritmo de control a implementar utilizando un controlador predic-
tivo del tipo GPC. Se establece la función objetivo y se resume la importancia de las variables
de ajuste de la experiencia, también conocidas como parámetros de tuning.
37
3.2 Sistema Fı́sico Bajo Estudio
El flujo viscoso externo alrededor de un cilindro representa un flujo prototipo de gran interés
para la fluidodinámica. Buena parte de los estudios de flujos en estelas de bluff bodies (ver sección
3.2.3) han sido realizados sobre cilindros, gracias a su simple geometrı́a y el comportamiento
caracterı́stico del flujo de separación de la capa lı́mite.
Figura 3.2.1: Regiones del flujo perturbado. Se pueden identificar distintas regiones: (i) flujo retardado, (ii) capas
lı́mite formadas en la superficie del cilindro, (iii) capas de corte, regiones de flujo separado y acelerado, (iv) estela
del cilindro.(Zdravkovich (1997) [70].
UD
En base a las dimensiones del problema se define al número de Reynolds, Re = . Siendo
ν
U la velocidad del flujo incidente, D el diámetro del cilindro y ν la viscosidad cinemática. Este
número es de suma importancia en experiencias que poseen movimiento relativos de fluidos
respecto a superficies ya que permite la clasificación y comparación de resultados. En efecto,
ciertas caracterı́sticas en la dinámica de las experiencias son dependientes del Re utilizado y
pueden ser comparadas con otras configuraciones de Re similares aunque las escalas sean muy
diferentes.
38
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
el desprendimiento regular de vórtices con signos opuestos, de una y otra parte del cilindro.
Las sucesivas posiciones que ocupan los vórtices son conocidas como camino de von Kármán.
fD
Se puede definir un número adimensional llamado número de Strouhal: St = , donde U es
U
la velocidad del flujo, f es la frecuencia de desprendimiento de vórtices y D es el diámetro del
cilindro. En la Fig. 3.2.2 se puede observar un camino de von Kármán tı́pico durante experiencias
de laboratorio mientras que la Fig. 3.2.3 muestra la generación de oscilaciones que comienzan
luego de la región de recirculación que desestabilizan al flujo.
Figura 3.2.2: Mecanismo de separación de la capa lı́mite y camino de von Kármán. Izq.: Perfil de un cilindro, lı́neas
potenciales del flujo y distribución de presiones del flujo ideal. Se puede observar la aceleración del flujo entre D y
E junto con su desaceleración entre E y F producto de los cambios de presión. En el flujo real, la fricción viscosa
contra la pared del cilindro se suma a la desaceleración provocando una insuficiencia para seguir la trajectoria
potencial con la consecuente separación en el punto S (Schlichting, 1978) [59]. Der.: Desprendimiento de vórtices
alternados formando el camino de von Kármán.
Figura 3.2.3: Formación de los vórtices von Kármán. En primer término, la estela del cilindro presenta burbujas
de recirculación que se desprenden dando lugar a la generación de vórtices alternados (Perry.1982) [50].
Capı́tulo 3.2. Sistema Fı́sico Bajo Estudio 40
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura 3.2.4: Control por Rotación Oscilatoria. La frecuencia de actuación fue fijada mientras que la amplitud de
rotación (A = Vtangencial /Vf lujo ) se definió en A = 1 y A = 2 respectivamente (Thiria, 2006) [66].
Figura 3.2.5: Control por Rotación Oscilatoria. Continuando con la secuencia anterior, la amplitud de rotación se
aumenta llegando a A = 4 y A = 5 respectivamente [66]. Se puede observar la cancelación de desprendimientos
de vórtices en la estela cercana para oscilaciones de amplitud suficientemente alta (Thiria, 2006).
Figura 3.2.6: Dispositivo de actuación por plasma montado en un cilindro (1) para estabilizar su estela. Se pueden
observar 4 electrodos externos (2) cada uno con su par interno (3). El cilindro posee una protección interna para
evitar descargas (4). El esquema muestra también la zona de descarga de plasma sobre las paredes del cilindro
(5) (Kozlov, 2010) [40].
Como principales virtudes de esta técnica se puede mencionar el escaso volumen y peso,
la simpleza del montaje y la ausencia de partes móviles. Estas caracterı́sticas, que resultan
cruciales en la etapa de implementación sobre aplicaciones reales, superan las posibilidades de
la mayorı́a de los actuadores mecánicos. Otro factor de importancia consiste en los tiempos de
respuesta cortos, del orden de 1ns para el establecimiento de la descarga gaseosa. Estos tiempos
se encuentran muy por debajo de los perı́odos caracterı́sticos y tiempos de muestreo necesarios en
varios escenarios de control de fluidodinámica (ver sección 2.4). En contraposición, los esquemas
de actuación que implican movimientos mecánicos poseen tiempos de respuesta más prolongados
que les restan flexibilidad en experiencias de alta velocidad.
Se decide entonces utilizar este esquema de actuación para la experiencia prototipo bajo
estudio. En particular, es importante destacar las bondades extras que poseen los actuadores
ElectroHidroDinámicos (EHD) [56, 62] donde las corrientes obtenidas son relativamente bajas
y no es necesaria la aplicación de campos magnéticos externos. Este tipo de actuadores son
simulados durante la experiencia y recomendados para su posterior implementación.
Figura 3.2.7: Efecto de la actuación por plasma en la estela de un cilindro (Kozlov, 2010) [40].
Figura 3.2.8: Ejemplos de bluff bodies en aumóviles y UAVs. Tanto el espejo retrovisor como las estructuras de
control de los UAVs son claros ejemplos de elementos que no se pueden integrar al fuselaje debido a la naturaleza
de su uso.
En los ejemplos anteriores, la existencia de bluff bodies implica la aparición de una estela con
desprendimiento de vórtices o turbulencia que puede generar arrastre, ruido y vibraciones.
La relación de la experiencia del cilindro en 2D con el control de proyectiles resulta evidente.
Los proyectiles son claros ejemplos de bluff bodies y el control de propiedades como el arrastre,
sustentación o turbulencias son de suma importancia para la balı́stica. Si bien, este campo de es-
tudio involucra efectos 3D no despreciables, el pasaje a 2D se justifica en escenarios simplificados
o donde reducir el tiempo de cómputo prevalece frente a la exactitud de los resultados.
45
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura 3.3.2: Condiciones de borde, disposición de sensores y actuadores de la experiencia. Se pueden observar
las condiciones de borde en los distintos laterales de la experiencia. Los actuadores son dispuestos sobre la pared
del disco y los sensores se alinean aguas abajo.
El número de Reynolds elegido para la experiencia es Re = 235. Dado que la velocidad del
flujo fue definida al igual que el diámetro del cilindro, se fija el Re ajustando la viscosidad del
fluido a ν = 235−1 , según:
UD 1
ν = =
Re 235
= 235−1 ≈ 4,2553E − 3
Figura 3.3.3: Evolución del número de Strouhal en función del número de Reynolds (Williamson, 1996) [69].
que será de utilidad para operar con las mediciones del paso k de forma matricial.
Se agregan 2 actuadores simétricos en la superficie del cilindro. Los actuadores poseen una
longitud de aproximadamente un 5 % de la circunferencia del cilindro y modelan los dispositivos
de inyección de plasma. La función de los actuadores es la adición sincronizada de cantidad de
movimiento tangencial a la superficie del cilindro. Los actuadores son dispuestos cerca del punto
de separación (Fig. 3.2.2) con el objeto de retardar la separación de la capa lı́mite respecto de
la superficie del cilindro mediante la inyección simétrica de plasma. Estudios previos bajo una
configuración similar demostraron que la inyección constante con una amplitud suficientemente
alta permite estabilizar la estela del cilindro [18]. En este caso, se propone estabilizar la estela
mediante una actuación variable durante el tiempo, que acepte las fluctuaciones naturales del
modelo fı́sico, y que eventualmente requiera una amplitud menor.
El actuador es simulado como en [18] y [28] mediante una condición de borde en una región
localizada del cilindro. La amplitud de la actuación indica la magnitud de velocidad tangencial
inyectada por los actuadores. Se define entonces la variable u(k) como la magnitud de la velocidad
tangencial inyectada por ambos actuadores de forma simultanea en el paso de tiempo k. De forma
análoga a la definición de y(k), se considera una forma más general de la variable de actuación
según u(k) ∈ Rr con r = 1.
A menos que se especifique lo contrario, se considera una inyección ideal del trazador y
mediciones perfectas en los sensores. Asimismo, se asume una velocidad de entrada constante,
uniforme a lo largo del eje de las ordenadas y constante en el tiempo. Esta situación dista
de cualquier escenario de experimentación real donde existen fluctuaciones en los sistemas de
inyección y errores inherentes al esquema de cámaras e iluminación utilizados. Esto permite
centrar la atención en las señales puras provenientes de la dinámica del fenómeno y demorar el
análisis de ruido u otro tipo de perturbaciones. Los efectos de las perturbaciones serán tomados
en cuenta en una etapa posterior a la verificación de la efectividad del algoritmo a lazo cerrado.
En esa etapa se pondrá a prueba la robustez del sistema frente a la existencia de ruido en la
inyección del escalar, en las condiciones de entrada y en las mediciones de los sensores.
tiempo. El sistema identificado permite predecir los estados futuros de las salidas si se asumen
ciertas entradas.
Luego se considera el algoritmo de control que calcula el valor adecuado de u(k) para los yi (k)
medidos en el paso k y anteriores. El valor de actuación calculado buscará cumplir el objetivo
de control que consiste en disminuir la concentración medida en el conjunto de sensores para
forzar un fenómeno de “túnel” del humo sobre el camino formado por los sensores. Este objetivo
puede ser planteado gracias a la disposición de los elementos en la experiencia y su carácter de
simetrı́a respecto del “túnel”.
Para representar la dinámica del flujo se considera un sistema lineal invariante en el tiempo
definido según:
y(k) + α1 y(k − 1) + · · · + αna y(k − na ) =
ν1 u(k) + ν2 u(k − 1) + · · · + νnb u(k − (nb − 1))
donde y(k) ∈ Rm representa el estado observable del sistema (la salida), u(k) ∈ Rr representa
la actuación (la entrada) y k ∈ N es el paso de tiempo actual. Los vectores y(k) y u(k) poseen
las m componentes de salida y las r componentes de entrada que se consideran observables para
cada paso de tiempo k dentro de la experiencia. Las variables na ∈ N y nb ∈ N definen los
horizontes de auto-regresión para y y u respectivamente. A modo de simplificación se puede
asumir na = p y na = nb − 1 sin perder generalidad. Reformulando los coeficientes del término
derecho se obtiene una nueva forma del sistema:
y(k) + α1 y(k − 1) + · · · + αna y(k − na ) =
(3.4.1)
β0 u(k) + β1 u(k − 1) + · · · + βp u(k − p)
donde p ∈ N define el orden del modelo.
Nos referimos al sistema como un modelo AutoRegressive with eXtra inputs(ARX). Los coe-
ficientes αi para 1 ≤ i ≤ p y βi para 0 ≤ i ≤ p, de tamaños m × m y m × r respectivamente, son
llamados observer Markov parameters y caracterizan el modelo [33].
Si se define el vector de parámetros
Θ := (α1 . . . αp β0 . . . βp )T ∈ R(pm+(p+1)r)×m
y el vector de regresión
−y(k − 1)
..
.
−y(k − p)
ϕ(k) =
∈ Rpm+(p+1)r (3.4.2)
u(k)
..
.
u(k − p)
la Eq. 3.4.1 puede ser escrita de la siguiente forma
y(k) = ΘT ϕ(k).
Por otro lado, definiendo θ, un vector de tamaño d := pm2 + (p + 1)mr que contiene todos
los coeficientes de las matrices αi y βi , y considerando Ξ(k) := ϕ(k) ⊗ Im , siendo ⊗ el producto
de Kronecker e Im la matriz identidad m × m, es posible reescribir la Eq. 3.4.1 de la siguiente
forma
y(k) = ΞT (k)θ.
51
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Para estimar θ, se define una fase de entrenamiento donde se fuerza al actuador mientras
se mide la respuesta del sistema fı́sico durante N pasos de tiempo. Se propone como señal de
actuación para el entrenamiento un pulso de gran amplitud y corta duración, que permita captar
la respuesta del sistema a un gran rango de frecuencias. La Fig. 3.4.1 presenta un diagrama de
bloques que sintetiza la fase de entrenamiento e identificación del sistema.
Las N muestras del entrenamiento son utilizadas bajo el criterio de estimación de mı́nimos
cuadrados para obtener un estimador θ̂N LS de θ. Se evalúa Ξ(k) sobre el conjunto de las N
R2 − R1 θ
Entonces, se concluye que kQT (Y − Φθ)k2
=k k2 . Al determinar esta cantidad y
R3
resolver el sistema R1 θ̂ = R2 se despeja θ̂, el estimador de θ, según:
θ̂ = R1−1 R2 (3.4.4)
Este sistema suele estar mejor condicionado que Ec. 3.4.3 y por lo tanto es menos sensible a
ruidos, diferencias de magnitudes medidas, similitud de mediciones en distintos sensores, etc.
Parámetros Utilizados
Como parámetros destacados de la estrategia de identificación del sistema se pueden men-
cionar a la duración y amplitud del pulso forzado como actuación, el número de muestras del
perı́odo de entrenamiento N y el horizonte de autoregresión determinado por p. Si bien es posible
ajustar dichos parámetros considerando únicamente el grado de aproximación del modelo ARX
respecto de las muestras observadas y la posibilidad de predecir estados futuros, se observó que
tales ajustes no aseguraban necesariamente un buen control. Dado que la estrategia de identi-
ficación del sistema se encuentra integrada con el algoritmo de control, se decide posponer la
selección de parámetros hasta definir el controlador y poder verificar que los ajustes aseguran
los objetivos de control propuestos. La Tabla 3.4.1 incluye una lista detallada de las propiedades
y variables utilizadas en esta fase.
Propiedad Variable
Cant. variables de salida m
Cant. variables de entrada r
Orden del sistema p
Cant. muestras de entrenamiento N
Actuación de entrenamiento u(1) . . . u(N )
Luego de la identificación del model ARX, es necesario establecer el lazo cerrado del control
y definir el algoritmo de feedback apropiado. La Fig. 3.5.1 muestra un diagrama de bloques de
la fase de control que se considera a continuación.
54
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
(k)
Los coeficientes β0 son llamados parámetros de respuesta del sistema al pulso (pulse reponse
parameters y son obtenidos según:
(0)
β0 = β0
k
(k) (k−i)
X
β0 = βk + αi β0 ,1 ≤ k ≤ p
i=1
p
(k) (k−i)
X
β0 = αi β0 ,k > p
i=1
con coeficientes calculados de forma recursiva. En primer lugar, es necesario definir los α1k :
(0)
α1 = α1 ,
k
(k) (k−i)
X
α1 = αk+1 + αi α1 , 1 ≤ k ≤ p − 1,
i=1
k
(k) (k−i)
X
α1 = αi α1 , k > p,
i=1
Y finalmente αkj :
(j) (j−1) (j−1)
α1 = α1 α1 + α2 ,
(j) (j−1) (j−1)
α2 = α1 α2 + α3 ,
..
.,
(j) (j−1)
αp−1 = α1 αp−1 + αp(j−1) ,
(j−1)
αp(j) = α1 αp .
sensores. De esta forma, se pretende generar un efecto de “tunel” sobre el trazador pasivo que
garantice la ausencia de desprendimiento de vórtices en ese segmento de la estela. En efecto, si
consideramos la simetrı́a en la posición de los sensores y actuadores junto con la dinámica del
sistema, podemos asumir que respuesta de control natural será aumentar la actuación cuando
el sistema aún no se encuentre estabilizado.
A tal fin, se define la función objetivo según
Qi := diag(q1 . . . qm ),
y qi representa el peso del sensor i. Si bien el peso de cada sensor puede definirse como
unitario, es posible variar el valor para dar preponderancia a determinados sensores frente a
otros. De esta forma se puede tomar en cuenta la distancia de cada sensor respecto del punto
de actuación y, por ejemplo, contemplar un peso menor en sensores con mayor retardo.
El parámetro λ de la Ec. 3.5.4 penaliza la actuación dentro del funcional. De esta forma se
le asocia un costo a la energı́a utilizada en el actuador para que el controlador se auto-regule y
consiga un balance de eficiencia. Durante la experiencia, se pudo comprobar que el valor de λ
considerado resultó muy sensible a la cantidad de los sensores utilizados, a su posición y a las
escalas de los valores medidos o de actuación. Por este motivo, se consideran experiencias de
verificación de robustez, fuera del entorno de diseño, que mantengan fijos parámetros como las
posiciones y cantidad de sensores. De la misma forma, se considera la normalización y cambio de
escala de los valores medidos para contar con series de datos homogéneas que quiten sensibilidad
a la variable λ. Estas cuestiones serán tratadas en el Capı́tulo 4.
Es importante remarcar que la minimización de la función de costo, J, no implica de forma
directa la minimización de la energı́a cinética de la turbulencia. Este objetivo general se alcanza
gracias a disponer adecuadamente de los sensores y a penalizar la existencia de lı́neas del flujo
no deseadas. De esta forma se fuerza al flujo a adoptar una configuración particular conocida
como estable.
Se asume una ley de control lineal y se define us (k) = Kvp , donde K es una matriz de
sr × p(m + r) que contiene los coeficientes del controlador.
Teniendo esto en cuenta y aplicando el método de Lagrange para minimizar J bajo las
restricciones dadas por la Ec. 3.5.1, se plantea el Lagrangiano L = J+ < l, ys − T us − Ψvp >;
donde l ∈ Rsm simboliza el multiplicador de Lagrange y < ·, · > es un producto interno usual
en Rsm . Buscando la solución óptima del sistema, se obtienen las siguientes ecuaciones:
ys − T us − Ψvp = 0,
2Qys + l = 0,
2λus − T T l = 0.
Como se requiere únicamente el valor de la actuación para el paso actual (k), es posible
ahorrar tiempo de procesamiento si se calculan sólo las primeras r filas del producto en el
primer término de la Ec. 3.5.6 según
Luego de la aplicación de la actuación u(k) es necesario medir el estado de los sensores y(k),
calcular vp y cerrar el ciclo de control repitiendo la Ec. 3.5.7 para el nuevo paso de tiempo. A
continuación, se resume el algoritmo de control aplicado mediante pseudo-código:
Parámetros Utilizados
El parámetro de mayor importancia durante la fase de control es el costo del actuador
λ utilizado en la función objetivo. Su valor debe ser restrictivo para evitar que la salida sea
controlada con un uso de actuación poco eficiente y a su vez lo suficientemente permisivo para
que el actuador fluctúe de acuerdo con la naturaleza del sistema.
La Tabla 3.5.1 resume las propiedades y variables utilizadas en esta fase.
Propiedad Variable
Horizonte de predicción s
Costo del actuador λ
Pesos de cada sensor Q
El presente capı́tulo introdujo la experiencia del escurrimiento sobre un cilindro en 2D ası́ co-
mo los conceptos básicos asociados sobre su control. Se sintetizaron las zonas caracterı́sticas del
escurrimiento poniendo foco en la estela del cilindro y los fenómenos de desprendimiento de
vórtices y turbulencia. Asimismo, se introdujo el número de Reynolds (Re) que caracteriza la
dinámica del fluido y el número de Strouhal (St) que se relaciona con la frecuencia de despren-
dimiento de vórtices y puede ser estimado en ciertos rangos de Re.
Luego de resumir las aplicaciones de control de bluff bodies y su relación con la experiencia
del cilindro, se detalló el esquema experimental incluyendo las dimensiones del problema, el valor
de Re = 235 y una estimación de Stestimado = 0,1814. Estos parámetros permiten pronosticar el
comportamiento del fenómeno fı́sico previo a su simulación.
Entonces, se introduce el algoritmo de identificación del sistema que permite obtener un
modelo matemático ARX de orden p a partir de un conjunto de muestras de entrenamiento.
Asimismo se utiliza el modelo ARX calculado, p, un horizonte de predicción s, el peso de cada
sensor y el coeficiente de penalización de la actuación λ para definir el algoritmo de control.
Dicho sistema hace uso de técnicas predictivas utilizando un controlador del tipo GCP. Ambos
algoritmos son definidos de manera genérica, para un conjunto de m sensores y r actuado-
res arbitrarios consiguiendo un esquema de controlador MIMO lineal que puede ser extendido
fácilmente a otras experiencias.
58
Parte 4
Ensayo Experimental
59
4.1 Introducción
60
4.2 Mallado de la Experiencia
Se efectúa la simulación utilizando el aplicativo Code Saturne [23, 2], un sistema de código
abierto escrito en Fortran, C99 y Python que realiza Direct Numerical Simulation (DNS). Este
tipo de simulación consiste en discretizar la experiencia con un conjunto de celdas y resolver las
ecuaciones de Navier-Stokes para cada paso de tiempo. El conjunto de celdas se denomina malla
(o mallado) y la solución a las ecuaciones se practica sobre los puntos de unión entre celdas.
Como agregado a la resolución del flujo de un fluido, Code Saturne permite resolver modelos
fı́sicos de transferencia de calor y combustión de fluidos, entre otros, mediante un algoritmo de
volúmenes finitos de segundo orden utilizando el método de Crank-Nicolson [23].
Figura 4.2.1: Detalle del tipo de celdas triangulares utilizadas en el mallado no-estructurado.
61
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura 4.2.2: Mallado de la geometrı́a del sistema cercana al cilindro. En si bien la diferencia entre el tamaño del
mallado sobre el borde del cilindro y las fronteras del dominio es grande, se utilizó una transición gradual y varios
anillos concéntricos de diversos tamaños.
Figura 4.2.3: Mallado de la geometrı́a del sistema. Se observa claramente la diferencia de densidad de celdas entre
las cercanı́as del cilindro y la región circundante.
Dado que el cilindro posee un diámetro unitario, su circunferencia resulta π. A fines prácti-
cos, se pretende un nivel de discretización tal que el cilindro esté compuesto por 100 celdas
en su superficie. Esto implica un número aproximado de 5 celdas para describir a cada actua-
dor, sabiendo que se representan como semi-arcos de aproximadamente 5 % de la circunferencia
(Capı́tulo 3.3). Se define entonces un tamaño de celda de 0,03 en la proximidad del cilindro y
dos anillos concéntricos con tamaños de celda 0,035 y 0,05 permitiendo un aumento gradual de
las dimensiones utilizadas (Fig. 4.2.2). El tamaño general del resto del dominio y lı́mites de la
experiencia se fijó en 0,1 (Fig. 4.2.3).
Este tipo de configuración permite economizar enormemente el tiempo de procesamiento sin
comprometer la calidad de la simulación en las regiones crı́ticas. Esto es posible al destinar una
pequeña cantidad de celdas a tomar dimensiones pequeñas (con un bajo poder de cobertura) y
una cantidad sensiblemente mayor para aquellas de mayor tamaño (con mejores posibilidades
de cubrir el amplio dominio). Es posible encontrar el detalle de las dimensiones empleados en
cada región al generar la malla en el Apéndice B.1. Se incluye además la distribución final de
celdas de acuerdo a su tamaño.
Figura 4.2.4: Extensión del mallado 2D a 3D. Se observa el detalle de una vista oblicua del mallado 2D (Izq.) en
comparación con su extensión a 3D (Der.) mediante la conversión de celdas triangulares a pentaedros de altura
0,005 homogénea.
U ∆t
C= < Cmax
∆x
donde U es la magnitud de la velocidad, (∆t) es el paso del tiempo y (∆x) indica el tamaño
elegido para la discretización espacial del problema (en nuestro caso, el tamaño de las celdas).
El coeficiente C es conocido como número de Courant y se exige que sea menor que cierta
constante Cmax que dependerá de la sensibilidad numérica del algoritmo utilizado. Cmax suele
ser inferior a 1, reforzando la necesidad de que la distancia recorrida por cada partı́cula en un
paso de tiempo (U ∆t) sea menor que el tamaño de la celda (∆x). En el caso particular del
método de Crank-Nicolson utilizado en la resolución numérica, la condición CFL no es necesaria
para asegurar la estabilidad [67] por tratarse de un método A-Stable pero de todas formas, un
número de Courant bajo es importante para mantener una buena precisión numérica.
Se elige entonces ∆t = 0,061 como paso de tiempo constante para todas las simulaciones de
forma arbitraria pero verificando que C ≈ 2. En efecto, para el caso extremo de ∆x = 0,03 y
conociendo que la velocidad caracterı́stica de la experiencia es unitaria, se obtiene:
1 · 0,061
C =
0,03
= 2,0333
4.3.1. Configuración
El aplicativo posee dos archivos de suma importancia que deben ser modificados para confi-
gurar correctamente el modelo:
usini1.f90 Establece los parámetros fı́sicos y numéricos del cálculo. En él se define el paso
de tiempo, viscosidad del fluido, la cantidad de pasos a simular, el orden del algoritmo de
volúmenes finitos, entre otras propiedades. También contiene la información necesaria para
definir los sensores de la experiencia que, dada la naturaleza del simulador, son definidos
mediante sondas de prueba (probes) indicando la posición cartesiana para cada una.
usclim.f90 Define las condiciones de contorno del sistema para las distintas caras de cada celda
del mallado. De esta forma se indican las condiciones de borde del sistema mediante el
mapeo de las celdas del mallado a tipos conocidos por Code Saturne.
Es importante remarcar que mientras las subrutinas de configuración del archivo usini1.f90 son
ejecutadas una única vez, al inicializar el motor de cálculo, la configuración de condiciones de
contorno indicadas en usclim.f90 son invocadas cada paso de tiempo y por lo tanto, pueden
ser modificadas. En ese sentido, las condiciones de contorno son dinámicas y esto permitirı́a
dinamizar los niveles de actuación durante la iteración de la simulación.
A continuación se incluye una breve reseña sobre las principales modificaciones realizadas a
cada archivo para establecer la configuración inicial de simulación. El detalle del código fuente
utilizado puede encontrarse en el Apéndice F.4.
4.3.1.1. usini1.f90
En primer lugar, es necesario fijar las variables numéricas definidas para la simulación. De
esta forma se define el paso de tiempo (dtref ), la cantidad de pasos a simular (ntmabs) y el
orden de difusión para la resolución de volúmenes finitos (blencv ) tanto en las componentes
de velocidad (iu, iv y iw ) como en el escalar pasivo utilizado (isca). También es necesario
indicar los pasos de tiempo para el perı́odo de muestreo empleado en las sondas (nthist) y para
el total de celdas (ntchr ). Cabe destacar que en ambos casos, el sistema almacena en archivos
los valores instantáneos medidos para la concentración de escalar y las tres componentes de
velocidad. Salvo que se indique lo contrario, el muestreo en los sensores será a cada paso de
tiempo y el muestreo general se realizará cada 10 paso a fines de obtener una representación
completa del estado de la simulación.
...
65
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
dtref = 0.061d0
ntmabs = 16000
...
!first order diffusivity: 0.0d0
!second order diffusivity: 1.0d0
blencv(iu(iphas)) = 1.0d0
blencv(iv(iphas)) = 1.0d0
blencv(iw(iphas)) = 1.0d0
...
blencv(isca(1)) = 0.0d0
...
nthist = 1
ntchr = 10
...
Ya definidas las variables fı́sicas y numéricas, se debe especificar la ubicación de cada sensor.
Code Saturne soporta hasta 100 sondas de prueba para las cuales se almacena las magnitudes
indicadas en archivos de texto especiales y con la frecuencia de muestreo correspondiente. En
este caso, se decide definir las sondas de forma genérica, estableciendo áreas para su colocación
de forma equiespaciada. El siguiente extracto de código muestra la declaración de la estructura
para indicar estas áreas junto con las variables auxiliares necesarias:
! Declares a custom type which includes start and end coordinates for the probe’s area.
TYPE probes_area
double precision xStart
double precision yStart
double precision xEnd
double precision yEnd
double precision separation
END TYPE
!Declares auxiliary variables for the coordinates and separation between probes.
double precision xProbe, yProbe, xSeparationProbe, ySeparationProbe
integer iProbe, iProbeLine, iProbeArea
Luego, se definen las áreas necesarias indicado la separación, los lı́mites de inicio y de fin
para cada una. En este caso se utilizaron dos áreas de sondas, una con Y positivas y la otra
dispuesta simétricamente con Y negativas. Las áreas son configuradas como lı́neas paralelas al
eje X con separación de 0,5 diámetros. Esta disposición comprende a la necesaria para el sistema
de control e incluye sondas extras que serán utilizadas con fines de inspección pero excluidas en
los distintos algoritmos.
!Defines two areas where the probes should be placed
TYPE(probes_area) probesAreas(2)
iProbe = iProbe + 1
xyzcap(1,iProbe) = xProbe
xyzcap(2,iProbe) = yProbe
xyzcap(3,iProbe) = 0.00d0
4.3.1.2. usclim.f90
La definición de las condiciones fı́sicas implica identificar las celdas del mallado que participan
en cada una de los lı́mites de la experiencia. El mecanismo utilizado en este caso consiste en
asignar un número que representa un color a cada una de las celdas lı́mite. Aquellas celdas que
requieran un tratamiento particular y la configuración de condiciones de borde, serán filtradas
del resto para recibir la configuración reservada por Code Saturne a tal fin.
El siguiente bloque de código, define las variables auxiliares necesarias junto con el mapeo
de bordes propuesto:
double precision alfa, beta
double precision xCentre, yCentre
real, parameter :: inputVelocity = 1d0
real :: upperActuatorValue, lowerActuatorValue
La pared del cilindro y el borde superior e inferior de simetrı́a son de fácil configuración.
Simplemente es necesario seleccionar las celdas que poseen sus respectivos colores mediante
getfbr(filtro, cantEncontradas, listaEncontradas) y luego definir el tipo de borde (itypfb)
para cada cara de celda que cumpla con la condición (ifac):
!pared -> iparoi
call getfbr(’4’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)
do iphas = 1, nphas
itypfb(ifac,iphas) = iparoi
enddo
enddo
do iphas = 1, nphas
itypfb(ifac,iphas) = isymet
enddo
enddo
La entrada posee la complejidad extra de definir la zona de inyección de escalar para aquellas
caras que posean el color indicado y tengan un centro en Y (calculado mediante cdgfbo(color,
caraEncontrada)) entre las ordenadas −0,1 y 0,1. En estos casos, además de fijar la velocidad
unitaria en el eje X a la constante inputVelocity = 1 , se define un valor unitario al escalar
(isca).
!entrada -> ientre
call getfbr(’2’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)
do iphas = 1, nphas
itypfb(ifac,iphas) = ientre
rcodcl(ifac,iu(iphas),1) = inputVelocity
rcodcl(ifac,iv(iphas),1) = 0.0d0
rcodcl(ifac,iw(iphas),1) = 0.0d0
yCentre = cdgfbo(2,ifac)
do ii = 1, nscal
if(iphsca(ii).eq.iphas) then
if (yCentre.gt.-0.1d0.and.yCentre.lt.0.1d0) then
icodcl(ifac, isca(ii)) = 1
rcodcl(ifac, isca(ii),1) = 1.d0
else
icodcl(ifac, isca(ii)) = 0
rcodcl(ifac, isca(ii),1) = 0.d0
endif
endif
enddo
enddo
enddo
Por último, se filtran los elementos que definen los semi-arcos de actuación para entregarles
un tratamiento particular. Mediante simples cálculos de geometrı́a, se asignan los componentes
de velocidad en X e Y necesarios para obtener una inyección de movimiento tangencial a la pared.
Se agregan dos variables para definir la magnitud de dichas velocidades: upperActuatorValue
y lowerActuatorValue, ambas nulas para los fines de la simulación inicial pero que serán
modificadas en cada iteración cuando se defina el control para el cilindro.
upperActuatorValue = 0
lowerActuatorValue = 0
xCentre = cdgfbo(1,ifac)
yCentre = cdgfbo(2,ifac)
alfa = atan(yCentre / xCentre)
beta = alfa - pi/2.0
do iphas = 1, nphas
itypfb(ifac,iphas) = iparoi
rcodcl(ifac,iu(iphas),1) = upperActuatorValue * cos(beta)
rcodcl(ifac,iv(iphas),1) = upperActuatorValue * sin(beta)
rcodcl(ifac,iw(iphas),1) = 0.0d0
enddo
enddo
xCentre = cdgfbo(1,ifac)
yCentre = cdgfbo(2,ifac)
alfa = atan(yCentre / xCentre)
beta = alfa + pi/2.0
do iphas = 1, nphas
itypfb(ifac,iphas) = iparoi
rcodcl(ifac,iu(iphas),1) = lowerActuatorValue * cos(beta)
rcodcl(ifac,iv(iphas),1) = lowerActuatorValue * sin(beta)
rcodcl(ifac,iw(iphas),1) = 0.0d0
enddo
enddo
4.3.2. Resultados
Una vez configurada de la experiencia, se procede con la ejecución de la simulación y el análisis
de las mediciones obtenidas. La Fig. 4.3.1 muestra el avance del escalar inyectado generando un
filamento que difunde a través del cilindro y demarca su burbuja de recirculación. Una vez que la
experiencia entra en régimen, la aparición de desprendimiento de vórtices genera un movimiento
oscilatorio aguas abajo del cilindro que es adoptado por el trazador mediante las lı́neas de emisión
(Fig. 4.3.2).
Figura 4.3.1: Inyección de trazador pasivo en el régimen inicial de la experiencia. Se puede observar la disposición
de los sensores aguas abajo del cilindro, en posiciones no alcanzadas aún por el escalar.
Figura 4.3.2: Inyección de trazador pasivo en régimen oscilatorio de la experiencia. El desprendimiento de vórtices
provoca un movimiento oscilatorio en la estela del cilindro que es copiado por el trazador.
Una magnitud caracterı́stica para este tipo de experiencias fı́sicas es la vorticidad que se
∂v
define como el rotor de la velocidad. En 2D se la puede expresar como ω(x, y, t) = ∂x − ∂u
∂y ,
siendo u(x, y, t) y v(x, y, t) las velocidades instantáneas en el eje X e Y respectivamente. Esta
magnitud mide el grado de la rotación local que sufre un punto (x, y) en el tiempo t entregando
valores negativos para una rotación horaria y positivos para una anti-horaria. La Fig. 4.3.3
compara los valores de escalar y vorticidad instantánea una vez que se establece el régimen
oscilatorio.
Figura 4.3.3: Concentración de escalar y vorticidad instantánea del flujo del cilindro. Realizando una comparación
cualitativa de ambas magnitudes se puede observar la similitud entre los caminos optados por el trazador y los
vórtices del camino de Von Kàrmàn.
La Fig. 4.3.4 entrega una vista de la variación de la concentración en los sensores 1 y 4 hasta
que el sistema entra en régimen oscilatorio. En la misma se puede observar el retardo temporal
que existe entre la información captada por cada sonda, producto de la distancia que poseen
respecto del cilindro.
Figura 4.3.4: Resultados de la concentración de escalar medida por los sensores 1 y 4, el más cercano y más alejado
del cilindro respectivamente, durante la fase de inicio. Es posible apreciar el retardo que sufre el avance del escalar
por el frente izquierdo. Esto resulta evidente en las mediciones del sensor 4 respecto del 1 tanto en las primeras
concentraciones obtenidas como en las repetitivas oscilaciones que acompañan el desprendimiento de vórtices.
Figura 4.3.5: Evolución de la concentración del escalar media en los distintos sensores (probe 1..8). Se puede
observar la diferencia de fase entre la señal de los sensores superiores (probe 1..4) y sus respectivas contrapartes
inferiores (probe 5..8). Una vez alcanzado el régimen estacionario, las oscilaciones se identifican periódicas cada
87 muestras.
Si bien, las señales de concentración de escalar entregan una discretización del fenómeno
real simulado, se observa claramente una oscilación periódica para el sistema. Una medición
detallada de la oscilación permite obtener una aproximación del perı́odo de la experiencia real.
De esta forma, se determina empı́ricamente el perı́odo de oscilación para la concentración del
escalar en 87 muestras, es decir T = 87 · 0,061 = 5,307. Esto es ası́ tanto para los sensores
cercanos al cilindro como para aquellos que se encuentran a mayor distancia.
Es importante comparar esta medición con el número de Strouhal estimado en el Capı́tulo
3.3 en base al Re de la experiencia: Stestimado = 0,1814. Dado que tanto el diámetro como la
velocidad caracterı́stica de la experiencia son unitarios, el valor de St coincide con la frecuencia
adimensional. Se puede aproximar el St real de la experiencia utilizando el T medido:
fD f ·1
St = = = T −1 = 5,307−1
U 1
= 0,884
Luego, St resulta muy cercano al Stestimado e indica que las oscilaciones del escalar medido
están relacionadas directamente con el desprendimiento de vórtices. Más aún, el perı́odo de los
desprendimientos se puede aproximar como el perı́odo de la señal medida en los sensores.
El sistema de control diseñado requiere algún mecanismo para modificar el valor de actuación
en Code Saturne de forma dinámica, esto es, frente a cada paso de tiempo.
Si bien las condiciones de borde pueden ser re-establecidas en cada iteración de la simulación
mediante código Fortran, este lenguaje resulta poco flexible, no posee buenas interfaces para
interactuar con aplicaciones matemáticas (Matlab, Scilab, Octave, Etc.) y su manejo de meca-
nismos multi-threading posee muy poco soporte y escaso uso. Estos factores resultan importantes
si se piensa en la extensión y reuso del sistema tanto para escenarios de simulación como para
implementaciones experimentales. Por otro lado, los sistemas escritos en C y C++ se caracteri-
zan por permitir la interacción con una gran cantidad de lenguajes y esquemas de comunicación,
manteniendo a su vez un rendimiento de computo similar al de Fortran. Es importante remarcar
que tanto Fortran como C/C++ poseen interfaces para realizar GPGPU mediante plataformas
como CUDA. Sin embargo, la versión CUDA C/C++ posee una mayor aceptación y soporte por
tratarse de un lenguaje más popular.
75
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura 4.4.1: Diagrama de bloques donde se muestra la dependencia entre los sistemas escritos en Fortran, C++
y Matlab. Se utiliza el nombre de archivo representativo para cada caso.
Incluso cuando la implementación en laboratorio queda fuera del alcance del presente trabajo,
se realizaron distintos avances en tal dirección con el desarrollo de pruebas de concepto de los
algoritmos en CUDA C/C++(Apéndice G.2) y de ejemplos de la obtención programática de
imágenes a partir de distintas cámaras (Apéndice G.1).
Figura 4.4.2: Diagrama simple de las actividades del simulador y controlador. Se pueden observar la concurrencia
entre los ciclos principales de cada subsistema y la dependencia del simulador sobre los valores calculados por el
controlador.
Por otro lado, el sistema controlador debe obtener los valores medidos en los distintos sensores
y elaborar una actuación ya sea durante el entrenamiento del sistema e identificación del ARX o
durante el control de la estela. La actuación de entrenamiento funciona en una fase inicial, donde
las muestras son acumuladas hasta contar con la cantidad suficiente para identificar el sistema.
Luego de calcular el modelo ARX, se lo utiliza con las muestras pasadas en el algoritmo de control
predictivo para calcular la actuación que mejor ajusta la función objetivo. Esta secuencia nos
presenta 2 fases marcadas: la fase de entrenamiento y la fase de control. La identificación del
sistema marca el punto de división entre ambas fases. En este caso, la muestra con los valores
de los sensores será obtenida de los archivos generados por Code Saturne que almacenan las
mediciones en formato CSV a cada paso de tiempo. A tal fin, se implementa un Parser que
recolecta las muestras.
Las Fig. 4.4.3 presenta un diagrama de colaboración simple que describe la secuencia de
comunicación entre los módulos mencionados durante la fase de entrenamiento. Cuando las
muestras recolectadas alcanzan el número necesario, se ejecuta el algoritmo de identificación del
sistema y se entra en la fase de control a lazo cerrado (Fig. 4.4.4).
4.4.3. Implementación
Se decide mantener la independencia de procesos entre ambos sistemas y emplear una es-
quema de comunicación mediante pipes de sistemas operativos basados en Unix. Dado que la
comunicación es bidireccional, se requieren dos archivos para establecer los canales de comuni-
cación en cada sentido. Los pipes son creados por nombre a través de archivos especiales FIFO
construidos con el comando mkfifo. El pipe de escritura para el simulador y lectura para el
controlador es llamado semaphore dado que permite señalizar al controlador en el momento
en que se requiere calcular el nuevo valor de actuación. La señal incluye el número de paso de
tiempo como parámetro que resulta importante en el sistema controlador para recolectar las
muestras adecuadas mediante el Parser. El otro sentido de la comunicación es representado por
los archivos act.upper y act.lower que permiten enviar los valores decimales de amplitud de
actuación al simulador. Los descriptores de archivo son abiertos en cada sistema de modo blo-
queante, de esta forma, los sistemas intercalan mensajes y se esperan mutuamente mientras su
par realiza operaciones de cálculo.
El siguiente bloque de código muestra la creación de los pipes y el lanzamiento del proceso
controlador al que se le indican los nombres definidos. Luego, el simulador abre los archivos
especiales en modo escritura o lectura según sea necesario. Esta secuencia de inicio se efectúa
una única vez gracias a la guarda de la variable estática actuatorValuesInitialized :
if (.not.actuatorValuesInitialized) then
actuatorValuesInitialized = .true.
endif
Luego, frente a cada iteración, el simulador escribe en el pipe el paso de tiempo (ntcabs) y
espera hasta que los valores de actuación son notificados por los otros pipes:
write(sStepNumber, ’(i0)’ ) ntcabs
write(103,*) sStepNumber
read(104,*) upperActuatorValue
read(105,*) lowerActuatorValue
Por último, al encontrarse en el paso de tiempo final de la simulación (ntmabs), cierra los
descriptores indicando al controlador que la simulación ha finalizado:
if (ntmabs.eq.ntcabs) then
close(103)
close(104)
close(105)
endif
El sistema controlador, por su parte, consta de un ciclo en el archivo main.cpp que emplea
una instancia de la clase SaturneCommunicator para esperar por el paso de tiempo (se-
maphoreStepNumber ) proveniente del pipe y enviar la actuación (act.upper y act.lower )
por los pipes restantes. A su vez, se utiliza un objeto Parser para recolectar las mediciones en
el paso de tiempo anterior y un Controller para calcular la actuación en base a las muestras.
El ciclo de control finaliza cuando se obtiene un paso de tiempo inválido.
...
Controller controller(/*...*/);
Parser parser(/*...*/);
SaturneCommunicator saturneCommunicator;
controller.initialize(/*...*/);
bool continueControl = true;
while (continueControl) {
int semaphoreStepNumber = saturneCommunicator.waitForStep(semaphore);
if (semaphoreStepNumber > 0) {
Row values = parser.readValues(probesPressureFilepath , semaphoreStepNumber - 1);
Actuation act = controller.getActuationFor(semaphoreStepNumber, values);
saturneCommunicator.send(upperActuator, act.upper);
saturneCommunicator.send(lowerActuator, act.lower);
}
else {
continueControl = false;
}
}
...
std::string strValue;
converter >> strValue;
actuatorFile << strValue <<std::endl;
}
El detalle del sistema controlador ası́ como las distintas abstracciones utilizadas puede en-
contrarse en el Apéndice F.6.
La fase de identificación del sistema tiene por objetivo la obtención de un modelo ARX que
ajuste de la mejor manera al modelo fı́sico simulado. A tal fin, se utiliza el sistema controlador
para forzar una señal de actuación predeterminada, capturar las muestras en los sensores durante
N pasos de tiempo e identificar el modelo ARX de orden p mediante una implementación en
Matlab del algoritmo introducido en el Capı́tulo 3.4.
81
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura 4.5.1: Fase de entrenamiento del sistema. Se puede observar la evolución de la concentración del escalar en
las 8 sensores en relación con el pulso forzado en la actuación. Los gráficos del escalar muestran que el efecto del
pulso posee un retardo dependiendo de la distancia del sensor a la zona de actuación. También es posible observar
que el desfasaje constante que existe entre señales de sensores simétricas es afectado por la actuación durante un
breve perı́odo de tiempo.
Luego de cierto tiempo de disparar el pulso, la concentración del escalar se reduce drástica-
mente en los distintos sensores. Considerando el flujo como un sistema dinámico no lineal, las
variables de estado orbitan alrededor de un centro de atracción [65]. El pulso forzado perturba
dicha órbita de forma abrupta para luego entrar en una etapa de relajación. La órbita de oscila-
ción natural es retomada gradualmente a medida que el sistema entra en régimen. El retardo de
control (death-time) se explica por la distancia de los sensores al punto de actuación y aumenta
[r,N] = size(u);
phi = zeros(na*m+nb*r,N);
for j=na+1:N
phi(:,j)=[reshape(-y(:, j-1:-1:j-na), na*m, 1); ...
reshape(u(:, j:-1:j-(nb-1)), nb*r, 1)];
end
Luego se calcula la matriz de regresión Ξ(k), llamada reg , utilizando el producto de Kro-
necker sobre los valores de ϕ(k):
phi_aux = fi(:, na+1:end);
reg = zeros(m*size(phi_aux,1), m*(N-na));
for j=1:N-na
reg(:, 1+(j-1)*m:j*m) = kron(phi_aux(:,j), eye(m));
end
Por último, los coeficientes αi y βi son extraı́dos del estimador y organizados en las matrices
del modelo: A y B.
a = zeros(m, m, na);
b = zeros(m, r, nb);
for j=1:na
a(:,:,j)=reshape(th(1+(j-1)*m*m:j*m*m),m,m);
end
for j=1:nb
b(:,:,j)=reshape(th(1+na*m*m+(j-1)*m*r:1+na*m*m+(j-1)*m*r+m*r-1),m,r);
end
A = zeros(m, m, na+1);
A(:,:,1) = eye(m);
A(:,:,2:end) = a(:,:,:);
B = b;
El código completo del cálculo del modelo ARX se puede encontrar en el Apéndice F.5 junto
con la versión implementada en CUDA C/C++ (Apéndice G.2.
El Apéndice C.2 presenta una breve comparación sobre las diferencias en los tiempos de
procesamiento requeridos por la versión Matlab y CUDA C/C++ del algoritmo.
Figura 4.5.2: Comportamiento del modelo frente a una actuación de frecuencia 0,2342 con A = 0,55 y σ = 20.
Los gráficos superiores presentan la evolución en la concentración del escalar a lo largo del tiempo para distintos
sensores. El gráfico inferior muestra la señal aplicada simultáneamente a ambos actuadores.
Figura 4.5.3: Comportamiento del modelo frente a una actuación de frecuencia 0,3643 con A = 0,60 y σ = 20.
En los gráficos superiores se observa la evolución en la concentración del escalar a lo largo del tiempo para
distintos sensores. El gráfico inferior muestra la señal aplicada simultáneamente a ambos actuadores. Se incluye la
respuesta del sistema al cesar la actuación pudiéndose observar que las predicciones mejoran gradualmente hasta
que el sistema entra nuevamente en régimen.
Figura 4.5.4: Espectrogramas de la verificación del modelo mediante una señal de frecuencia 0,2342 (125 % respecto
de la caracterı́stica del sistema). Se compara el espectrograma de la simulación (izquierda) y de las predicciones
del modelo ARX obtenido en la fase de identificación del sistema.
En el caso extremo de frecuencia de actuación 0,2342 (Fig. 4.5.5), la predicción del modelo
agrega un componente de alta frecuencia a las salidas que el sistema real no posee. Esto puede
estar relacionado con la saturación de la dinámica del flujo inducida por las no-linealidades que
están ausentes en el modelo lineal ARX. Un simple análisis de Fourier sobre la parte periódica
de las señales de actuación demuestra la componente de alta frecuencia no es introducida por el
actuador, al menos no directamente (Fig. 4.5.6). El análisis de frecuencia para ambas actuaciones
presenta picos para componentes que coinciden con las frecuencias estimadas de 0,2342 y 0,3643,
correspondientes al 125 % y 193 % de la caracterı́stica.
Figura 4.5.5: Espectrogramas de la verificación del modelo mediante una señal de frecuencia 0,3643 (193 % respecto
de la caracterı́stica del sistema). Se compara el espectrograma de la simulación (izquierda) y de las predicciones
del modelo ARX obtenido en la fase de identificación del sistema.
Figura 4.5.6: Análisis de frecuencia de las señales de actuación utilizadas para la verificación del modelo ARX.
Se elimina la componente media para mayor claridad de espectro de frecuencias relevante. Sup.: Módulo de la
transformada de Fourier de la señal de gaussianas superpuestas con frecuencia 0,2342. Inf.: De forma análoga al
anterior, se analizan los componentes de Fourier de la señal de gaussianas con frecuencia 0,3643.
Luego de identificado el modelo ARX, el sistema deja la fase de entrenamiento para entrar en
modo de control a lazo cerrado. Esta fase se caracteriza por requerir el cálculo inicial de ciertos
parámetros que serán reutilizados en operaciones más simples en iteración de la simulación. Este
paso es disparado una única vez por el subsistema C++ efectuando el cómputo en Matlab. A
su vez, las muestras y valores de actuación son acumulados en C++ para ser utilizados en la
invocación de una nueva función en Matlab frente a cada paso de tiempo.
En primer lugar se determinan las dimensiones del sistema en base a la cantidad de compo-
nentes del vector de estado y el paso actual de tiempo es asumido sobre la cantidad de muestras:
m = size(y,1);
r = size(u,1);
s = 3*p;
k = size(y,2);
El horizonte de predicción se fija en s = 270, 3 veces el valor de p. Esta cantidad indica los pasos
de tiempo proyectados por el controlador hasta conseguir una actuación estable (sin variaciones).
Se opta por emplear un valor de s elevado para evitar un controlador agresivo respecto de la
proyección del valor de actuación óptimo y el tiempo para conseguirlo. De esta forma se pretende
contemplar la naturaleza oscilatoria del sistema y la posibilidad de oscilaciones en el control del
orden de 3 veces el perı́odo caracterı́stico del fenómeno. A su vez, se tiene conocimiento de
resultados exitosos en experiencias de control similares con 2p ≤ s ≤ 3p [35, 36].
A continuación, se transforma el modelo ARX a la convención propuesta en [33] que presenta
ciertas facilidades en su manipulación. Luego, se calculan los parámetros del sistema de Markov,
(1) (s−1)
β0 , β0 , . . . β0 :
a = -A(:,:,2:end);
b = B;
beta00 = b(:,:,1);
beta0 = zeros(m, r, s-1);
beta0(:,:,1) = b(:,:,2) + a(:,:,1)*beta00;
90
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
for kk=2:s-1
if kk<=p
aux=zeros(size(beta00));
for l=1:kk-1;
aux=aux+a(:,:,l)*beta0(:,:,kk-l);
end
aux=aux+a(:,:,kk)*beta00;
beta0(:,:,kk) = b(:,:,kk+1)+aux;
else
aux=zeros(size(beta00));
for l=1:p;
aux=aux+a(:,:,l)*beta0(:,:,kk-l);
end
beta0(:,:,kk)=aux;
end
end
T_column(1:m,:)=beta00;
for j=2:s;
T_column((j-1)*m+1:j*m,:)=beta0(:,:,j-1);
end;
Luego se calculan las relaciones recursivas de α1k , αkj y βkj en las variables alpha y beta:
psi=zeros(m*s,p*(m+r));
for kk=1:p-1;
alpha(:,:,1,kk)=a(:,:,1)*a(:,:,kk)+a(:,:,kk+1);
end;
alpha(:,:,1,p)=a(:,:,1)*a(:,:,p);
for j=2:s-1;
for kk=1:p-1;
alpha(:,:,j,kk)=alpha(:,:,j-1,1)*a(:,:,kk)+alpha(:,:,j-1,kk+1);
end;
alpha(:,:,j,p)=alpha(:,:,j-1,1)*a(:,:,p);
end
for kk=1:p-1;
beta(:,:,1,kk)=a(:,:,1)*b(:,:,kk+1)+b(:,:,kk+2);
end
beta(:,:,1,p)=a(:,:,1)*b(:,:,p+1);
for j=2:s-1;
for kk=1:p-1;
beta(:,:,j,kk)=alpha(:,:,j-1,1)*b(:,:,kk+1)+beta(:,:,j-1,kk+1);
end;
beta(:,:,j,p)=alpha(:,:,j-1,1)*b(:,:,p+1);
end
Con las matrices T y Ψ definidas, se calculan las primeras r filas de la matriz de control K
(Ec. 3.5.5) utilizando q y λ. Tanto la variable de resultado, K r , como los parámetros de inicio
son almacenados en control state:
Q=kron(eye(s), diag(q));
invLambdaTTQT = -pinv(lambda*eye(r*s) + T’*Q*T);
control_state.K_r = invLambdaTTQT(1:r, :) * T’ * Q * psi;;
control_state.p = p;
control_state.limits = limits;
control_state.s = s;
control_state.m = m;
control_state.r = r;
control_state.lambda = lambda;
Se conforma el vector columna vp (k − p) con los valores pasados de y(k) y u(k). Luego, se
utiliza el vector junto con las r filas calculadas de la matriz de control, K r , para obtener la
nueva actuación según la ley de control establecida en Ec. 3.5.7:
vp = zeros(p*m+p*r, 1);
for i=1:p
vp((i-1)*m+1:i*m) = y(:,k-i);
end
offset = m*p;
for i=1:p
vp((i-1)*r+1+offset:i*r+offset) = u(:,k-i);
end;
Por último, se utilizan los lı́mites definidos con anterioridad para eliminar valores de actua-
ción fuera de los rangos aceptados por la experiencia:
indices_out_of_limit = find(u_k < limits.min_value);
u_k(indices_out_of_limit) = limits.min_value;
indices_out_of_limit = find(u_k > limits.max_value);
u_k(indices_out_of_limit) = limits.max_value;
control_state.u_k = u_k;
A modo de sı́ntesis, la Tabla 4.6.1 resume los valores de los parámetros de ajuste utilizados
en el algoritmo de control. El resultado de control demostró ser muy sensible a la definición de
dichos valores. Los ajustes finales requirieron un trabajo de comparación manual y de reiteradas
simulaciones a fin de balancear el efecto conjunto de los parámetros.
Tabla 4.6.1: Valores definidos para los distintos parámetros de control del sistema.
Figura 4.6.1: Resultados del sistema de control a lazo cerrado. Se puede observar el efecto de la amplitud de
actuación sobre la concentración del escalar en los distintos sensores en función del tiempo.
La señal de actuación resultante presenta un carácter oscilatorio marcado, donde los mo-
vimientos ascendentes (descendientes) del actuador generan una reducción (incremento) en el
escalar medido en los sensores. De acuerdo con la posición del sensor respecto de la actuación,
es necesario considerar un retardo temporal variable.
La estabilización de la estela del cilindro puede apreciarse en imágenes instantáneas de las
lı́neas de emisión (Fig. 4.6.2) que difieren del escenario sin actuación y se mantienen limitadas
en la zona del “túnel” de sensores. Por su parte la vorticidad instantánea (Fig. 4.6.3) disminuye
considerablemente respecto de los valores originales.
Figura 4.6.2: Lı́neas de misión y valores de la concentración del escalar en los sensores durante la fase de actuación.
Es posible observar el efecto del control que restringe las lı́neas de misión al interior del ”túnel“ de sensores.
Figura 4.6.3: Vorticidad instantánea y valores en las sondas durante la fase de control. Los valores detectados
resultan menores que las mediciones en un escenario sin actuación.
Figura 4.6.4: Análisis de frecuencias de la actuación. Módulo de la transformada de Fourier de la entrada menos
su media.
Figura 4.6.5: Análisis de frecuencias de la señal de salida para los sensores 1 y 2. Se puede comparar el módulo
de la transformada de Fourier de la señal menos su media para el caso sin actuación (Izq.) respecto del caso con
actuación (Der.).
Figura 4.6.6: Análisis de frecuencias de la señal de salida para los sensores 3 y 4. Se puede comparar el módulo
de la transformada de Fourier de la señal menos su media para el caso sin actuación (Izq.) respecto del caso con
actuación (Der.).
Media y1 y2 y3 y4 y5 y6 y7 y8
Sin Actuación 0,077 0,071 0,063 0,058 0,077 0,071 0,064 0,057
Con Actuación 0,043 0,047 0,051 0,054 0,043 0,046 0,050 0,054
Tabla 4.6.2: Valores medios del escalar en los distintos sensores. Se puede ver un claro descenso de los valores de
concentración medidos sin el controlador y con el controlador. La disminución posee un porcentaje mayor en los
sensores más cercanos al punto de actuación.
u(t) = u + u0 (t)
La fórmula anterior debe entenderse como el cálculo de energı́a por unidad de masa, siendo
T KE(t)/m una definición más rigurosa. Luego, los valores de TKE calculados para cada celda
de la simulación se pueden integrar sólo si se asume que poseen masa homogénea. Esto es una
buena aproximación en el caso de celdas de idéntico tamaño pero no puede asegurarse en el
mallado no estructurado aplicado a la experiencia (Capı́tulo 4.2).
Para resolver este problema y permitir el análisis detallado del campo de velocidades re-
sultante de la experiencia, se implementa un sistema de transformación para mallas irregulares
definidas por polı́gonos 2D en mallas regulares con celdas cuadradas de cierto tamaño prefijado.
La Fig. 4.6.8 entrega una vista de la malla original y la conversión a una grilla de celdas regula-
res. Sabiendo que los celdas de la malla original varı́an de tamaño entre 0,03 y 0,1, se opta por
generar una grilla con celdas cuadradas de lado 0,045 que permita captar el detalle de las celdas
pequeñas en las cercanı́as del cilindro.
Figura 4.6.7: Representación gráfica de la composición de una señal (u(t)) mediante sus partes media (u) y
perturbaciones o turbulencias (u0 (t)). La dinámica de la señal original queda caracterizada por u0 (t) mientras que
u responde al comportamiento estacionario (basado en Stull, 2008) [63].
Figura 4.6.8: Conversión de valores medidos en malla irregular a una grilla homogénea. Sobre el mallado original
(Izq.) se dispone una grilla celdas cuadradas (Der.). A modo de ejemplo, se colorean los triángulos del mallado
original que participan en una celda cuadrada del nuevo mallado (resaltada en rojo). Las superficies parciales
de color rojo participan en la composición de la magnitud fı́sica mientras que las naranjas no lo hacen por ser
proyectadas fuera del cuadrado.
La transformación se realiza generando una grilla cartesiana con celdas de idéntico tamaño,
recorriendo cada celda de la grilla y proyectando en ella las celdas originales de la malla. Para
cada celda de la nueva grilla se recorren las celdas de la malla original calculando el porcentaje
de superposición en la proyección. Luego, la magnitud fı́sica de la celda cuadrada se compone
del aporte pesado de las celdas originales proyectadas en ella.
De esta forma, cada celda de la malla irregular puede aportar a una o más celdas de la grilla
regular. El código de conversión puede ser encontrado en el Apéndice F.2 e incluye la lectura de
los archivos CHR de salida de la simulación Code Saturne. Dichos archivos poseen información
escalar (como la concentración de trazador pasivo) o vectorial (como las componentes del campo
de velocidades) en formato Ensight Gold [12] que permite post-procesamiento y visualización de
los valores para una geometrı́a de la experiencia.
Luego de obtener la conversión a una grilla homogénea, se calcula el TKE instantáneo en
la superficie que comprende la región bajo estudio. Un análisis detallado de la TKE demuestra
que la energı́a asociada con las fluctuaciones disminuye considerablemente luego de iniciado
el ciclo de control (Fig. 4.6.9). El cambio observado en el escenario controlado respecto de la
experiencia sin control corresponde a una reducción de aproximadamente el 85 % del TKE. El
código de implementación puede ser encontrado en el Apéndice F.3.
Figura 4.6.9: Valores de la Energı́a Cinética de la Turbulencia (TKE) instantánea en la transición del sistema al
activar el controlador. Los valores fueron normalizados por unidad de superficie con una discretización cuadrada
de 0,045 y corresponden a la región definida por −5 < x < 20, −5 < y < 5. El controlador es activado en el paso
de tiempo 500 provocando una caı́da del TKE de aproximadamente el 85 %. Se incluyen los valores medios antes
y después de iniciado el control a modo de referencia.
El impacto del control puede apreciarse también en el gráfico del desvı́o estándar (Standard
Deviation o STD) de la velocidad en el sentido del flujo. En este caso se toma la componente X
del campo de velocidades en cada paso de tiempo y se calcula el STD para cada celda según:
v
u
u1 X N
ST D = t (ujx (k) − µj )2 ,
N
k=1
donde ujx (k) corresponde a la velocidad en X para una celda arbitraria j y µj indica el valor
medio calculado en dicha celda. Esta medida es similar al concepto de media cuadrática (Root
Mean Square o RMS) salvo que en ésta última no se considera el valor de la media:
v
u
u1 X N
RM S = t (ujx (k))2 ,
N
k=1
En el caso particular de señales con media nula, los valores de STD coinciden con RMS. Por otro
lado, resulta claro que el cálculo del RMS sobre las fluctuaciones de la velocidad (ujx (k) − µj )
coincide exactamente con su cálculo de STD.
Realizando el cálculo del RMS de las fluctuaciones para cada celda se puede obtener un gráfico
que entregue una idea de la dispersión en las velocidades para el escenario sin actuación (Fig.
4.6.10) y para el controlado (Fig. 4.6.11). Se puede observar que el sistema de control modifica
la dispersión del campo de velocidades concentrando las fluctuaciones dentro del “túnel”de
sensores.
Figura 4.6.10: RMS de las fluctuaciones de la velocidad en X para el escenario sin control. La lı́nea horizontal en
y = 0,415 atraviesa el valor máximo del RMS en el hemisferio superior.
Figura 4.6.11: RMS de las fluctuaciones de la velocidad en X para el escenario controlado. La lı́nea horizontal en
y = 0,280 atraviesa el valor máximo del RMS en el hemisferio superior.
En ambas figuras se traza una lı́nea sobre la ordenada que posee el valor máximo en el
hemisferio superior. La simetrı́a del problema garantiza un comportamiento similar en el inferior
(no incluido en el análisis). Graficando el valor del RMS a lo largo de dicha lı́nea se puede
comparar el descenso marcado de los valores del RMS máximos de un escenario al otro (Fig.
4.6.12). A su vez, el valor pico se mueve de la lı́nea definida por y = 0,415 en el caso sin actuación
a y = 0,280 en el caso controlado, demostrando el efecto de estabilización en la estela. Estos
resultados son similares a los obtenidos en experiencias de control a lazo abierto en laboratorio
sobre el escurrimiento de cilindro con Re = 235 [18].
Figura 4.6.12: RMS de las fluctuaciones (STD) de la velocidad en X a lo largo de la ordenada que atraviesa los
valores máximos en los escenario con y sin actuación. Los valores guardan correspondencia con las lı́neas marcadas
en Figs. 4.6.10 y 4.6.11.
La Fig. 4.6.13 compara el TKE obtenido con un ruido sobre el flujo de entrada de 10 % de
amplitud. En este caso se agrega el ruido a la condición de contorno correspondiente al borde
de entrada de forma uniforme.
Figura 4.6.13: Valores instantáneos del TKE al agregar ruido pseudo-aleatorio con 10 % de amplitud en la velocidad
del flujo de entrada. A modo de referencia, se grafica el valor obtenido en el caso ideal y los valores medios de
ambos escenarios.
La Fig. 4.6.14 muestra el efecto de aplicar ruido al inyector del trazador pasivo con una ampli-
tud del 10 %. Nuevamente, se modifican las condiciones de contorno para variar la concentración
inyectada en cada paso del tiempo.
Figura 4.6.14: Valores instantáneos del TKE al agregar ruido pseudo-aleatorio con 10 % de amplitud sobre la
concentración de la inyección de trazador pasivo. A modo de referencia, se grafica el valor obtenido en el caso
ideal y los valores medios de ambos escenarios.
La Fig. 4.6.15 expone los resultados de aplicar ruido de amplitud 0,1 % en las mediciones
obtenidas de los sensores. Para ello se modifica el sistema de control y se introduce un com-
ponente pseudo-aleatorio luego del parseo de los archivos con muestras. En todos los casos, el
comportamiento del sistema de control fue satisfactorio verificándose su robustez y manteniendo
el porcentaje de reducción del TKE del escenario ideal.
Figura 4.6.15: Valores instantáneos del TKE al agregar ruido pseudo-aleatorio con 0,1 % de amplitud sobre la
concentración medida en los sensores. A modo de referencia, se grafica el valor obtenido en el caso ideal y los
valores medios de ambos escenarios.
Del mismo modo, se consideran alteraciones en la velocidad de entrada que implican cambios
de hasta un 20 % en el número de Reynolds. Para este propósito se varı́a el valor de la velocidad
de entrada utilizando una rampa hasta alcanzar el nuevo valor. Luego de cierta cantidad de
iteraciones de simulación, se reestablece el valor original con una nueva rampa. La Fig. 4.6.17
plantea un cambio descendente de la velocidad hasta alcanzar el valor de Re = 219 (represen-
tando una variación del 7 % respecto del valor original de Re = 235). La Fig. 4.6.16 presenta un
cambio ascendente hasta un valor de Re = 282 (variación del 20 % respecto del original).
Figura 4.6.16: Respuesta del sistema de control frente a cambios de Re = 235 a Re = 219. Se modifican las
condiciones de entrada hasta obtener el nuevo valor. Luego de varios ciclos de simulación se retorna a la condición
original. Sup.: Concentración del escalar medida en el sensor 1 y valor de referencia con el Re de simulación para
cada instante de tiempo. Inf.: Amplitud del actuador calculado por el sistema.
Figura 4.6.17: Respuesta del sistema de control frente a cambios de Re = 235 a Re = 282. Se modifican las
condiciones de entrada hasta obtener el nuevo valor. Luego de varios ciclos de simulación se retorna a la condición
original. Sup.: Concentración del escalar medida en el sensor 1 y valor de referencia con el Re de simulación para
cada instante de tiempo. Inf.: Amplitud del actuador calculado por el sistema.
En ambos casos, el sistema de control se adapta y estabiliza la estela del cilindro para
las nuevas condiciones. Las flexibilidad del controlador se demuestra en cambios no sólo de la
amplitud del controlador sino en la frecuencia de control que se ve claramente afectada. Luego de
un perı́odo transitorio tanto en las rampas positivas como en las negativas, el sistema de control
se muestra capaz adaptar las predicciones sobre el modelo y calcular una actuación óptima para
el nuevo escenario.
Los valores de TKE obtenidos en al modificar el número de Reynolds son comparados con
simulaciones a iguales Re pero sin actuación (Fig. 4.6.18). En ambos casos se obtienen impor-
tantes disminuciones en el TKE, obteniendo una reducción de aproximadamente un 80 % con
Re = 219 y 73 % con Re = 282.
Figura 4.6.18: Valores instantáneos del TKE obtenidos en el sistema controlado luego de modificar el número de
Reynolds a Re = 219 y Re = 282. A modo de referencia, se grafica el valor medio correspondiente al caso no
controlado con dichos números. El eje temporal guarda correlación con las simulaciones graficadas en Figs. 4.6.17
y 4.6.16.
106
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
los mismos se observa la estabilización de la estela y reducción del TKE en comparación con el
caso sin actuación (reducción aproximada de un 80 % con Re = 219 y 73 % con Re = 282).
Conclusiones Generales y
Perspectivas
108
5.1 Conclusiones Generales
Se desarrolló un sistema de control lineal de flujos a lazo cerrado basado en el análisis visual
sobre las lı́neas de emisión de un flujo. El controlador se basa en la modelización del flujo
mediante modelos de caja negra y la optimización de un objetivo de control utilizando técnicas
predictivas. Se utiliza un modelo lineal ARX para describir la dinámica del sistema a controlar
y se aplica un algoritmo de GPC para calcular la actuación óptima a cada paso de tiempo con
una ley de control lineal.
El sistema fue implementado y puesto a prueba mediante simulaciones numéricas que de-
mostraron su efectividad y robustez frente a variaciones en las condiciones de entrada. Como
experiencia prototipo para los ensayos se eligió el escurrimiento de un cilindro por tratarse de
un fenómeno de oscilaciones auto-sostenidas, sistemas conocidos por la existencia de fuertes
no-linealidades.
El controlador estabilizó la estela del cilindro basándose en la medición de trazadores pasivos
en 8 sensores colocados aguas abajo y utilizando actuadores de plasma simétricos para agregar
cantidad de movimiento tangencial al cilindro. Esta configuración demostró una reducción de la
energı́a cinética de las fluctuaciones (TKE) de más de un 80 %. Esta verificación empı́rica muestra
la validez del controlador lineal bajo escenarios adversos, donde los esfuerzos y recientes avances
cientı́ficos son orientados al uso de estructuras no-lineales de mayor complejidad.
De esta manera se obtiene un importante avance con implicancias en el área del control de
fluidos en tiempo real, donde la simpleza y su carácter genérico juegan roles fundamentales para
conseguir una performance adecuada y la factibilidad técnica de su construcción.
109
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
de GPGPU mediante CUDA C/C++ para optimizar los tiempos de identificación del sistema,
factor clave para permitir el uso del sistema de control en una experiencia real de laboratorio.
Otro paso importante en este sentido, consiste en la compatibilidad que ofrece C++ en la
interacción con dispositivos periféricos como ser cámaras digitales o generadores de señales. En
este sentido, se realizaron pequeños sistemas experimentales para la obtención de imágenes que
podrı́an integrarse fácilmente en el controlador y reemplazar el uso del simulador.
Tanto el diseño de los algoritmos de identificación del sistema y de control como la defini-
ción de la experiencia prototipo, la preparación de la simulación numérica y la verificación de
resultados, representaron un enorme desafı́o de trabajo interdisciplinario. La coordinación de
esfuerzos dentro de un equipo de trabajo con áreas de conocimiento tales como la matemática,
fı́sica, fluidodinámica y teorı́a de control resulta ardua, pero es a su vez un trabajo desafiante
y fructı́fero. Es importante remarcar el papel que juega la informática en este contexto, don-
de se requiere la cristalización de distintas concepciones teóricas en una experiencia de ciencia
aplicada. La correcta simulación, comunicación entre sistemas nuevos o existentes, algoritmia
aplicada, análisis de tiempos o capacidades de cómputo resultan factores fundamentales para
garantizar el éxito de estas lı́neas de investigación.
El presente trabajo establece una base importante para el desarrollo de distintos proyectos
de control a lazo cerrado de fluidos.
Quizá las mayores perspectivas del sistema de control desarrollado consisten en su implemen-
tación en una experiencia real de laboratorio. Con este objetivo en consideración se desarrolló un
programa externo al simulador y que pudiera conectarse fácilmente con dispositivos de labora-
torio como cámaras o generadores de señales. A su vez, los pequeños avances experimentales
sobre el uso de GPGPU con CUDA C/C++ marcan el camino de evolución del sistema para
responder frente a las exigencias de velocidad y previsibilidad de un sistema en tiempo real.
La elección de ARX como modelo matemático fue componente importante del sistema cons-
truido. Este modelo, sin embargo, no contempla la existencia de ruido en las señales. Una
variación de modelos auto-regresivos que contempla dicho comportamiento puede encontrarse
en modelos ARMAX. La extensión del sistema de control en este sentido podrı́a significar un
paso importante para garantizar la robustez del control frente a condiciones reales.
Otro factor que resulta de gran interés consiste en el uso de una cantidad mayor de sensores
visuales. La modificación de posiciones, sensibilidad y cantidad de los sensores demostró tener
un efecto directo sobre los parámetros de tuning del controlador. Sin embargo, la extensión del
campo de visión del algoritmo GPC podrı́a asegurar la estabilidad en una zona más amplia del
fluido. El empleo entonces de una cantidad mayor de sensores permitirı́a un mejor modelo de la
realidad y la posibilidad de estabilizar experiencias que no cuenten con relaciones de simetrı́a
como la del escurrimiento bajo estudio.
En caso de mantener la disposición de sensores, es necesario evaluar el efecto de retardo que
poseen frente a cambios en la actuación. El retardo puede ser modelado mediante parámetros que
permitan modificar la posición de los sensores sin que esto afecte la sensibilidad del controlador.
Aún utilizando un controlador predictivo, existe la posibilidad de experimentar con distintas
leyes de control para el modelo identificado. Se conocen referencias a sistemas de control adapta-
tivos que fueron implementados experimentalmente para el presente trabajo. Si bien es necesario
mejorar la velocidad de convergencia, simulaciones preliminares (Apéndice D.1) demostraron re-
sultados prometedores con actuaciones más suaves y sin oscilaciones no deseadas. Por otra parte,
el aumento del orden del modelo y horizontes de predicción con el controlador original mejora su
actuación eliminando las altas frecuencias pero mantiene el carácter oscilatorio (Apéndice D.2).
Por último, se puede destacar la posibilidad de realizar un producto comercial o académico
que emplee el sistema desarrollado para simular experiencias. Aunque el éxito comercial del
producto está relacionado con la eficacia del sistema en una experiencia real aún no practicada,
el alto grado de interconexión y el carácter genérico de los algoritmos permitirı́an un gran abanico
de combinaciones entre experiencias prototipo, parámetros de control y modelos matemáticos.
111
Apéndices
112
A Reseña de Control de Fluidos
A.1. Objetivos
Los objetivos generales para el control de fluidos suelen estar vinculados a reducciones en
el costo de recursos necesarios para cierto proceso, facilitar o impedir cierto fenómeno. Estos
objetivos macro se apoyan en otros más especı́ficos que definen las particularidades del control
a aplicar sobre el flujo bajo estudio. Para ilustrar esta diferencia se puede mencionar la ma-
nipulación de fuselajes de avión para aumentar la sustentación, reducir el arrastre y demorar
la transición entre fluidos turbulento y laminar. Estos objetivos básicos no excluyentes tienen
como finalidad mejorar las condiciones de vuelo: reducción de ruidos o vibraciones, reducción del
combustible requerido para vencer la resistencia al aire, entre otras. Muchos de los estudios del
área se concentran en los objetivos especı́ficos para, una vez dominados, poder contribuir a un
objetivo de mayor envergadura. A continuación se resumen los objetivos especı́ficos de control
de fluidos que resultan más relevantes [22]:
Arrastre (drag ): El efecto de arrastre está relacionado con la resistencia al avance de cierto
cuerpo sobre un fluido. Está vinculado con la fricción que produce el fluido en movimiento
contra las superficies del cuerpo y con la creación de vórtices o cambios de presión que
dependen de la forma del cuerpo en cuestión.
Sustentación (lift): Es la fuerza perpendicular al flujo del fluido que actúa en sentido contrario
al peso del objeto en movimiento. En aeronáutica, se aplican esfuerzos continuos a la
búsqueda de escenarios con mayor sustentación sobre superficies alares para permitir ganar
altura a la aeronave. Por el contrario, en automovilismo, se realizan cambios en el fuselaje
como el agregado de alerones que disminuyen la sustentación y empujan el vehı́culo hacia
el suelo.
Separación de la Capa Lı́mite (separation): Este fenómeno se observa al aparecer una va-
riación de la velocidad del fluido demasiado grande como para que el fluido se pueda adherir
al sólido. Al ocurrir esto, las lı́neas de corriente alrededor del cuerpo se separan generando
desprendimientos en forma de vórtices o turbulencia que aumentan la resistencia al movi-
miento. Por estos motivos se pretende posponer la separación de la capa lı́mite salvo en
situaciones donde una separación temprana facilite la mezcla de ciertos fluidos.
113
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura B.1: Histograma acumulativo sobre las cantidades de celdas. Si bien se muestra el volumen de las celdas
como clasificador para la acumulación, se aclara que el mallado fue realizado 2D donde se asume una profundidad
unitaria para el cálculo volumétrico.
115
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura B.2: Tamaño en la separación del mallado para las lı́neas de la geometrı́a. El mallado en las lı́neas de
frontera se define con un tamaño mayor (0,1) al utilizado en las lı́neas que determinan el cilindro (0,03). A fines
de proveer una transición suave, es necesario agregar lı́neas ficticias que fijen separaciones intermedias (0,04 y
0,06).
Figura B.3: Tamaño en la separación del mallado para las superficies de la geometrı́a. El sistema de mallado utiliza
los tamaños definidos en las superficies para generar las celdas intermedias a las distintas lı́neas del mallado. Las
dimensiones de las celdas varı́an gradualmente entre los tamaños definidos por las lı́neas y los indicados por las
superficies encerradas entre ellas.
Figura B.4: Magnitud de la velocidad en una simulación divergente. Un sector del mallado presenta celdas que no
cumplen con las condiciones de estabilidad en la cercanı́a del cilindro.
Figura B.5: Magnitud de la velocidad en una simulación divergente. Las celdas afectadas comienzan a trasladar
sus valores elevados a celdas vecinas.
Figura B.6: Magnitud de la velocidad en una simulación divergente. El error de cálculo se expande afectando a
un porcentaje elevado de las celdas en la simulación, se torna inestable y eventualmente diverge.
119
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Dado que se requieren operaciones de álgebra lineal para resolver multiplicaciones, descom-
posiciones e inversiones, se decide evaluar el uso de librerı́as Basic Linear Algebra Subprograms
(BLAS) existentes. A tal fin, se utiliza la librerı́a GNU Scientific Library (GSL) y GPU Accele-
rated Linear Algebra (CULA) siendo la primera una implementación pura en C++ y la segunda
una versión BLAS que da soporte a rutinas CUDA. A fin de comparar la velocidad de las im-
plementaciones, se crea una abstracción de matriz utilizando el tipo de dato abstracto de GSL
pero con implementaciones de las operaciones con ambas librerı́as.
El conjunto de datos utilizados coincide con la la fase de entrenamiento del sistema con la
actuación de un pulso y N = 1090 muestras. En cada caso, se realizó un promedio sobre los
valores obtenidos de dos ejecuciones. Se mide el tiempo de ejecución total y el ajuste de cada
coordenada del vector de estado obteniendo un ajuste promedio de todas las coordenadas, la
coordenada de ajuste mı́nimo y la de ajuste máximo. Se utiliza aproximadamente un perı́odo
caracterı́stico del fenómeno como horizonte de predicción, s = 90, para realizar la comparación
con lfd compare.m (ver Apéndice F.5).
Se emplea un equipo con procesador Intel i5 2500K con 4 cores y una velocidad de reloj de
3,3Ghz y una placa gráfica nVidia GeForce GTX 570 con 480 CUDA cores y una velocidad de
GPU de 1,57Ghz.
Cabe destacar que el nivel de ajuste se mantiene similar en todos los casos.
Figura D.1: Control Adaptativo aplicado sobre el escurrimiento del cilindro. Se puede apreciar el carácter asintótico
de la señal de actuación.
122
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
Figura D.2: Comparación de control adaptativo con distintos parámetros de ajuste. Se puede observar gran
diferencia en los resultados de control frente a cambios en los parámetros, pudiendo divergir (lı́nea azul) o mantener
una progresión asintótica (lı́nea verde) con cambios menores en las variable de ajuste.
Figura D.3: Tamaño en la separación del nuevo mallado para las lı́neas de la geometrı́a.
Figura D.4: Tamaño en la separación del nuevo mallado para las superficies de la geometrı́a.
Luego, se empleó el sistema de control bajo estudio cuyo código fuente se encuentra en el
Apéndice F.6 ampliando el valor del órden del modelo, p. Los primeros resultados no fueron
positivos pero se pudo observar una mejora notable al realizar un muestreo más lento sobre los
valores de simulación (practicando under-sampling). En este caso se obtuvo una señal de control
mucho más suave que en las experiencias originales, que controla los valores de escalar sin el
agregado de fluctuaciones ni señales de alta frecuencia indeseables (Fig. D.5).
A fin de ajustar los parámetros de control con el nuevo orden del modelo, fue necesario
modificar los pesos de los sensores. El resumen de los parámetros de control se puede observar
en la Tabla D.1.
Tabla D.1: Valores definidos para los distintos parámetros de control del sistema.
Figura D.5: Experiencia de control realizada sobre una nueva malla utilizando órdenes de modelo ARX elevados.
En este caso, utilizando p = 150, se consigue un control estable luego de reducir la frecuencia de muestreo a la
mitad de la empleada en el control original.
Crop/
Nombre Resol. Máx. FPS ROI Buffer Tipo de Transferencia
PixelFly qe - Cooke Coroporation 640x480 50 Si Sin buffer Directa por RJ45 en placa Adq.
SpeedCam Mini Vis e2 - Weinberger 512x512 2500 Si 2GB buffer Desde buffer por Ethernet 1Gbit
TM9701 - Pulnix 768x484 30 No Sin buffer Directa por placa Adq. PXD
Tabla D.2: Caracterı́sticas de cámaras digitales evaluadas para la adquisición de imágenes en futuros escenarios
de control en tiempo real.
D.3.1. PixelFly qe
Se escribe el código de captura usando la API provista por PixelFly y se miden los tiempos
aproximados. En este caso se cuenta con un SDK unificado para las PixelFly y las cámaras de
la familia Sensicam llamado Uniform SDK. Dicha librerı́a posee una interfaz clara y requiere
elementos de WinApi siendo por demás portable. Los resultados obtenidos se resumen según:
D.3.2. Pulnix
Se trata de una cámara anticuada con una API de control del adaptador provista por la
empresa Imagenation. Se posee documentación de la API y se realiza un sistema que retorna los
siguientes resultados:
127
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
(1)
Figura 1. Esquema del experimento. Ubicación de actuadores
y sensores de concentración del escalar durante la simulación donde y(k) es un vector de m x 1 que representa el
2D (Re:235, dt:0.061, cilindro centrado verticalmente a 7.5 estado del sistema (la salida), u(k) es un vector de r x 1
diámetros de la entrada sobre una superficie de 27.5 x 25 que representa la actuación (la entrada), p es el orden
diámetros. del modelo, k es el paso del tiempo. En el caso que
estudiamos y(k) es un vector que contiene la medida
Con este diseño la actuación procura posponer la instantánea de concentración del trazador en las
separación de la capa límite. distintas posiciones de los sensores y u(k) representa la
Luego de mallar la geometría del sistema en 2D, se amplitud instantánea de los actuadores.
utiliza el aplicativo Código Saturne para realizar Nos referimos al sistema definido por (1) como un
simulaciones de elementos finitos. modelo Modelo autoregresivo con entrada exógena
En cada paso de la simulación se mide la (ARX). Los coeficientes matriciales del modelo,
concentración de un escalar pasivo que se inyecta con para 1 ≤ i ≤ p, para 0 ≤ i ≤ p , de m x m y m x r
flujo constante aguas arriba del cilindro. Los puntos de respectivamente, son llamados parámetros de Markov
sensado se ubican de manera simétrica en dirección del del observador y caracterizan al modelo10.
escurrimiento dentro de la estela formada por el cilindro Definiendo el vector de parámetros
(Fig. 2, 3 y 4).
y el vector de regresión
donde es una matriz Toeplitz dada por V. RESULTADOS DEL SISTEMA DE CONTROL
A fin de identificar el modelo del sistema, se idea
una fase de entrenamiento donde la actuación es forzada
con la señal característica de un pulso para medir su
respuesta frente a una amplia variedad de frecuencias de
entrada. Los valores medidos son utilizados en la Ec. 2
para formar los coeficientes de control en base al
modelo estimado (Fig. 5).
7- Thiria B., Goujon-Durand S., and Wesfreid J. Journal of 12- Kegerise M.A., Cambell R.H., and Cattafesta L.N. Journal
Fluid Mechanics, 560, 123–147 (2006). of Sound and Vibration, 307, 924–940 (2007).
8- Protas B. and Styczek A. Physics of Fluids, 14(7), 2073– 13- Huang S.C. and Kim J. Physics of Fluids, 20(101509)
2087 (2002). (2008).
9- Beaudoin J.F., Cadot O., Aider J.L., and Wesfreid J.E. 14- Hervé A., Denis Sipp P.J.S., and Samuelides M. Journal of
Physics of Fluids, 18(085107) (2006). Fluid Mechanics, 702, 26–58 (2012).
10- Juang J.N. and Phan M. Deadbit predictive controllers. 15- D’Adamo J., González L.M., Gronskis A., and Artana G.
Technical Memorandum 112862, Nasa (1997). Fluid Dynamics Research, 44(055501), 20 (2012).
11- Kegerise M.A., Cambell R.H., and Cattafesta L.N. Journal 16- Ljung L. System Identification: Theory for the User.
of Sound and Vibration, 307, 906–923 (2007). Prentice-Hall Inc., Englewood Cliffs, N.J. (1987)
I. INTRODUCTION
Control of fluid flows is a discipline with a remarkable importance for industry and science. Classical control
objectives such as reference value tracking or disturbances rejection can be applied to many configurations, including
drag reduction or instability suppression that are of great interest for practical applications.
On one hand, passive control devices aim at controlling the flow state with a given target without requiring an
external power source to operate. In this type of control, the action is permanent and is not suitable for a change in
the control parameter since they are strongly tight to the original layout of the experiment. This methodology can
be found for instance in vortex generators,1–3 or splitter plates,4 . On the other hand, active control requires applying
energy for the flow to attain a defined target. This kind of control allows changing the actuation parameters in time
to adjust the controller to new conditions in the experiment. Typical examples of actuators involved with this control
are pulsed and synthetic jets,2,5 , adjustable mechanical devices, rotating cylinders,6 or plasma actuators,7–9 . These
devices are most commonly used in an open-loop control configuration which does not involve feedback mechanisms
at time scales comparable to characteristic times of the flow nor prediction of the future state of the actuated flow.
Closed-loop control is a signal-based control that involves the estimation or measurement of the instantaneous state
of the flow to feed the controller back and adjust the control parameters in real time. This configuration thus involves
evaluation of the actuators inputs from the sensor outputs to achieve a desired effect. This kind of control is suitable
for applications with limited amount of energy to manipulate the flow and for systems intended to a relatively wide
operating envelope, thereby limiting the drop in performance associated with multiple designs.
Inferring a model describing the system, and capable of predicting the response of the flow to the forcing, from
observations is crucial to compute the necessary actuation for a given target. There basically exist two strategies
to obtain models that attempt to arrange observations into some pattern: the physics-based model approach and
the system identification approach. The former seeks a reduced order model (ROM) based on a basis deduced from
experiments. One of the usual choices of basis has been to consider a Proper Orthogonal Decomposition (POD). The
set of equations of the reduced order model is obtained by a Galerkin projection of the Navier-Stokes equation onto
the POD modes. This procedure leads to a system of ordinary differential equations of as many equations as modes
retained in the analysis. However, neglecting the high index modes usually responsible for damping of the physical
system may lead to a divergence of the resulting ROM. A description of efforts to avoid this effect can be found for
instance in10 , among others. POD modes usually exhibit multiple frequencies and it is difficult to associate their
spatial structure to an easily observable flow feature. Further, the approximation basis obtained may not be versatile
enough to accurately describe diverse flow conditions. Recently, different efforts have been dedicated to improve the
quality of the basis to remedy this limitation,11 . Another limitation of this POD-based approach is the difficulty with
the proper inclusion of an external action in the formulation, either associated to the actuation or to autonomous
disturbances to the flow.
Among the advantages of this formulation is the possibility to easily define the objective function. When it is
desired to minimize fluctuations of the flow, it is possible to directly seek for a minimization of the total energy of
the fluctuating part of the flow, which can be determined from the temporal coefficients of the modes (chronos). It is
also possible to build a ROM from the so-called global modes, but this strategy is not always well suited,12 . However,
one of the most restrictive requirements of ROM approaches is that the data used to generate the model are velocity
fields of the flow to be controlled. From the point of view of field applications, this constitutes a major limitation.
Hence, the analysis with this kind of approach has been mostly restricted to numerical benchmarks or experiments
in wind tunnels equipped with Particle Image Velocimetry (PIV) systems.
Models issued from the second approach, System Identification, are usually empirical black box models. One of
the most popular choices of this methodology is based on an autoregressive relation between current and past system
control variables and observables that constitute the state vector. Typical examples are the algorithms based on
AutoRegressions with eXogenous inputs (ARX),13–16 or AutoRegressions with eXogenous inputs and Moving Average
(ARMAX),17 . Estimation of the parameters of the model is performed using known input-output data retrieved from
flow field measurements. The estimation involves minimizing the error norm (typically in the L2 -sense) between the
model output and the actual output from the fluid flow system given the same input data sequence. Shortcomings
associated with a system identification strategy such as that described in17 comprise effects associated to non-linearities
not included in the analysis, a laborious tuning of the parameters of the model and difficulties in the definition of the
objective function.
In this work we propose an improvement upon this last point. Actuation is introduced with the purpose of forcing
some characteristic streaklines of the flow to lie into a prescribed region. The objective function to be minimized is
defined in terms of the concentration of a tracer injected upstream in the flow, at selected points downstream. To
this end, we introduce a new visualization-based approach for active fluid flow control.
This approach has similarities with the concept of visual servoing techniques. Control strategies based on vision
are well established techniques in robotics and automation communities. The method consists in using feedback
information provided by a vision sensor observing the system to be controlled. In the field of flow control, only a few
efforts have been carried-out along these lines, using the velocity flow fields as input data18–20 .
In practical applications, the techniques of flow control based on velocity field data often prove impractical. The use
of Particle Image Velocimetry (PIV) systems outside of a laboratory environment may present some problems related
to the use of powerful lasers, to the dense seeding of tracers required and to the careful alignment of sophisticated
cameras. Further, traditional PIV systems may not be rapid enough for all applications as a consequence of low
sampling rates and time required for the processing of the acquired images.
To avoid difficulties associated with the use of PIV, we here present a closed-loop control methodology simply
based on the image intensity in a set of probes (selected points of the image of the flow field). The image intensity
is proportional to the local concentration of a passive tracer injected upstream. The prototypical wake produced by
a cylinder immersed in a uniform stream is chosen as the physical system to control. The flow is controlled with
plasma actuators disposed on the cylinder surface. The present work is focused on a laminar, two-dimensional flow
at a low Reynolds number (Re, evaluated with the cylinder diameter, free stream velocity and viscosity coefficient)
of 235. This value is close to the threshold of appearance of 3-D instabilities of the non-actuated flow. However, a
synchronized plasma actuation in the span-wise direction, enlarges the range of Reynolds number in which the flow
remains 2-D and a steady plasma actuation has already been shown to be able to stabilize this kind of flow,21 . We
here test the visualization-based control on a numerical benchmark since all system variables are then easily available
and this facilitates the evaluation of the control performance. However, the present method can be easily applied in
a laboratory environment and beyond in a real application.
In section 2 of this manuscript we explain how data were generated using a numerical simulation. The system
identification algorithm is presented in section 3. In section 4, we propose a Generalized Predictive Controller (GPC)
scheme to minimize fluctuations of the wake over a predictive horizon. In section 5, the control system is tested and
results are discussed. Model validity and robustness under noise in the measurements, in the tracer injection system,
and changes in the inflow conditions are analysed.
We consider a two-dimensional flow around a circular cylinder and the control objective of stabilizing the wake
(suppression of the vortex shedding).
Simulations are performed with the code Saturne,22 . A uniform stream with constant velocity is considered as inlet
condition, and the other boundary conditions are indicated on Fig. 1. The Strouhal number of the flow (calculated
from the shedding frequency, free-stream velocity and diameter of cylinder) is close to 0.2. Considering the mesh
used and the CFL condition, the non-dimensional time step of the simulation (based on velocity of the free-stream
and cylinder diameter) was set to 0.061. A filament of a passive scalar with a unit constant concentration is injected
upstream the cylinder. The concentration of the injected scalar is monitored downstream and a control action is
applied at each simulation step. Several probes are symmetrically placed in the wake along the streamwise direction
to measure the scalar concentration (see Figs. 2 and 3). Once the non-actuated flow system attains the asymptotic
regime, the tracers concentration at each probe becomes periodic in time (Fig. 4). Note that in a physical experiment,
the tracer’s concentration at a given point can be associated to the instantaneous gray level of a pixel, or group of
pixels, in a single camera snapshot. Unless specified, we consider a perfect tracer injection system, perfect sensors and
a spatially uniform, constant in time, velocity at the inlet. In a practical implementation, there can exist fluctuations
of the injection system and the cameras used to visualize the flow have errors in the measurements. We will take
into account these effects in the closed loop problem by considering a pseudo-random noise introduced in the scalar
concentration at the injection point and a pseudo-random noise affecting measurements of the sensors. In some cases,
we will also admit that a pseudo-random noise may affect the inlet conditions and that the inlet velocity is altered
in time. Two actuators are set on the cylinder surface and add momentum tangentially to the surface. The set-up of
the simulation considers plasma actuators,23 with simultaneous and equal momentum injection over an arc length of
about 5% of the cylinder circumference (Fig. 1). The actuators are located close to the separation line with the goal
that the momentum injection produced by actuation promotes the postponement of the separation of the boundary
layer from cylinder surface. Previous studies have shown that, with this actuator configuration, a steady forcing of
amplitude high enough is able to stabilize the wake flow,21 . We here propose to stabilize the wake flow with a time
varying forcing of much lower amplitude. The actuator is simulated as in21 and24 as an imposed boundary condition
in a localized region of the surface of the cylinder. We identify the amplitude of actuation with the value of the
tangential velocity at that location at the surface of the cylinder. The control system we propose builds upon the two
actuators- that force the flow simultaneously, in phase, and with the same amplitude- and upon the measurements
obtained from eight probes. The system identification algorithm that we describe in the following section enables to
derive a model that links the amplitude of the actuation and the value of scalar concentration at each probe. The
control algorithm we consider in this work determines the command required at each time step based on the previous
values of the amplitude of actuation, on the scalar concentration at the probes measured in the past and on the future
measurements predicted by the model within a time horizon. Consequently, the controller scheme can be classified as
a multiple input multiple output (MIMO) configuration.
Figure 1. Experiment layout. Actuators and scalar concentration probes location (Re = 235, Simulation domain 27.5 × 25
diameters, cylinder vertically centred at 7.5 diameters from the inlet).
Figure 2. Instantaneous streakline pattern of the non actuated flow and values of scalar concentration at the different probes.
Figure 3. Instantaneous vorticity field of the non actuated flow and vorticity amplitude at probes location.
Figure 4. Time evolution of scalar concentration measured at probes 1 and 4 when starting the simulation. Note the difference
in amplitude and the delays in time between the two measures associated to the different positions of the probes.
where y(k) ∈ Rm is the system state (the output), u(k) ∈ Rr the actuation (the input), p ∈ N the model order and
k ∈ N the current time step.
We refer to this system as an AutoRegressive with eXogenous inputs model (ARX). The model matrix coefficients,
αi , 1 ≤ i ≤ p, and βi , 0 ≤ i ≤ p, of size m × m and m × r respectively, are the so-called observer Markov parameters
and characterize the model,13 . Sometimes the dynamics from u to y contains a delay of nd samples, so some first
coefficients βi are zero. It may be a good idea in some cases to explicitly display this delay in eq. (1). However for
easier notation and taking into account that is acceptable to underestimate delays but not to overestimate them, we
directly consider in this work nd = 0.
Defining the parameters matrix
Θ := (α1 . . . αp β0 . . . βp )T ∈ R(pm+(p+1)r)×m
and the regression vector
−y(k − 1)
..
.
−y(k − p)
ϕ(k) =
∈ Rpm+(p+1)r ,
u(k)
..
.
u(k − p)
Eq. (1) can be written as
y(k) = ΘT ϕ(k).
If we define θ as a vector of size d := pm2 + (p + 1)mr which gathers all the coefficients of matrices αi and βi , and
consider Ξ(k) := ϕ(k) ⊗ Im , ⊗ being the Kronecker product and Im the m × m identity matrix, Eq. (1) rewrites as
y(k) = ΞT (k)θ.
To estimate θ, we consider a training phase where both the actuation and the response of the physical system are
known. N training samples are used, together with a least squares criterion, to determine an estimation θ̂N
LS
of θ from
!−1
1 X 1 X
N N
LS
θ̂N = Ξ(k)ΞT (k) Ξ(k)y(k). (2)
N N
k=1 k=1
PN
When the matrix k=1 Ξ(k)ΞT (k) is close to being singular, a more effective method may be used to estimate the
25
parameters, . Defining
ΦT := (Ξ(1) . . . Ξ(N )) ∈ Rd×N m ,
Y T := (y T (1) . . . y T (N )) ∈ R1×N m ,
the estimation of θ is obtained from a QR decomposition of the N m × (d + 1) matrix [ΦY ], in which the first d
columns are those of the matrix Φ and the last column is the vector Y .
2
With these definitions, our problem consists in finding θ which minimizes kY − Φθk2 . We consider a QR-
R0
decomposition of matrix [ΦY ] = QR, Q being a N m × N m matrix with orthonormal columns and R =
0
R1 R2
a N m × (d + 1) upper triangular matrix. In particular, R0 = with R1 a d × d upper triangular matrix, R2
0 R3
a d × 1 vector, and R3 a scalar.
2
2
Q having orthonormal columns, it comes that kY − Φθk2 =
QT (Y − Φθ)
2 . Since QT Φ is the first d columns of
R and QT Y is thelast column of R, it yields
R1 θ R2
QT Φθ = and QT Y = .
0 R3
2
R2 − R1 θ
2
So, we obtain
QT (Y − Φθ)
2 =
. When minimizing this quantity and solving the system R1 θ̂ =
R3 2
2
R2 we obtain θ̂ the estimation of θ. Also note that
Y − Φθ̂
= |R3 |2 .
2
A. Tuning of parameters
The training phase was designed to collect input-output instances (Fig. 5) and identify a model of the system.
During this phase, the actuators trigger a step pulse and the scalar measurements are used in Eq. (2) to estimate
the coefficients. Considering the flow as a nonlinear dynamical systems, this forcing step perturbs the orbit in the
state space from the attractor. The system then enters a relaxation phase in which the trajectory gradually returns
to the orbit around the attractor. Analysis of these transients has been carried-out in some recent works,26 . When
the pulse step is triggered, the scalar concentration in the probes is drastically reduced during a short period of time.
This reduction occurs with different delays that depend on the distance of the probe to the cylinder. The number of
samples to be considered to train the autoregression model is related to these delays and to the time required for the
system to relax to an unperturbed flow dynamics when actuation ceases17 .
Figure 5. Training phase of the system. The four upper plots show the scalar concentration evolution in time at the different
probes during the training period. The bottom plot shows the pulsed actuation applied simultaneously to each actuator.
The variables involved in the system identification strategy are the pulse duration of the forcing, the number N of
training samples, the sampling rate, the number of probes m and their location and the horizon of autoregression p.
In our configuration, the tuning parameters have been set to p = 90 time steps, N = 1090, pulse duration of 10 time
steps and a non-dimensional sampling rate of 0.061.
B. Effects of non-linearities
A review of cylinder wake control with single sensor linear feedback control systems or systems involving several
pressure probes can be found in27 . Wake flows can be considered in general as oscillators exhibiting self-excited
oscillations. Although the von Kármán mode is the first global mode to become unsteady, a wake flow far above the
critical Reynolds number, for which the steady flow becomes unstable, may exhibit multiple interacting global modes.
Stabilization of the flow requires in principle attenuation of all these global modes. Single-sensor control is difficult
since forcing with an amplitude high enough to suppress the most unstable mode often destabilizes other modes.
Measurements at different locations within the wake are therefore not simply related by a phase shift and multiple,
spatially distributed, sensors are then required to control the flow. The present visualization-based approach is hence
well suited to stabilize a large number of modes since many sensors are available.
To account for the effect of non-linearities, a natural choice would probably have been to use a non-linear model,25 .
However, this approach is computationally more challenging and expected benefits are often limited. Discussions
about linear control approaches in non-linear flows can be found for example in16 . In particular, a strategy based
on neural networks has been proposed for a wake flow control problem in a recent work,28 . Other strategies like
adaptive identification algorithms or the stabilization of the flow prior to system identification are also possible,29 . In
agreement with the rationale of other researchers,16 , for flow control purpose, instead of deriving an accurate system
model, our primary goal is to construct a simple input-output data-based system model, which could lead to effective
feedback control laws.
When non-linear interactions between the global modes and the control input are significant, a linearised model
developed with the purpose of reducing kinetic energy fluctuation of the flow manages to suppress oscillations of the
signal at the sensor locations,30,31 . Therefore, even when non-linearities are present, the use of a linear model allows
to locally reduce the quantity to be minimized. We thus aim at deriving a model, not to control the dynamics of all
oscillating modes, but to control the dynamics of some streaklines. It hence reformulates from annihilating all unstable
modes to stabilizing solely the modes that significantly drift the flow from its prescribed pattern. It reduces to a
wake design problem in which only wake fluctuations within prescribed margins determined by the probes location are
allowed. Obviously, a physical knowledge of the flow pattern that can be associated to a stabilized flow is required.
In the case of the cylinder wake, it is well known that stabilization produces narrow and longer wakes. Hence, by
forcing the wake to exhibit this pattern one can expect that the energy associated to the fluctuations will be reduced.
To test the validity of the model, we compare tracer’s concentration signals, in conditions different from those of
the training phase, with the outputs of the identified model (90 time step ahead prediction) ŷi , i = 1, · · · , 8. We test
the model with a data set, labelled data series 1, associated to a step actuation combined with a sinus function (sinus
frequency is 225 % higher than the natural frequency of the flow), Fig. 6. We can observe a satisfactory behaviour
of the model reproducing the main frequencies of the oscillations and not dramatically straying from data (Fig. 8).
The system is stable and returns to its equilibrium state once the actuation ceases. However, during the actuation
interval, the model predicts signals of tracer concentration with a high frequency component while the actual system
does not exhibit these frequencies. This can be related to saturations of the flow dynamics induced by non-linearities
that are absent in the identified linear model we consider.
A second data series (data series 2 ) considers the case when the period of the forcing allows lock-in (Fig. 7).
The frequency of the excitation considered is here 1.25 times higher than the frequency of the natural flow and the
actuation imposes its dynamics to the vortex shedding. For this data set, the identified model reproduces the signals
at the probes correctly without introducing significant spurious frequencies (Fig. 9).
Letting s ∈ N be the prediction horizon, we define vectors ys ∈ Rsm , us ∈ Rsr and vp ∈ Rp(m+r) according to
ŷ(k) u(k)
ys (k) := .. ..
. , us (k) := . ,
ŷ(k + s − 1) u(k + s − 1),
Figure 6. Model behaviour with data series 1. In the upper plots are shown the scalar concentration evolution in time at
different probes during the experiment. The bottom plot shows the actuation applied simultaneously to each actuator. The
actuation is a step combined with a sinus function having a frequency of 225 % higher than the natural frequency of the flow.
y(k − 1)
..
.
y(k − p)
vp (k − p) :=
u(k − 1) .
..
.
u(k − p)
From Eq. (1) we can obtain a matrix expression to predict future outputs of the system,
Figure 7. Model behaviour with data series 2 in a lock-in regime. In the upper plots are shown the predictions of the
identified model for the scalar concentration evolution in time at different probes. The bottom plot shows the actuation applied
simultaneously to each actuator. Actuation is a sinus function with a frequency 125 % higher than the natural frequency of
the flow.
β0
β0(1) β0
(2) (1)
T :=
β0 β 0 β0
... ... ... ... ...
(s−1) (1)
β0 . . . . . . β 0 β0
(1) (s−1)
with β0 , β0 , . . . β0 known as system Markov parameters, and T and Ψ matrices of size ms × sr and ms × p(m + r)
respectively. They are obtained by a series of recursive relations from the model parameters as described in13 .
(k)
The so-called pulse response parameters of the system β0 are obtained from:
10
Figure 8. Comparison of spectrograms of the simulation (left) and predictions of the model built through system identification
(right) for the data set of Fig. 6.
Figure 9. Comparison of spectrograms of the simulation (left) and predictions of the model built through system identification
(right) for the data set of Fig. 7.
(0)
β0 = β0 ,
k
X
(k) (k−i)
β0 = βk + αi β0 , 1 ≤ k ≤ p,
i=1
p
X
(k) (k−i)
β0 = αi β0 , k > p.
i=1
11
(0)
α1 = α1 ,
k
X
(k) (k−i)
α1 = αk+1 + αi α1 , 1 ≤ k ≤ p − 1,
i=1
k
X
(k) (k−i)
α1 = αi α1 , k ≥ p,
i=1
(j) (j−1) (j−1)
β1 = α1 β1 + β2 ,
..
.
(j) (j−1)
βp−1 = α1 βp−1 + βp(j−1) ,
(j−1)
βp(j) = α1 βp ,
(j) (j−1) (j−1)
α1 = α1 α1 + α2
,
..
.
(j) (j−1)
αp−1 = α1 αp−1 + αp(j−1) ,
(j−1)
αp(j) = α1 αp .
We consider a control algorithm based on Generalized Predictive Controller (GPC),14 , with the objective of de-
creasing the scalar concentration measured by the sensors. The algorithm generates, at each sampling instant, the
future s inputs that minimize the cost function
J = ysT (k)Qys (k) + λuTs (k)us (k) (4)
where Q is a sm × sm block diagonal matrix with blocks Qi := diag(q1 . . . qm ), with qi the weight of sensor i,
0 ≤ qi ≤ 1. The values of these weights are set to unity. The use of different weight values for each probe i allows,
for instance, to take into account the downstream diffusion of the vorticity of the tracer. An improved version of this
cost function with vectors ys ranging from k + nd to k + s − 1 , gives the possibility to take into account the delays
from inputs to outputs. However, for the sake of simplicity, we consider in this manuscript nd = 0 .
The parameter λ of Eq. (4) penalizes the actuation magnitude. In our experiments, λ has always been set to 4.
Note that minimizing the cost function J does not necessary imply minimizing the kinetic energy of fluctuations.
This goal is achieved only by a suitable choice of probes location. The minimization of the cost function only allows
to penalize certain, undesirable, streaklines.
We consider a linear control law, us (k) = Kvp (k − p), with K a sr × p(m + r) matrix containing the controller
coefficients.
Applying Lagrange’s method to minimize J under the constraint given by Eq. (3), we consider the Lagrangian
L = J + hl, ys − T us − Ψvp i, where l ∈ Rsm denotes the Lagrange multiplier, and h·, ·i is a suitable inner product of
Rsm , yielding the system of optimality:
ys − T us − Ψvp = 0,
2Qys + l = 0,
2λus − T T l = 0.
One then obtains K = −(T T QT + λIsr )−1 T T QΨ, hence
us (k) = −(T T QT + λIsr )−1 T T QΨvp (k − p) (5)
where Isr represents the sr × sr identity matrix.
a. Since only the actuation value for the current time step k is required, only the first r rows of the product in
the first term of Eq. (5) are considered, so that finally
u(k) = {−(T T QT + λIsr )−1 }r T T QΨvp (k − p). (6)
Once the actuation u is computed from Eq. (6) and the measurements y are taken, vp is updated and the whole
process is repeated at the next time step. The resulting control algorithm is now summarized:
12
Once the control parameters are tuned, the physical model is simulated and the trained controller determines an
actuation signal that stabilizes the flow.
In Fig. 10, the clear link between actuation and scalar concentration is shown. As we can see, once the actuation is
activated and after a short period of time, the control system stabilizes. A decrease (increase) of scalar concentration
detected by the sensors leads to a fast decrease (increase) of the magnitude of actuation. The instantaneous images
of streaklines (Fig. 11) and vorticity field (Fig. 12) compared to the non-actuated flow (Figs. 2 and 3) show the
stabilization of the wake as a consequence of the forcing and how the wake is controlled.
To further illustrate the stabilization of the wake, we represent in Fig. 13 the energy associated with fluctuations
as a function of time for the non-actuated and the actuated flow. As we can see, a reduction of about 85 percent in
energy is obtained.
The control impact can also be appreciated from the plot of the RMS fields of the velocity in the stream-wise
direction (Figs. 14 and 15). As can be seen, the control system forces the wake fluctuations to be concentrated within
the narrow path delimited by the probes. We show on Fig. 16 the RMS values along an horizontal line containing the
point that exhibits the maximum value of fluctuations (indicated as white lines on Figs. 14 and 15). The decrease
of the peak values of the RMS and the shift of this maximum towards downstream positions that we can observe in
Fig. 16 indicates the stabilizing effect of the control on the wake. These results are similar to those obtained with a
continuous forcing,21 .
The validity of the control algorithm under conditions different from the training configuration is now considered
with cases in which a pseudo-random noise of amplitude 10% affects the uniform inlet flow velocity (Fig. 17), a
pseudo-random noise of 10% affects the concentration injection (Fig. 18) and pseudo-random noise of 0.1% affects
sensor measurements, (Fig. 19). In all these cases the behavior of the control system was satisfactory and illustrates
its robustness.
Alteration of the inlet velocity was also considered with changes up to 20% in the Reynolds number. For this
purpose we considered a time varying velocity at the inlet following an ascending (resp. descending) ramp, plateaued
at the new value and then decreased (resp. increased) to the original one. We can observe on Figures 20 and 21
that the controller is able to adapt the command and preserve the control performance. After a transient, the control
system stabilizes the cylinder wake under the new conditions and the fluctuating energy diminishes (Fig. 22).
VI. CONCLUSIONS
A visualization-based closed-loop control system was developed and tested in a numerical simulation. The approach
we propose is based on images of the flow and essentially consists in preventing the flow field to exhibit some patterns.
A laminar flow around a circular cylinder was chosen to demonstrate the algorithm performance in reducing the wake
oscillations amplitude. The control was achieved via plasma actuators disposed on the cylinder surface that add
momentum tangentially to the cylinder surface close to the boundary layer separation line. The control system is
based on an ARX system identification model with a Generalized Predictive Controller.
The flow considered here exhibits global instabilities with amplitudes that are driven by the non-linear interaction
of the modes. Single-sensor control of this kind of flow is difficult since forcing with an amplitude high enough to
suppress the most unstable mode often destabilizes other modes. Indeed, the un-modelled non-linear dynamics may
13
Figure 10. Closed-loop control results. Scalar concentration at different probes and amplitude of actuation as a function of
time.
severely limit the performance of control systems based on a single or very few probes. The present visualization-
based system effectively relies on a large number of non-intrusive sensors. The resulting linear controller was shown to
achieve an efficient feedback control with a reduction of more than 80% in the mean fluctuating kinetic energy. In the
context of separated flows, the control effectiveness is often limited by the absence of workable cost functions16 . In this
regard, our study represents a step forward, extending the use of linear system models in complex flows by allowing
the choice of a suitable cost function. The goal of this work was restricted to obtaining a narrow wake, which, for
this kind of flow, is known to produce a reduction of the kinetic energy associated with wake fluctuations. Extensions
to other goals usually considered in separated flows like lift enhancement or separation reduction are possible by a
suitable choice of the probes location.
Compared to noise amplifier flows, the present test case puts markedly less stringent constrains on how to take into
account the effects of external disturbances in the control strategy. The robustness of the control system was tested
by considering pseudo-random noise in the measures of the sensors, tracer injection system and uniformity of the inlet
flow. We also tested the ability of the controller to adjust to a new inlet velocity. In all these cases, and within the
range of the parameters studied, we obtained satisfactory results, achieving a reduction of the wake fluctuations energy
of about 85%. These results provide confidence in application of this approach to physical experiments that may be
close to field configurations. The number of probes required depends on the characteristics of the flow considered and
the tuning of parameters may be laborious in some cases. In physical experiments, the use of a numerical benchmark to
14
Figure 11. Instantaneous streaklines and values of scalar concentration at the probes of the controlled wake.
Figure 12. Instantaneous vorticity field and values at the probes of the controlled flow.
Figure 13. Instantaneous and time-averaged kinetic energy of fluctuations for the non-actuated and controlled flow. Control is
activated at time step number 500.
15
Figure 14. RMS of the velocity in the stream-wise direction for the non-controlled flow. The horizontal white line at y=0.415
is in correspondence with the maximum of the RMS.
Figure 15. RMS of the velocity in the stream-wise direction for the controlled flow. The horizontal white line at y=0.280 is in
correspondence with the maximum of the RMS.
Figure 16. RMS of the velocity in the streamwise direction along white lines indicated on figures 14 and 15.
16
Figure 17. Instantaneous values and time averages of the kinetic energy of the controlled flow when a pseudo-random noise of
10 % is added to the inlet flow velocity.
Figure 18. Instantaneous values and time averages of the kinetic energy of the controlled flow when a pseudo-random noise of
10% is added to the injection system.
Figure 19. Instantaneous values and time averages of the kinetic energy of the controlled flow when a pseudo-random noise of
0.1 % is added to the sensors.
17
Figure 20. Changes in the inlet condition. The Reynolds number increases from 235 to 282 and recovers its initial value following
a ramp (green-dash plot)). Upper plot: Scalar concentration at probe 1 as a function of time. Lower plot: Instantaneous
amplitude of the forcing in each actuator. The control system adapts its command to stabilize the wake to the new inlet
condition.
Figure 21. Changes in the inlet condition: The Reynolds number of the controlled flow decreases from 235 to 219 and recovers
its initial value following a ramp (green-dash plot)). Upper plot: Scalar concentration at probe 1 as a function of time. Lower
plot: Instantaneous amplitude of the forcing in each actuator. The control system adapts its command to stabilize the wake
to the new inlet condition.
determine the appropriate parameters may simplify this procedure. Compared with other control techniques relying
on images of the flow, some advantages of the present implementation are the simplicity of the instrumentation
required and a reduction of the post-processing steps of the acquired images. The proposed control methodology
is generic enough to be adapted to other experiments, in particular those involving three-dimensional flows where
the tracer concentration can be monitored with images acquired from two or more cameras suitably disposed. The
present work can be considered as a proof-of-concept and an actual application to a real-world problem may benefit
from the use of a more robust ARMAX model instead of the present ARX implementation. Mutatis mutandis, the
corresponding control methodology is quite similar.
18
Figure 22. Instantaneous and time averages of kinetic energy fluctuations when inlet conditions change in time as in Figs. 20
and 21.
ACKNOWLEDGMENTS
We thank C. Collewet for helpful comments. This research is supported by grants of the UBA, CONICET and
CNRS.
REFERENCES
1 J. Lin, “Review of research on low-profile vortex generators to control boundary-layer separation,” Progress in Aerospace Sciences 38,
389–420 (2002).
2 G. Godard and M. Stanislas, “Control of a decelerating boundary layer. part 3: Optimization of round jets vortex generators,” Aerospace
an adverse pressure gradient,” Flow, Turbulence and Combustion 78, 331–363 (2007).
6 B. Thiria, S. Goujon-Durand, and J. Wesfreid, “The wake of a cylinder performing rotary oscillations,” Journal of Fluid Mechanics
(2009).
13 J.-N. Juang and M. Phan, “Deadbit predictive controllers,” Technical Memorandum 112862 (Nasa, 1997).
14 M. A. Kegerise, R. H. Cabell, and L. N. Cattafesta, “Real time feedback control of flow-induced cavity tones - part 1: Fixed-gain
electrohydrodynamic forcing: a linear stability analysis,” Fluid Dynamics Research 44, 20 (2012).
22 F. Archambeau, N. Méchitoua, and M. Sakiz, “Code_saturne: a finite volume code for the computation of turbulent incompressible
19
23 J. R. Roth, D. M. Sherman, and S. P. Wilkinson, “Electrohydrodynamic flow control with a glow-discharge surface plasma,” AIAA
Journal 38, 1166–1172 (2000).
24 A. Gronskis, R. Sosa, and G. Artana, “Modelling ehd actuation with a slip velocity,” (2009).
25 L. Ljung, System Identification: Theory for the User (Prentice-Hall Inc., Englewood Cliffs, N.J., 1987).
26 G. Tadmor, O. Lehmann, B. R. Noack, and M. Morzynski, “Mean field representation of the natural and actuated cylinder wake,”
% Rutina para extrudar una malla 2D del GID (leida en formato .msh)
% una distancia dz y guardarla con formato .msh para utilizar en code saturne
% Lectura de la malla 2D
fid = fopen(unit1, ’r’);
nnodes = textscan(fid, ’ %f’, 1, ’headerlines’, 4);
node_coords = textscan(fid, ’ %f %f %f’, nnodes{1});
nelems = textscan(fid, ’ %f’, 1, ’headerlines’, 3);
elems = textscan(fid, ’ %f %f %f %f %f %f %f %f %f’, nelems{1});
layers = textscan(fid, ’ %d %q’, layers_number, ’headerlines’, 3);
fclose(fid);
%Matriz de conectividad
n1=0;n2=0;n3=0;
for i=1:nelems{1}
if elems{2}(i)==1
n1=n1+1;
152
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
elseif elems{2}(i)==2
n2=n2+1;
elseif elems{2}(i)==3
n3=n3+1;
end
end
nelems_lin=n1;
nelems_tri=n2;
nelems_quad=n3;
nelemens_tot=nelems_lin+3*(nelems_tri+nelems_quad);
Elemconec1=zeros(nelems_lin,9);
Elemconec2=zeros(2*nelems_tri,8);
Elemconec3=zeros(2*nelems_quad,9);
Elemconec4=zeros(nelems_tri,11);
Elemconec5=zeros(nelems_quad,13);
n1=0;n2=0;n3=0;n4=0;n5=0;
for i=1:nelems{1}
if elems{2}(i)==1
n1=n1+1;
%elementos de superficie rectangulares (frontera)
Elemconec1(n1,1)=i;
Elemconec1(n1,2)=3;
Elemconec1(n1,3)=elems{3}(i);
Elemconec1(n1,4)=elems{4}(i);
Elemconec1(n1,5)=elems{5}(i);
Elemconec1(n1,6)=elems{6}(i);
Elemconec1(n1,7)=elems{6}(i)+nnodes{1};
Elemconec1(n1,8)=elems{7}(i)+nnodes{1};
Elemconec1(n1,9)=elems{7}(i);
end
end
nparcial=nelems_lin;
for i=1:nelems{1}
if elems{2}(i)==2
n2=n2+1;
%elementos de superficie triangulares (simentróa)
Elemconec2(n2,1)=n2+nparcial;
Elemconec2(n2,2)=elems{2}(i);
Elemconec2(n2,3)=elems{3}(i);
Elemconec2(n2,4)=Lnumber;
Elemconec2(n2,5)=elems{5}(i);
Elemconec2(n2,6)=elems{6}(i);
Elemconec2(n2,7)=elems{7}(i);
Elemconec2(n2,8)=elems{8}(i);
%elementos de superficie triangulares (la otra siemtróa en z=dz)
Elemconec2(n2+nelems_tri,1)=n2+nparcial+nelems_tri;
Elemconec2(n2+nelems_tri,2)=elems{2}(i);
Elemconec2(n2+nelems_tri,3)=elems{3}(i);
Elemconec2(n2+nelems_tri,4)=Lnumber;
Elemconec2(n2+nelems_tri,5)=elems{5}(i);
Elemconec2(n2+nelems_tri,6)=elems{8}(i)+nnodes{1};
Elemconec2(n2+nelems_tri,7)=elems{7}(i)+nnodes{1};
Elemconec2(n2+nelems_tri,8)=elems{6}(i)+nnodes{1};
end
end
nparcial=2*nelems_tri+nelems_lin;
for i=1:nelems{1}
if elems{2}(i)==3
n3=n3+1;
%elementos de superficie cuadrangulares (simentróa)
Elemconec3(n3,1)=n3+nparcial;
Elemconec3(n3,2)=elems{2}(i);
Elemconec3(n3,3)=elems{3}(i);
Elemconec3(n3,4)=Lnumber;
Elemconec3(n3,5)=elems{5}(i);
Elemconec3(n3,6)=elems{6}(i);
Elemconec3(n3,7)=elems{7}(i);
Elemconec3(n3,8)=elems{8}(i);
Elemconec3(n3,9)=elems{9}(i);
%elementos de superficie cuadrangulares (simentróa)
Elemconec3(n3+nelems_quad,1)=n3+nparcial+nelems_quad;
Elemconec3(n3+nelems_quad,2)=elems{2}(i);
Elemconec3(n3+nelems_quad,3)=elems{3}(i);
Elemconec3(n3+nelems_quad,4)=Lnumber;
Elemconec3(n3+nelems_quad,5)=elems{5}(i);
Elemconec3(n3+nelems_quad,6)=elems{9}(i)+nnodes{1};
Elemconec3(n3+nelems_quad,7)=elems{8}(i)+nnodes{1};
Elemconec3(n3+nelems_quad,8)=elems{7}(i)+nnodes{1};
Elemconec3(n3+nelems_quad,9)=elems{6}(i)+nnodes{1};
end
end
nparcial=2*nelems_tri+nelems_lin+2*nelems_quad;
for i=1:nelems{1}
if elems{2}(i)==2
n4=n4+1;
%elementos de volumen tipo prisma
Elemconec4(n4,1)=nparcial+n4;
Elemconec4(n4,2)=6;
Elemconec4(n4,3)=elems{3}(i);
Elemconec4(n4,4)=elems{4}(i);
Elemconec4(n4,5)=elems{5}(i);
Elemconec4(n4,6)=elems{6}(i);
Elemconec4(n4,7)=elems{7}(i);
Elemconec4(n4,8)=elems{8}(i);
Elemconec4(n4,9)=elems{6}(i)+nnodes{1};
Elemconec4(n4,10)=elems{7}(i)+nnodes{1};
Elemconec4(n4,11)=elems{8}(i)+nnodes{1};
end
end
nparcial=3*nelems_tri+nelems_lin+2*nelems_quad;
for i=1:nelems{1}
if elems{2}(i)==3
n5=n5+1;
%elementos de volumen tipo hexahedro
Elemconec5(n5,1)=n5+nparcial;
Elemconec5(n5,2)=5;
Elemconec5(n5,3)=elems{3}(i);
Elemconec5(n5,4)=elems{4}(i);
Elemconec5(n5,5)=elems{5}(i);
Elemconec5(n5,6)=elems{7}(i)+nnodes{1};
Elemconec5(n5,7)=elems{8}(i)+nnodes{1};
Elemconec5(n5,8)=elems{8}(i);
Elemconec5(n5,9)=elems{7}(i);
Elemconec5(n5,10)=elems{6}(i)+nnodes{1};
Elemconec5(n5,11)=elems{9}(i)+nnodes{1};
Elemconec5(n5,12)=elems{9}(i);
Elemconec5(n5,13)=elems{6}(i);
end
end
end
F.2.2. chrComputeAverage.m
F.2.3. chrComputeVorticityAverageForGeoXY.m
[x,y] = meshgrid(geoXY.gridValues.x,geoXY.gridValues.y);
u = averageXY(:,:,1); v= averageXY(:,:,2);
fprintf(’Computing vorticity...\n’);
vorticityZ = curl(x,y,u’,v’);
vorticityZ = vorticityZ’;
F.2.4. chrExtractBinaryHeader.m
F.2.5. chrFindFiles.m
F.2.6. chrFindFilesAndComputeAverage.m
geo = chrReadBinaryGeo(geoFilepath);
average = chrComputeAverage(filepaths, geo, settings.isVector);
chrCleanFolderIfExists(settings.outputFolder);
header = chrExtractBinaryHeader(filepaths{1});
chrWriteBinaryContent(header, average, outputFilepath);
%ignore copyResult variable since it could fail because of user permissions
%in the OS
copyResult = copyfile(geoFilepath, settings.outputFolder);
F.2.7. chrGetAmountOfHeadingCharacters.m
F.2.8. chrReadBinaryContent.m
headerCharacters = chrGetAmountOfHeadingCharacters();
fseek(file, headerCharacters, -1);
F.2.9. chrReadBinaryGeo.m
F.2.10. chrReadVelocity2D.m
F.2.11. chrWriteBinaryContent.m
F.2.12. chrWriteCaseFile.m
fclose(file);
end
F.2.13. geoComputeIntersectionArea.m
F.2.14. geoGetBoundingRectsForDelta.m
end
end
end
F.2.15. geoTransformContentToNonXY.m
F.2.16. geoTransformContentToXY.m
end
end
end
F.2.17. geoTransformMeshToXYGrid.m
minBounds = min(geo.coordinates);
maxBounds = max(geo.coordinates);
bounds.minX = minBounds(1);
bounds.minY = minBounds(2);
bounds.maxX = maxBounds(1);
bounds.maxY = maxBounds(2);
gridBounds.minX = 0;
gridBounds.maxX = floor((bounds.maxX - bounds.minX)/xyStep);
if ~mod(bounds.maxX - bounds.minX, xyStep)
gridBounds.maxX = gridBounds.maxX - 1;
end
gridBounds.minY = 0;
gridBounds.maxY = floor((bounds.maxY - bounds.minY)/xyStep);
if ~mod(bounds.maxY - bounds.minY, xyStep)
gridBounds.maxY = gridBounds.maxY - 1;
end
if ~mod(bounds.maxX-bounds.minX,xyStep)
maxXValue = bounds.maxX - xyStep;
else
maxXValue = bounds.maxX;
end
if ~mod(bounds.maxY-bounds.minY,xyStep)
maxYValue = bounds.maxY - xyStep;
else
maxYValue = bounds.maxY;
end
gridValues.x = bounds.minX:xyStep:maxXValue;
gridValues.y = bounds.minY:xyStep:maxYValue;
F.2.18. polygonArea.m
F.2.19. polygonClip.m
%this is an implementation of
%http://en.wikipedia.org/wiki/Line-line_intersection
intersection = zeros(1,2);
detL1 = det(line1);
detL2 = det(line2);
detL1x = det([line1(:,1),[1;1]]);
detL1y = det([line1(:,2),[1;1]]);
detL2x = det([line2(:,1),[1;1]]);
detL2y = det([line2(:,2),[1;1]]);
end %computeIntersection
if ( crossVector(3) <= 0 )
in = true;
else
in = false;
end
end %inside
% % Sutherland-Hodgman Algorithm
clippedPolygon = subjectPolygon;
numVerticies = size(clipPolygon,1);
clipVertexPrevious = clipPolygon(end,:);
inputList = clippedPolygon;
clippedPolygon = [];
previousVertex = inputList(end,:);
if ( inside(inputList(subjectVertex,:),clipBoundary) )
if( not(inside(previousVertex,clipBoundary)) )
subjectLineSegment = [previousVertex;inputList(subjectVertex,:)];
clippedPolygon(end+1,1:2) = computeIntersection(clipBoundary,subjectLineSegment);
end
clippedPolygon(end+1,1:2) = inputList(subjectVertex,:);
elseif( inside(previousVertex,clipBoundary) )
subjectLineSegment = [previousVertex;inputList(subjectVertex,:)];
clippedPolygon(end+1,1:2) = computeIntersection(clipBoundary,subjectLineSegment);
end
previousVertex = inputList(subjectVertex,:);
clipVertexPrevious = clipPolygon(clipVertex,:);
if ~exist(’results’, ’var’)
processEnergy;
end
result = results{1};
settings.noActuationMean.start = 1;
settings.noActuationMean.end = 50;
settings.actuationMean.start = 409;
settings.actuationMean.end = 891;
amountOfMarkersInPlot = 0;
timeStepRange = [1 5000];
stepsQty = length(result.energy);
plotSteps = timeStepRange(1):timeStepRange(2);
markerSteps = 1:floor(max(timeStepRange)/amountOfMarkersInPlot):max(timeStepRange);
noActuationMean = mean(result.energy(settings.noActuationMean.start:settings.noActuationMean.end));
actuationMean = mean(result.energy(settings.actuationMean.start:settings.actuationMean.end));
currentFigure = figure;
handleKinetic = plot(NaN,NaN,’k-’,plotSteps, spline(result.steps,result.energy, plotSteps), ’k-’,
markerSteps, spline(result.steps,result.energy, markerSteps),’ko’,’LineWidth’, 2, ’MarkerFaceColor’, ’
k’, ’MarkerSize’, 5);
hold on;
handleMeanNoAct = plot(result.steps,repmat(noActuationMean, stepsQty,1),’r-.’, ’LineWidth’, 2);
handleMeanAct = plot(result.steps,repmat(actuationMean, stepsQty,1),’b--’, ’LineWidth’, 2);
%grid on;
legend([handleKinetic(1), handleMeanNoAct, handleMeanAct], {’Instantaneous’, ’Mean (Non-actuated)’, ’Mean (
Actuated)’})
xlabel(’Time Step Number’, ’FontSize’, 22);
ylabel(’Energy of Fluctuations’, ’FontSize’, 22);
currentAxes = get(currentFigure,’CurrentAxes’);
currentAxis = axis;
axis(currentAxes, [timeStepRange currentAxis(3:4)]);
set(currentAxes,’FontSize’,18);
title(’Kinetic energy of fluctuations per unit area - Transition from non-actuated to actuated’);
F.3.2. processEnergy.m
resultsFilepath = ’ScenarioResults.mat’;
if exist(resultsFilepath, ’file’)
load(resultsFilepath);
else
xyStep = 0.045;
%cacheFolder = ’/Users/invitado/tmp/cache’;
cacheFolder = ’/media/Datos/Pablo/Workspace/tmp/cache/0.045’;
settings.filenamesFilter = ’chr.velocity*’;
settings.geoFilename = ’chr.geo’;
settings.outputFolder = ’Out’;
settings.isVector = true;
outputFilename = ’chr.velocityaverage’;
filepaths = chrFindFiles(settings);
geoFilepath = strcat(settings.folder, ’/’, settings.geoFilename);
outputFilepath = strcat(settings.outputFolder, ’/’, outputFilename);
outputCaseFilepath = strcat(settings.outputFolder, ’/CHR.case’);
result = struct();
result.ntchr = ntchr;
result.energy = kineticEnergyPerturbIntNormalized;
result.steps = steps;
save(resultsFilepath, ’results’);
end
F.3.3. processRmsCriteria.m
PLOT = true;
xyStep = 0.045;
%cacheFolder = ’/Users/invitado/tmp/cache’;
cacheFolder = ’/media/Datos/Pablo/Workspace/tmp/cache’;
settings.filenamesFilter = ’chr.velocity*’;
settings.geoFilename = ’chr.geo’;
settings.outputFolder = ’Out’;
settings.isVector = true;
outputFilename = ’chr.velocityaverage’;
filepaths = chrFindFiles(settings);
geoFilepath = strcat(settings.folder, ’/’, settings.geoFilename);
outputFilepath = strcat(settings.outputFolder, ’/’, outputFilename);
outputCaseFilepath = strcat(settings.outputFolder, ’/CHR.case’);
if PLOT
%magnitude = sqrt(sum(binariesXY{1}.^2, 3));
reynoldsVel = computeReynoldsTensor(velocityXY.u);
varVel = std(velocityXY.u, 0, 3).^2;
rmsVel = computeRMS(velocityXY.u);
meanVel = mean(velocityXY.u,3);
figure;
subplot(121);
pcolor(x,y,reynoldsVel’);
hold on;
axis equal;
xlim([geoXY.bounds.minX geoXY.bounds.maxX]);
ylim([geoXY.bounds.minY geoXY.bounds.maxY]);
shading interp;
colorbar;
title(sprintf(’Reynolds Long. Tensor over %s Dataset’, settings.name));
subplot(122);
pcolor(x,y,varVel’);
hold on;
axis equal;
xlim([geoXY.bounds.minX geoXY.bounds.maxX]);
ylim([geoXY.bounds.minY geoXY.bounds.maxY]);
shading interp;
colorbar;
title(sprintf(’Variance over %s Dataset’, settings.name));
figure;
subplot(121);
pcolor(x,y,rmsVel’);
hold on;
axis equal;
xlim([geoXY.bounds.minX geoXY.bounds.maxX]);
ylim([geoXY.bounds.minY geoXY.bounds.maxY]);
shading interp;
colorbar;
title(sprintf(’Root Mean Square over %s Dataset’, settings.name));
subplot(122);
pcolor(x,y,meanVel’);
hold on;
axis equal;
xlim([geoXY.bounds.minX geoXY.bounds.maxX]);
ylim([geoXY.bounds.minY geoXY.bounds.maxY]);
shading interp;
colorbar;
title(sprintf(’Mean over %s Dataset’, settings.name));
end
F.3.4. computeReynoldsTensor.m
F.3.5. computeRMS.m
F.3.6. selectIntegrationCoordinates.m
!-------------------------------------------------------------------------------
! Code_Saturne version 2.0.2
! --------------------------
! This file is part of the Code_Saturne Kernel, element of the
! Code_Saturne CFD tool.
! Copyright (C) 1998-2009 EDF S.A., France
! contact: saturne-support@edf.fr
! The Code_Saturne Kernel is free software; you can redistribute it
! and/or modify it under the terms of the GNU General Public License
! as published by the Free Software Foundation; either version 2 of
! the License, or (at your option) any later version.
! The Code_Saturne Kernel is distributed in the hope that it will be
! useful, but WITHOUT ANY WARRANTY; without even the implied warranty
! of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU General Public License for more details.
! You should have received a copy of the GNU General Public License
! along with the Code_Saturne Kernel; if not, write to the
! Free Software Foundation, Inc.,
! 51 Franklin St, Fifth Floor,
! Boston, MA 02110-1301 USA
!-------------------------------------------------------------------------------
! Purpose:
! -------
! Local variables
integer iphas
!===============================================================================
! --- Turbulence (for each phase)
! 0...Laminar
! 10...Mixing length
! 20...k-epsilon
! 21...k-epsilon (linear production)
! 30...Rij-epsilon, (standard LRR)
! 31...Rij-epsilon (SSG)
! 40...LES (Smagorinsky)
! 41...LES (Dynamic)
! 42...LES (WALE)
! 50...v2f (phi-model)
! 60...k-omega SST
! For 10, contact the development team before use
iphas = 1
iturb(iphas) = 0
return
end subroutine
!===============================================================================
subroutine usinsc &
!================
( iihmpu, nfecra , nscaus , iverif )
!===============================================================================
! Purpose:
! ------
! User subroutine for input of the number of user scalars.
!-------------------------------------------------------------------------------
! Arguments
!__________________.____._____.________________________________________________.
! name !type!mode ! role !
!__________________!____!_____!________________________________________________!
! iihmpu ! i ! <-- ! indicates if the XML file from the GUI is !
! ! ! ! used (1: yes, 0: no) !
! nfecra ! i ! <-- ! Fortran unit number for standard output !
! nscaus ! i ! <-> ! number of user scalars !
! iverif ! i ! <-- ! flag for elementary tests !
!__________________!____!_____!________________________________________________!
! Type: i (integer), r (real), s (string), a (array), l (logical),
! and composite types (ex: ra real array)
! mode: <-- input, --> output, <-> modifies data, --- work array
!===============================================================================
implicit none
! Arguments
integer iihmpu, nfecra
integer nscaus
integer iverif
! Local variables
!===============================================================================
! --- Number of USER scalars (thermal or not, and whatever their carrier phase).
! These scalars come in addition to the following "basic" scalars
! (which are naturally included in the model):
! - pressure
! - turbulent variables
! - nscapp scalars introduced by an active combustion, coal,
! or electric arc module.
! Thus, for a calculation with no specific physics, the user scalars
! may for example be:
! - temperature or enthalpy,
! - mass fractions of transported scalars
! - the variance of another user scalar
! The maximum number of scalars is defined by ’nscamx’ in paramx.h;
! it is the maximum admissible value for: nscaus + nscapp.
! Set nscaus = 0 if there is no user scalar.
nscaus = 1
return
end subroutine
!===============================================================================
subroutine usipsc &
!================
( nscmax, nscaus, iihmpu, nfecra, iscavr, ivisls , iverif )
!===============================================================================
! Purpose:
! -------
! User subroutine for the input of parameters depending on the
! number of user scalars.
!-------------------------------------------------------------------------------
! Arguments
!__________________.____._____.________________________________________________.
! name !type!mode ! role !
!__________________!____!_____!________________________________________________!
! nscmax ! i ! <-- ! maximum number of scalars !
! nscaus ! i ! <-- ! number of user scalars !
! iihmpu ! i ! <-- ! indicates if the XML file from the GUI is !
! ! ! ! used (1: yes, 0: no) !
! nfecra ! i ! <-- ! Fortran unit number for standard output !
! iscavr(nscmax) ! ia ! <-- ! associated scalar number for variance scalars !
! ivisls(nscmax) ! ia ! <-> ! uniform scalar diffusivity flag !
! iverif ! i ! <-- ! flag for elementary tests !
!__________________!____!_____!________________________________________________!
! Type: i (integer), r (real), s (string), a (array), l (logical),
! and composite types (ex: ra real array)
! mode: <-- input, --> output, <-> modifies data, --- work array
!===============================================================================
implicit none
! Arguments
integer nscmax, nscaus, iihmpu, nfecra
integer iscavr(nscmax), ivisls(nscmax)
integer iverif
! Local variables
integer iutile, iscal
!===============================================================================
! --- Variance of a USER scalar:
! If we wish a user scalar j to represent the variance of a
! user scalar k, we set
! iscavr(j) = k.
! The values taken by iscavr are thus naturally greater or equal to 1
! and less than or equal to the total number of scalars.
! So, if we set iscavr(j) = k, we must have
! 0 < j < nscaus+1, 0< k < nscaus+1 and j different from k.
! For example for user scalar 3 to be the variance of user scalar 3,
! we set:
! iscavr(3) = 2
! with nscaus at least equal to 3.
! Do not intervene if you do not wish to explicitly include the
! variance of a user scalar in the simulation.
! For non-user scalars relative to specific physics (coal, combustion,
! electric arcs: see usppmo) implicitly defined in the model,
! the corresponding information is given automatically, and
! iscavr should not be modified.
! --- Variable diffusivity (ivisls=1) or constant diffusivity (ivisls=0) for
! each USER scalar, EXCEPT those which represent the variance
! of another.
! For user scalars iscal which represent the variance of another user
! scalar, we do not set ivisls(iscal) here.
! This is the purpose of the test on iscavr(ISCAL) in the example below.
! Indeed, the diffusivity of the variance of a scalar is assumed to
! have the same behavior as the diffusivity of this scalar.
! For non-user scalars relative to specific physics (coal, combustion,
! electric arcs: see usppmo) implicitly defined in the model,
! the corresponding information is given automatically, and
! ivisls should not be modified here.
! Caution: complete usphyv with the law defining the diffusivity
! ========= if and only if ivisls = 1 has been set here.
do iscal = 1, nscaus
! For user scalars which do not represent the variance of another scalar
if (iscavr(iscal).le.0) then
ivisls(iscal) = 0
endif
enddo
return
end subroutine
!===============================================================================
subroutine usipgl &
!================
( nphmax, nesmax, &
iespre, iesder, iescor, iestot, &
nphas , iihmpu, nfecra, &
idtvar, ipucou, iphydr, ialgce , iescal , iverif )
!===============================================================================
! Purpose:
! -------
! User subroutine for the setting of global parameters.
!-------------------------------------------------------------------------------
! Arguments
!__________________.____._____.________________________________________________.
! name !type!mode ! role !
!__________________!____!_____!________________________________________________!
! nphmax ! i ! <-- ! maximum number of phases !
! nesmax ! i ! <-- ! maximum number of error estimators per phase !
! iespre ! i ! <-- ! number of the prediction error estimator !
! iesder ! i ! <-- ! number of the derivative error estimator !
! iescor ! i ! <-- ! number of the correction error estimator !
! iestot ! i ! <-- ! number of the total error estimator !
! nphas ! i ! <-- ! number of active phases !
! iihmpu ! i ! <-- ! indicates if the XML file from the GUI is !
! ! ! ! used (1: yes, 0: no) !
! nfecra ! i ! <-- ! Fortran unit number for standard output !
! idtvar ! i ! --> ! variable time step flag !
! ipucou ! i ! --> ! reinforced u-p coupling flag !
! iphydr ! i ! --> ! flag for handling of the equilibrium between !
! ! ! ! the pressure gradient and the gravity and !
! ! ! ! head-loss terms !
! ialgce ! i ! <-- ! option for the method of calculation of !
! ! ! ! cell centers !
! iescal ! ia ! <-- ! flag for activation of error estimators for !
! (nesmax,nphmax) ! ! ! Navier-Stokes !
! iverif ! i ! <-- ! flag for elementary tests !
!__________________!____!_____!________________________________________________!
! Type: i (integer), r (real), s (string), a (array), l (logical),
! and composite types (ex: ra real array)
! mode: <-- input, --> output, <-> modifies data, --- work array
!===============================================================================
implicit none
! Arguments
integer nphmax, nesmax
integer iespre, iesder, iescor, iestot
integer nphas , iihmpu, nfecra
integer idtvar, ipucou, iphydr
integer iescal(nesmax,nphmax)
integer iverif
! Local variables
integer iphas, ialgce
!===============================================================================
! --- Time step (0 : uniform and constant
! 1 : variable in time, uniform in space
! 2 : variable in time and space
! -1 : steady algorithm)
idtvar = 0
return
end subroutine
!===============================================================================
subroutine usipsu &
!================
( nmodpp , iverif )
!===============================================================================
! Purpose:
! -------
! User subroutine for the input of additional user parameters.
!-------------------------------------------------------------------------------
! Arguments
!__________________.____._____.________________________________________________.
! name !type!mode ! role !
!__________________!____!_____!________________________________________________!
! nmodpp ! i ! <-- ! number of active specific physics models !
! iverif ! i ! <-- ! flag for elementary tests !
!__________________!____!_____!________________________________________________!
! Type: i (integer), r (real), s (string), a (array), l (logical),
! and composite types (ex: ra real array)
! mode: <-- input, --> output, <-> modifies data, --- work array
!===============================================================================
implicit none
include "paramx.h"
include "cstnum.h"
include "dimens.h"
include "numvar.h"
include "optcal.h"
include "cstphy.h"
include "entsor.h"
include "vector.h"
include "parall.h"
include "period.h"
include "ihmpre.h"
include "ppppar.h"
include "ppthch.h"
include "ppincl.h"
include "coincl.h"
include "cpincl.h"
include "elincl.h"
!===============================================================================
! Arguments
integer nmodpp
integer iverif
! Local variables
integer iphas, iutile, ii, jj, imom
!===============================================================================
!===============================================================================
! This subroutine allows setting parameters
! which do not already appear in the other subroutines of this file.
! It is possible to add or remove parameters.
! The number of physical properties and variables is known here.
!===============================================================================
! Calculation options (optcal.h)
! ==============================
! --- Calculation restart: isuite (= 1) or not (0)
! In case of restart, read auxiliary restart file ileaux (= 1) or not (0).
isuite = 1
ileaux = 1
! --- Duration
! ntmabs = absolute number of the last time step required
! if we have already run 10 time steps and want to
! run 10 more, ntmabs must be set to 10 + 10 = 20
! ntmabs = total_time / dtref
ntmabs = 16000
iphas = 1
iscalt(iphas) = -1
! imgr = 0: no multigrid
! imgr = 1: algebraic multigrid
! Only available for pressure and purely diffusive variables.
imgr = 0
!=========================================================================
! Physical constants (cstphy.h)
! =============================
! --- gravity (g in m/s2, with the sign in the calculation coordinate axes).
gx = 0.d0
gy = 0.d0
gz = 0.d0
! With compressibility:
! ---------------------
! ro0 is not useful, stricto sensu; nonetheless, as experience
! shows that users often use this variable, it is required
! to assign to it a strictly positive value (for example,
! an initial value).
! viscl0 is useful and represents the molecular dynamic viscosity,
iphas = 1
ro0(iphas) = 1.d0 !calculo adimensional
viscl0(iphas) = 1.d0/235.D0 !1/Reynolds
cp0(iphas) = 1.d0
t0(iphas) = 1.d0
p0(iphas) = 0.d0
iphas = 1
irovar(iphas) = 0
ivivar(iphas) = 0
if (nscaus.gt.0) then
! We loop on user scalars:
do jj = 1, nscaus
! For scalars which are not variances
if (iscavr(jj).le.0) then
! We define the diffusivity
visls0(jj) = viscl0(iphsca(jj))
endif
enddo
endif
! We give below the example of the calculation of moments <u> and <rho u v>
! the moment <u> is reread in the restart file if we are restarting,
! the moment <rho u v> is reinitialized to zero.
! Moment <u> is calculated starting from time step 1000
! Moment <rho u v> is calculated from time step 10000.
iutile = 0
if (iutile.eq.1) then
endif
return
end subroutine
!===============================================================================
TYPE probes_line
double precision xStart
double precision yStart
double precision xEnd
double precision yEnd
double precision separation
END TYPE
TYPE(probes_line) probesLines(0)
TYPE(probes_area) probesAreas(2)
!===============================================================================
! 1. Input-output (entsor.h)
!===============================================================================
! --- write auxiliary restart file iecaux = 1 yes, 0 no
iecaux = 1
! nthsav: saving period the chronological record files (they are first stored in a temporary file and then
saved every nthsav time step)
! = 0: by default (4 times during a calculation)
! = -1: saving at the end of the calculation
! > 0: period (every nthsav time step)
nthsav = 1
iProbe = 0
do iProbeLine = 1, size(probesLines), 1
ySeparationProbe = sin(atan((probesLines(iProbeLine) %yEnd - probesLines(iProbeLine) %yStart)/ &
(probesLines(iProbeLine) %xEnd - probesLines(iProbeLine) %xStart))) &
*probesLines(iProbeLine) %separation
xSeparationProbe = cos(atan((probesLines(iProbeLine) %yEnd - probesLines(iProbeLine) %yStart)/ &
(probesLines(iProbeLine) %xEnd - probesLines(iProbeLine) %xStart))) &
*probesLines(iProbeLine) %separation
iProbe = iProbe + 1
xyzcap(1,iProbe) = xProbe
xyzcap(2,iProbe) = yProbe
xyzcap(3,iProbe) = 0.00d0
do iProbeArea = 1, size(probesAreas), 1
ySeparationProbe = sign(probesAreas(iProbeArea) %separation, probesAreas(iProbeArea) %yEnd - probesAreas
(iProbeArea) %yStart)
xSeparationProbe = sign(probesAreas(iProbeArea) %separation, probesAreas(iProbeArea) %xEnd - probesAreas
(iProbeArea) %xStart)
iProbe = iProbe + 1
xyzcap(1,iProbe) = xProbe
xyzcap(2,iProbe) = yProbe
xyzcap(3,iProbe) = 0.00d0
if (isca(1).gt.0.and.nscaus.ge.1) then
ipp = ipprtp(isca (1))
nomvar(ipp) = ’Scalar1’
ichrvr(ipp) = 1
ilisvr(ipp) = 1
ihisvr(ipp,1)= -1
endif
! Other variables
iphas = 1
return
end subroutine
!===============================================================================
subroutine ustbtr &
!================
( ncel , ncelet , nfac , nfabor , nnod , &
longia , longra , &
nideve , nituse , nrdeve , nrtuse )
!===============================================================================
! Purpose:
! -------
! User subroutine to define the sizes of macro-arrays ia and ra,
! of user arrays ituser and rtuser,
! of developper arrays idevel and rdevel.
!-------------------------------------------------------------------------------
! Arguments
!__________________.____._____.________________________________________________.
! name !type!mode ! role !
!__________________!____!_____!________________________________________________!
! ncel ! i ! <-- ! number of cells !
! ncelet ! i ! <-- ! number of extended (real + ghost) cells !
! nfac ! i ! <-- ! number of interior faces !
! nfabor ! i ! <-- ! number of boundary faces !
! nnod ! i ! <-- ! number of vertices !
! longia ! i ! --> ! size of array ia !
! longra ! i ! --> ! size of array ra !
! nideve ! i ! --> ! size of array idevel !
! nituse ! i ! --> ! size of array ituser !
! nrdeve ! i ! --> ! size of array rdevel !
! nrtuse ! i ! --> ! size of array rtuser !
!__________________!____!_____!________________________________________________!
! Type: i (integer), r (real), s (string), a (array), l (logical),
return
end subroutine
F.4.2. usclim.f90
!-------------------------------------------------------------------------------
! Code_Saturne version 2.0.2
! --------------------------
! This file is part of the Code_Saturne Kernel, element of the
! Code_Saturne CFD tool.
! Copyright (C) 1998-2009 EDF S.A., France
! contact: saturne-support@edf.fr
! The Code_Saturne Kernel is free software; you can redistribute it
! and/or modify it under the terms of the GNU General Public License
! as published by the Free Software Foundation; either version 2 of
! the License, or (at your option) any later version.
! The Code_Saturne Kernel is distributed in the hope that it will be
! useful, but WITHOUT ANY WARRANTY; without even the implied warranty
! of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU General Public License for more details.
! You should have received a copy of the GNU General Public License
! along with the Code_Saturne Kernel; if not, write to the
! Free Software Foundation, Inc.,
! 51 Franklin St, Fifth Floor,
! Boston, MA 02110-1301 USA
!-------------------------------------------------------------------------------
subroutine usclim &
!================
( idbia0 , idbra0 , &
ndim , ncelet , ncel , nfac , nfabor , nfml , nprfml , &
nnod , lndfac , lndfbr , ncelbr , &
nvar , nscal , nphas , &
nideve , nrdeve , nituse , nrtuse , &
ifacel , ifabor , ifmfbr , ifmcel , iprfml , maxelt , lstelt , &
ipnfac , nodfac , ipnfbr , nodfbr , &
icodcl , itrifb , itypfb , &
idevel , ituser , ia , &
xyzcen , surfac , surfbo , cdgfac , cdgfbo , xyznod , volume , &
dt , rtp , rtpa , propce , propfa , propfb , &
coefa , coefb , rcodcl , &
w1 , w2 , w3 , w4 , w5 , w6 , coefu , &
rdevel , rtuser , ra )
!===============================================================================
! Purpose:
! -------
! User subroutine.
! Fill boundary conditions arrays (icodcl, rcodcl) for unknown variables.
! Introduction
! ============
! Here one defines boundary conditions on a per-face basis.
! Boundary faces may be identified using the ’getfbr’ subroutine.
! getfbr(string, nelts, eltlst):
! - string is a user-supplied character string containing selection criteria;
! - nelts is set by the subroutine. It is an integer value corresponding to
! the number of boundary faces verifying the selection criteria;
! - lstelt is set by the subroutine. It is an integer array of size nelts
! containing the list of boundary faces verifying the selection criteria.
! Note that the default condition for scalars (other than k and epsilon)
! is homogeneous Neumann.
! Remarks
! =======
! One have the ordering array for boundary faces from the previous time
! step (except for the fist one, where ’itrifb’ has not been set yet).
! The array of boundary face types ’itypfb’ has been reset before
! entering the subroutine.
! * For other values: take as an approximation the value in the adjacent cell
! i.e. as above with iel = ifabor(ifac).
!-------------------------------------------------------------------------------
! Arguments
!__________________.____._____.________________________________________________.
! name !type!mode ! role !
!__________________!____!_____!________________________________________________!
! idbia0 ! i ! <-- ! number of first free position in ia !
! idbra0 ! i ! <-- ! number of first free position in ra !
! ndim ! i ! <-- ! spatial dimension !
! ncelet ! i ! <-- ! number of extended (real + ghost) cells !
! ncel ! i ! <-- ! number of cells !
! nfac ! i ! <-- ! number of interior faces !
! nfabor ! i ! <-- ! number of boundary faces !
! nfml ! i ! <-- ! number of families (group classes) !
! nprfml ! i ! <-- ! number of properties per family (group class) !
! nnod ! i ! <-- ! number of vertices !
! lndfac ! i ! <-- ! size of nodfac indexed array !
! lndfbr ! i ! <-- ! size of nodfbr indexed array !
! ncelbr ! i ! <-- ! number of cells with faces on boundary !
! nvar ! i ! <-- ! total number of variables !
! nscal ! i ! <-- ! total number of scalars !
! nphas ! i ! <-- ! number of phases !
! nideve, nrdeve ! i ! <-- ! sizes of idevel and rdevel arrays !
! nituse, nrtuse ! i ! <-- ! sizes of ituser and rtuser arrays !
! ifacel(2, nfac) ! ia ! <-- ! interior faces -> cells connectivity !
! ifabor(nfabor) ! ia ! <-- ! boundary faces -> cells connectivity !
! ifmfbr(nfabor) ! ia ! <-- ! boundary face family numbers !
! ifmcel(ncelet) ! ia ! <-- ! cell family numbers !
! iprfml ! ia ! <-- ! property numbers per family !
! (nfml, nprfml) ! ! ! !
! maxelt ! i ! <-- ! max number of cells and faces (int/boundary) !
! lstelt(maxelt) ! ia ! --- ! work array !
! ipnfac(nfac+1) ! ia ! <-- ! interior faces -> vertices index (optional) !
! nodfac(lndfac) ! ia ! <-- ! interior faces -> vertices list (optional) !
! ipnfbr(nfabor+1) ! ia ! <-- ! boundary faces -> vertices index (optional) !
! nodfbr(lndfbr) ! ia ! <-- ! boundary faces -> vertices list (optional) !
! icodcl ! ia ! --> ! boundary condition code !
! (nfabor, nvar) ! ! ! = 1 -> Dirichlet !
! ! ! ! = 2 -> flux density !
! ! ! ! = 4 -> sliding wall and u.n=0 (velocity) !
! ! ! ! = 5 -> friction and u.n=0 (velocity) !
! ! ! ! = 6 -> roughness and u.n=0 (velocity) !
! ! ! ! = 9 -> free inlet/outlet (velocity) !
! ! ! ! inflowing possibly blocked !
! itrifb ! ia ! <-- ! indirection for boundary faces ordering !
! (nfabor, nphas) ! ! ! !
! itypfb ! ia ! --> ! boundary face types !
! (nfabor, nphas) ! ! ! !
! idevel(nideve) ! ia ! <-> ! integer work array for temporary development !
! ituser(nituse) ! ia ! <-> ! user-reserved integer work array !
! ia(*) ! ia ! --- ! main integer work array !
! xyzcen ! ra ! <-- ! cell centers !
! (ndim, ncelet) ! ! ! !
! surfac ! ra ! <-- ! interior faces surface vectors !
! (ndim, nfac) ! ! ! !
! surfbo ! ra ! <-- ! boundary faces surface vectors !
! (ndim, nfabor) ! ! ! !
! cdgfac ! ra ! <-- ! interior faces centers of gravity !
! (ndim, nfac) ! ! ! !
! cdgfbo ! ra ! <-- ! boundary faces centers of gravity !
! (ndim, nfabor) ! ! ! !
! xyznod ! ra ! <-- ! vertex coordinates (optional) !
! (ndim, nnod) ! ! ! !
! volume(ncelet) ! ra ! <-- ! cell volumes !
! dt(ncelet) ! ra ! <-- ! time step (per cell) !
! rtp, rtpa ! ra ! <-- ! calculated variables at cell centers !
! (ncelet, *) ! ! ! (at current and previous time steps) !
! propce(ncelet, *)! ra ! <-- ! physical properties at cell centers !
! propfa(nfac, *) ! ra ! <-- ! physical properties at interior face centers !
! propfb(nfabor, *)! ra ! <-- ! physical properties at boundary face centers !
! coefa, coefb ! ra ! <-- ! boundary conditions !
! (nfabor, *) ! ! ! !
implicit none
include "paramx.h"
include "pointe.h"
include "numvar.h"
include "optcal.h"
include "cstphy.h"
include "cstnum.h"
include "entsor.h"
include "parall.h"
include "period.h"
include "ihmpre.h"
!===============================================================================
! Arguments
integer idbia0 , idbra0
integer ndim , ncelet , ncel , nfac , nfabor
integer nfml , nprfml
integer nnod , lndfac , lndfbr , ncelbr
integer nvar , nscal , nphas
integer nideve , nrdeve , nituse , nrtuse
! Local variables
integer idebia, idebra
!===============================================================================
! 1. Initialization
!===============================================================================
if (.not.actuatorValuesInitialized) then
write( sProcessorNumber, ’(i1)’ ) irangp
call system("mkfifo semaphore."//sProcessorNumber)
call system("mkfifo act.upper.csv."//sProcessorNumber)
call system("mkfifo act.lower.csv."//sProcessorNumber)
actuatorValuesInitialized = .true.
endif
idebia = idbia0
idebra = idbra0
d2s3 = 2.d0/3.d0
!===============================================================================
! 2. Assign boundary conditions to boundary faces here
!$PhysicalNames
!1 Layer0
!2 entrada
!3 salida
!4 pared
!5 simetria
!6 interna
!7 actuador
!5 simetria
!$EndPhysicalNames
do iphas = 1, nphas
itypfb(ifac,iphas) = ientre
rcodcl(ifac,iu(iphas),1) = inputVelocity
rcodcl(ifac,iv(iphas),1) = 0.0d0
rcodcl(ifac,iw(iphas),1) = 0.0d0
yCentre = cdgfbo(2,ifac)
do ii = 1, nscal
if(iphsca(ii).eq.iphas) then
if (yCentre.gt.-0.1d0.and.yCentre.lt.0.1d0) then
icodcl(ifac, isca(ii)) = 1
rcodcl(ifac, isca(ii),1) = 1.d0
else
icodcl(ifac, isca(ii)) = 0
rcodcl(ifac, isca(ii),1) = 0.d0
endif
endif
enddo
enddo
enddo
do iphas = 1, nphas
itypfb(ifac,iphas) = iparoi
enddo
enddo
do iphas = 1, nphas
itypfb(ifac,iphas) = isymet
enddo
enddo
if (ntcabs.ge.actuatorStartingStep) then
write(103,*) sStepNumber
read(104,*) upperActuatorValue
read(105,*) lowerActuatorValue
else
upperActuatorValue = 0
lowerActuatorValue = 0
endif
if (ntmabs.eq.ntcabs) then
close(103)
close(104)
close(105)
endif
xCentre = cdgfbo(1,ifac)
yCentre = cdgfbo(2,ifac)
alfa = atan(yCentre / xCentre)
beta = alfa - pi/2.0
do iphas = 1, nphas
itypfb(ifac,iphas) = iparoi
rcodcl(ifac,iu(iphas),1) = upperActuatorValue * cos(beta)
rcodcl(ifac,iv(iphas),1) = upperActuatorValue * sin(beta)
rcodcl(ifac,iw(iphas),1) = 0.0d0
enddo
enddo
call getfbr(’7 and y < 0’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)
xCentre = cdgfbo(1,ifac)
yCentre = cdgfbo(2,ifac)
alfa = atan(yCentre / xCentre)
beta = alfa + pi/2.0
do iphas = 1, nphas
itypfb(ifac,iphas) = iparoi
rcodcl(ifac,iu(iphas),1) = lowerActuatorValue * cos(beta)
rcodcl(ifac,iv(iphas),1) = lowerActuatorValue * sin(beta)
rcodcl(ifac,iw(iphas),1) = 0.0d0
enddo
enddo
return
end subroutine
function [A B] = lfd_arx(y, u, p)
y = y’;
u = u’;
na = p;
nb = na+1;
%Modelo de partida:
% y(k)+a_1*y(k-1)+a_2*y(k-2)+...a_na*y(k-na)=
% =b_1*u(k)+b_2*u(k-1)+...+b_nb*u(k-(nb-1))
%donde
% y(k) es la salida en el tiempo k, vector de mx1
% u(k) es la entrada en el tiempo k, vector de rx1
% a_1,..a_na matrices de mxm
% b_1,...b_nb matrices de mxr
%venimos considerando na=nb-1
%De acuerdo con esta escritura, se considera
% N:cantidad de observaciones
% y: matriz de observaciones de las salidas, de mxN; es decir, en la
%columna j la salida en el tiempo j
% u: matriz de las observaciones de las entradas, de rxN; es decir, en la columna j la entrada en el
tiempo j
[m,N] = size(y);
[r,N] = size(u);
F = [reg’ Y];
R = triu(qr(F));
%d: cantidad de nómeros a determinar para armar las matrices %del modelo
d = na*m*m+nb*r*m;
R0 = R(1:d+1,1:d+1);
R1 = R0(1:d,1:d);
R2 = R0(1:d,end);
a = zeros(m, m, na);
b = zeros(m, r, nb);
for j=1:na
a(:,:,j)=reshape(th(1+(j-1)*m*m:j*m*m),m,m);
end
for j=1:nb
b(:,:,j)=reshape(th(1+na*m*m+(j-1)*m*r:1+na*m*m+(j-1)*m*r+m*r-1),m,r);
end
A = zeros(m, m, na+1);
A(:,:,1) = eye(m);
A(:,:,2:end) = a(:,:,:);
B = b;
y = pvget(data, ’OutputData’);
y = y{1};
ny = size(y , 2);
s = RandStream.create(’mrg32k3a’,’NumStreams’,1);
RandStream.setDefaultStream(s); %to ensure deterministic output
%randseed(45233); %to ensure deterministic output
s = RandStream.create(’mrg32k3a’,’NumStreams’,1);
RandStream.setDefaultStream(s); %to ensure deterministic output
%randseed(45233); %to ensure deterministic output
act(delayBeforeRampSteps+rampUpSteps+1:delayBeforeRampSteps+rampUpSteps+rampDownSteps) =
peakMagnitude*[1-deltaRampDown:-deltaRampDown:0];
act = repmat(act’, 1, 2);
end
/*
In order to compile the code it is possible to run the "mex" command either via Matlab or Linux Shell:
Matlab: mex(’-v’, ’-f’, fullfile(matlabroot,’bin’,’engopts.sh’),’controlador.cpp’, ’Parser.cpp’, ’
MatlabExecutor.cpp’, etc)
Shell: mex -v -f /usr/local/opt/matlab2009/bin/engopts.sh main.cpp Parser.cpp MatlabExecutor.cpp
Controller.cpp SaturneCommunicator.cpp -o controller
Run with:
LD_LIBRARY_PATH=/usr/local/opt/matlab2009/bin/glnxa64:/usr/local/opt/matlab2009/sys/os/glnxa64:
$LD_LIBRARY_PATH
sudo ldconfig /usr/local/opt/matlab2009/bin/glnxa64
./controller
*/
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <limits>
#include <algorithm>
#include "Parser.h"
#include "Logger.h"
#include "MatlabExecutor.h"
#include "Controller.h"
#include "SaturneCommunicator.h"
#include "Constants.h"
std::stringstream prefixConverter;
prefixConverter << "[CPU." << argv[1] << "]";
prefixConverter >> logPrefix;
try {
Controller controller(argv[1], logger, matlabExecutor);
SaturneCommunicator saturneCommunicator;
controller.initialize("configuration.txt");
bool continueControl = true;
while (continueControl) {
int semaphoreStepNumber = saturneCommunicator.waitForStep(semaphore, logger);
if (semaphoreStepNumber >= 0) {
Row values = parser.readValues(probesPressureFilepath , semaphoreStepNumber - 1);
Actuation act = controller.getActuationFor(semaphoreStepNumber, values);
F.6.2. Config.h
#ifndef CONFIG__
#define CONFIG__
#include <map>
#include <string>
#include <fstream>
class Config {
private:
typedef std::map< std::string, std::string > t_keyvalues;
typedef std::pair< std::string, std::string > t_keyvalue;
t_keyvalues keyValues;
public:
Config(const std::string& configurationFilepath){
initialize(configurationFilepath);
}
Config(){
}
if (!line.empty()){
std::string::size_type pos = line.find_first_of("=");
if (pos != std::string::npos) {
std::string key = line.substr(0, pos-1);
std::string value = line.substr(pos+1, line.size());
trim(key);
trim(value);
keyValues.insert(t_keyvalue(key, value));
}
}
}
}
}
private:
void trim(std::string& str, const std::string trimChars = std::string(" \f\n\r\t\v") ) {
std::string::size_type pos;
pos = str.find_last_not_of(trimChars);
str.erase( pos + 1 );
pos = str.find_first_not_of(trimChars);
str.erase( 0, pos );
}
#endif
CONTROL_PARAMETER_P = 90
CONTROL_PARAMETER_Q = [1.4 1.4 1.4 1.4 1.4 1.4 1.4 1.4]
CONTROL_PARAMETER_GAMMA = 4
CONTROL_LIMITS_MAX_VALUE = 5
CONTROL_LIMITS_MIN_VALUE = 0
CONTROL_CALCULATE_ACTUATION_AFTER_STEPS = 1
CONTROL_PREDICTION_MAX_STEPS = 1000
SENSORS_MASK_PROBES_TO_USE = 7,9,11,13,48,50,52,54
SENSORS_NORMALIZE_VARIABLE_Y_SENTENCE = if ~exist(’yNormalizerScalars’),global yNormalizerScalars;range =
1:170; yNormalizerScalars=diag(1./mean(y(range,:)));end;y=y*yNormalizerScalars;
ACTUATOR_UPPERVALUE_ARRAYINDEX = 0
ACTUATOR_LOWERVALUE_ARRAYINDEX = 0
ACTUATOR_NORMALIZE_VARIABLE_U_SENTENCE = u=u(:,1);
SAVE_OUTPUT_FILEPATH = outputs.csv
SAVE_INPUT_FILEPATH = inputs.csv
TRAINING_FROM_STORED_DATA_ENABLED = 1
TRAINING_FROM_STORED_DATA_FILEPATH = ProbesAndActuation_one_pulse_sync_r235_full_line.mat
TRAINING_FROM_STORED_DATA_OUTPUT_VARIABLE = scalar_values
TRAINING_FROM_STORED_DATA_INPUT_VARIABLE = actuation
TRAINING_FROM_STORED_DATA_SAMPLING_RATE = 1
TRAINING_GENERATION_ENABLED = 0
TRAINING_GENERATION_FUNCTION_INVOKE = %lfd_training_actuation_pulse(10, 375, 37, 3750)
COMPUTE_MODEL_STEPS = 1
CONTROL_PARAMETER_P = 35
CONTROL_PARAMETER_Q = [1 1 1 1]
CONTROL_PARAMETER_GAMMA = 0.8
CONTROL_LIMITS_MAX_VALUE = 3
CONTROL_LIMITS_MIN_VALUE = 0
CONTROL_CALCULATE_ACTUATION_AFTER_STEPS = 1
CONTROL_PREDICTION_MAX_STEPS = 1000
SENSORS_MASK_PROBES_TO_USE = 4,6,13,15
SENSORS_NORMALIZE_VARIABLE_Y_SENTENCE = if ~exist(’yNormalizerScalars’),global yNormalizerScalars;
yNormalizerScalars=diag(1./mean(y));end;y=y*yNormalizerScalars;
ACTUATOR_UPPERVALUE_ARRAYINDEX = 0
ACTUATOR_LOWERVALUE_ARRAYINDEX = 0
ACTUATOR_NORMALIZE_VARIABLE_U_SENTENCE = u=u(:,1);
SAVE_OUTPUT_FILEPATH = outputs.csv
SAVE_INPUT_FILEPATH = inputs.csv
TRAINING_FROM_STORED_DATA_ENABLED = 0
TRAINING_FROM_STORED_DATA_FILEPATH = %ProbesAndActuation_mixed_sync.mat
TRAINING_FROM_STORED_DATA_OUTPUT_VARIABLE = %scalar_values
TRAINING_FROM_STORED_DATA_INPUT_VARIABLE = %actuation
TRAINING_FROM_STORED_DATA_SAMPLING_RATE = %10
TRAINING_GENERATION_ENABLED = 1
TRAINING_GENERATION_FUNCTION_INVOKE = lfd_training_actuation_pulse(10, 180, 10, 900)
COMPUTE_MODEL_STEPS = 10
F.6.5. Constants.h
#ifndef CONSTANTS__
#define CONSTANTS__
#define Y_STEP (6.0+6.0)/SAMPLES_PER_LINE //based on the amount of samples per line. Having 12.5 diametres
to the upper and bottom limits of the tunnel.
#include <vector>
#include "Matrix.h"
struct Actuation {
Cell upper;
Cell lower;
};
#endif
F.6.6. Controller.h
#ifndef CONTROLLER__
#define CONTROLLER__
#include <vector>
#include <set>
#include "Logger.h"
#include "MatlabExecutor.h"
#include "Constants.h"
#include "Config.h"
class Controller {
private:
Matrix cummulativeOutputsForModel, cummulativeOutputs;
Matrix cummulativeActuationForModel, cummulativeActuation;
std::vector < Actuation > trainingActuations;
std::vector < Actuation >::const_iterator itTrainingActuation;
Actuation previousActuation;
bool initialized;
bool modelAlreadyComputed;
size_t invocationsCount;
char* processorNumber;
std::set< size_t > probesToUse;
Logger& logger;
MatlabExecutor& matlabExecutor;
std::ofstream inputsLogFile;
std::ofstream outputsLogFile;
Config config;
public:
Controller(char* processorNumber, Logger& logger, MatlabExecutor& matlabExecutor);
void initialize(const std::string& configurationFilepath);
Actuation getActuationFor(int currentStep, const Row& lastStepOutputs);
private:
void addOutputsForModelComputation(const Row& lastStepOutputs, const Row& actuation);
std::vector < Actuation > getTrainingActuation();
Actuation getActuationFromRow(const Row& row);
void computeModel();
Actuation computeActuation();
Actuation getActuationForNewStep();
#endif
F.6.7. Controller.cpp
#include <sstream>
#include <set>
#include "Controller.h"
inputsLogFile.open(config.get("SAVE_INPUT_FILEPATH").c_str(), std::ofstream::out);
outputsLogFile.open(config.get("SAVE_OUTPUT_FILEPATH").c_str(), std::ofstream::out);
if (! inputsLogFile.good())
throw "There was an error trying to open the input file";
if (! outputsLogFile.good())
throw "There was an error trying to open the output file";
std::istringstream maskProbesToUseStr(config.get("SENSORS_MASK_PROBES_TO_USE"));
logger << "Defining Mask Probes to use: ";
std::string probeToUse;
while ( getline(maskProbesToUseStr, probeToUse, ’,’) )
{
this->probesToUse.insert(atoi(probeToUse.c_str()));
logger << " " << probeToUse;
}
logger << std::endl;
void Controller::restoreTrainingData() {
std::ostringstream loadExpression;
loadExpression << "load(’"<< config.get("TRAINING_FROM_STORED_DATA_FILEPATH") << "’);";
loadExpression << "y = " << config.get("TRAINING_FROM_STORED_DATA_OUTPUT_VARIABLE") << ";";
loadExpression << "u = " << config.get("TRAINING_FROM_STORED_DATA_INPUT_VARIABLE") << ";";
loadExpression << "y = y(1:" << config.getInt("TRAINING_FROM_STORED_DATA_SAMPLING_RATE") << ":end,:);";
loadExpression << "u = u(1:" << config.getInt("TRAINING_FROM_STORED_DATA_SAMPLING_RATE") << ":end,:);";
matlabExecutor.evaluate(loadExpression.str());
logger << "Received y data values. Rows: " << yMatrix.getRows() << ". Cols: " << yMatrix.getColumns() <<
std::endl;
cummulativeOutputs = yMatrix;
cummulativeOutputsForModel = yMatrix;
if (uMatrix.getRows() != yMatrix.getRows()) {
logger << "Error computing restarting values. ’u’ amount of samples should match ’y’ amount of samples.
ySamples:" << yMatrix.getRows() << " uySamples:" << uMatrix.getRows() << std::endl;
throw "Error computing training actuation values.";
}
else {
cummulativeActuation = uMatrix;
cummulativeActuationForModel = uMatrix;
}
matlabExecutor.evaluate("clear y u;");
cummulativeOutputs = this->removeUselessProbeValues(cummulativeOutputs);
cummulativeOutputsForModel = this->removeUselessProbeValues(cummulativeOutputsForModel);
}
void Controller::checkInitialized() {
if (! this->initialized)
throw "The controller was not initialized yet.";
}
Actuation Controller::getActuationForNewStep() {
this->checkInitialized();
if (itTrainingActuation != trainingActuations.end()) {
Actuation act = *itTrainingActuation;
++itTrainingActuation;
logger << "Taking training actuation: [" << act.lower << ", " << act.upper << "]" << std::endl;
return act;
}
else {
logger << "Computing actuation from sensor values ..." << std::endl;
return this->computeActuation();
}
}
void Controller::computeModel() {
std::ostringstream expression;
expression << "p = " << config.getInt("CONTROL_PARAMETER_P") << "; gamma= " << config.getFloat("
CONTROL_PARAMETER_GAMMA") << ";";
expression << "q = " << config.get("CONTROL_PARAMETER_Q") << ";";
matlabExecutor.evaluate(expression.str());
expression.str(" ");
expression << "limits.max_value = " << config.getInt("CONTROL_LIMITS_MAX_VALUE") << "; limits.min_value =
" << config.getInt("CONTROL_LIMITS_MIN_VALUE") << ";";
matlabExecutor.evaluate(expression.str());
matlabExecutor.putMatrix("y", cummulativeOutputsForModel);
matlabExecutor.putMatrix("u", cummulativeActuationForModel);
std::ostringstream saveExpression;
saveExpression << "save model_data."<< processorNumber <<".dat y u;";
matlabExecutor.evaluate(saveExpression.str());
matlabExecutor.evaluate(config.get("SENSORS_NORMALIZE_VARIABLE_Y_SENTENCE"));
matlabExecutor.evaluate(config.get("ACTUATOR_NORMALIZE_VARIABLE_U_SENTENCE"));
matlabExecutor.evaluate("data = iddata(y, u);");
matlabExecutor.evaluate("[A B] = lfd_arx(data.OutputData, data.InputData, p);");
matlabExecutor.evaluate("control_state = lfd_control_lagrange_init(y, u, p, gamma, A, B, limits, q);");
matlabExecutor.evaluate("clear data y u A B limits;");
}
Actuation Controller::computeActuation() {
matlabExecutor.putMatrix("y", cummulativeOutputs);
matlabExecutor.putMatrix("u", cummulativeActuation);
matlabExecutor.evaluate(config.get("SENSORS_NORMALIZE_VARIABLE_Y_SENTENCE"));
matlabExecutor.evaluate(config.get("ACTUATOR_NORMALIZE_VARIABLE_U_SENTENCE"));
matlabExecutor.evaluate("control_state = lfd_control_lagrange(control_state, y, u);");
matlabExecutor.evaluate("next_step_act = control_state.u_k;");
matlabExecutor.evaluate("clear y u;");
Actuation act;
if ((invocationsCount % config.getInt("CONTROL_CALCULATE_ACTUATION_AFTER_STEPS")) != 0) {
act = this->previousActuation;
}
else {
logger << "Calculating actuation for step: " << currentStep << std::endl;
act = this->getActuationForNewStep();
Row actRow(2);
actRow[0] = act.upper;
actRow[1] = act.lower;
cummulativeActuation.pushRow(actRow);
cummulativeOutputs.pushRow(lastStepOutputsNormalized);
this->addOutputsForModelComputation(lastStepOutputsNormalized, actRow);
F.6.8. Logger.h
#ifndef LOGGER__
#define LOGGER__
#include <iostream>
#include <fstream>
class Logger {
private:
bool includePrefix;
std::string prefix;
std::ofstream file;
public:
typedef std::ostream& (*ostream_manipulator)(std::ostream&);
Logger(const std::string& prefix, const std::string& filepath) : includePrefix(true), prefix(prefix),
file(filepath.c_str()) {
if (!file)
std::cerr << "Error al inicializar el log en ’" << filepath << "’." << std::endl;
}
};
#endif
%In order to get a proper control algorithm, the functional was defined as
% min(y_s^tQy_s+gamma u_s^u_s)
%Where y_s=(y_k y_k+1 ...y_k+s-1)’
% u_s=(u_k u_k+1 ...u_k+s-1)’
%Then, it can be applied as:
% u_s = K * v_p
%Where v_p = (y_k-1..y_k-p u_k-1...u_k-p)’
% y_s = T*u_s + phi*v_p ,
%Then, the K matrix can be computed as
% K = -inv(T’Q*T+gamma*I)*T’*Q*phi
y = y’;
u = u’;
if size(y,2) ~= size(u,2)
error(’lfd_control:input’,’Unable to determine current time step number: k. Samples in y(count: %d) and
u(count: %d) do not match’, size(y,2), size(u,2));
end
for kk=2:s-1
if kk<=p
aux=zeros(size(beta00));
for l=1:kk-1;
aux=aux+a(:,:,l)*beta0(:,:,kk-l);
end
aux=aux+a(:,:,kk)*beta00;
beta0(:,:,kk) = b(:,:,kk+1)+aux;
else
aux=zeros(size(beta00));
for l=1:p;
aux=aux+a(:,:,l)*beta0(:,:,kk-l);
end
beta0(:,:,kk)=aux;
end
end
clear aux
% T: [beta_0^0 0 0 ... 0;
% beta_0^1 beta_0^0 0 ... 0;
% beta_0^2 beta_0^1 beta_0^0 0 ... 0;
% ...
% beta_0^s-1 ... beta_0^1 beta_0^0]
T_column(1:m,:)=beta00;
for j=2:s;
T_column((j-1)*m+1:j*m,:)=beta0(:,:,j-1);
end;
for j=2:s-1;
for kk=1:p-1;
alpha(:,:,j,kk)=alpha(:,:,j-1,1)*a(:,:,kk)+alpha(:,:,j-1,kk+1);
end;
alpha(:,:,j,p)=alpha(:,:,j-1,1)*a(:,:,p);
end
for kk=1:p-1;
beta(:,:,1,kk)=a(:,:,1)*b(:,:,kk+1)+b(:,:,kk+2);
end
beta(:,:,1,p)=a(:,:,1)*b(:,:,p+1);
for j=2:s-1;
for kk=1:p-1;
beta(:,:,j,kk)=alpha(:,:,j-1,1)*b(:,:,kk+1)+beta(:,:,j-1,kk+1);
end;
beta(:,:,j,p)=alpha(:,:,j-1,1)*b(:,:,p+1);
end
% size(T’*Q*T) = r*s;
gammaIdentitySize = r*s;
% Since: u_s = K*vp and only ’r’ rows are necessary from u_s, it is possible to reduce the computation
taking ’r’ rows from K
% Let K=-inv(gamma*eye(n)+T’*Q*T)*T’*Q*F, so ’r’ rows are necessary
% from -inv(gamma*eye(n)+T’*Q*T) to compute the first ’r’ u_s components.
Q=kron(eye(s), diag(q));
invGammaTTQT = -pinv(gamma*eye(gammaIdentitySize) + T’*Q*T);
control_state.K_r = invGammaTTQT(1:r, :) * T’ * Q * phi;
control_state.p = p;
control_state.limits = limits;
control_state.s = s;
control_state.m = m;
control_state.r = r;
control_state.gamma = gamma;
control_state.u_k = zeros(r, 1);
end
y = y’;
u = u’;
limits = control_state.limits;
p = control_state.p;
m = control_state.m;
r = control_state.r;
K_r = control_state.K_r;
k = size(y, 2) + 1;
vp = zeros(p*m+p*r, 1);
for i=1:p
vp((i-1)*m+1:i*m) = y(:,k-i);
end
offset = m*p;
for i=1:p
vp((i-1)*r+1+offset:i*r+offset) = u(:,k-i);
end;
control_state.u_k = u_k;
end
F.6.11. MatlabExecutor.h
#ifndef MATLABEXECUTOR__
#define MATLABEXECUTOR__
#include <vector>
#include "engine.h"
#include "Logger.h"
#include "Matrix.h"
class MatlabExecutor {
private:
Engine *ep;
Logger& logger;
public:
MatlabExecutor(Logger& logger);
~MatlabExecutor();
void putMatrix(const std::string& matrixVariableName, Matrix& values);
Matrix getMatrix(const std::string& matrixVariableName);
void evaluate(const std::string& expression);
double evaluateScalar(const std::string& expression);
};
#endif
F.6.12. MatlabExecutor.cpp
#include <string.h>
#include "engine.h"
#include "MatlabExecutor.h"
MatlabExecutor::~MatlabExecutor() {
if (!(ep = engOpen("\0"))) {
logger << "Closing engine..." << std::endl;
engClose(ep);
}
}
logger << "Putting matrix. Variable: " << matrixVariableName << std::endl;
engPutVariable(ep, matrixVariableName.c_str(), matrix);
mxDestroyArray(matrix);
F.6.13. Matrix.h
#ifndef MATRIX__
#define MATRIX__
class Row {
private:
std::vector< Cell > data;
public:
Row(size_t columns) {
this->data.resize(columns);
}
class Matrix {
private:
std::vector< Row > data;
public:
Matrix(size_t rows, size_t columns): data(rows, Row(columns)) {
}
const Cell& get(size_t row, size_t col) const {
return data[row][col];
}
void set(size_t row, size_t col, Cell& value) {
data[row][col] = value;
}
const Row& getRow(size_t row) const {
return this->data[row];
}
void pushRow(const Row& row) {
data.push_back(row);
}
size_t getRows() const {
return this->data.size();
}
size_t getColumns() const {
if (this->getRows() == 0)
return 0;
else
return this->data[0].getColumns();
}
std::vector< Row > toRowsVector() {
return this->data;
}
return data[row];
}
Matrix submatrixByRows(size_t rowIndexFrom, size_t rowIndexTo) {
Matrix result(rowIndexTo - rowIndexFrom + 1, this->getColumns());
size_t j = 0;
for(size_t i = rowIndexFrom; i <= rowIndexTo; ++i) {
result[j++] = this->data[i];
}
return result;
}
};
#endif
F.6.14. Parser.h
#ifndef PARSER__
#define PARSER__
#include <string>
#include <vector>
#include "Logger.h"
#include "Matrix.h"
class Parser {
private:
Logger& logger;
unsigned int probesCount;
void processLine(const std::string& line, unsigned int& currentStep, Row& probeValues);
Row readValuesForStep(const std::string& probesFilepath, unsigned int stepNumber);
Row readValuesWithRetry(const std::string& probesFilepath, unsigned int stepNumber, unsigned int retries)
;
public:
Parser(Logger& logger, unsigned int probesCount);
Row readValues(const std::string& probesFilepath, unsigned int stepNumber);
};
#endif
F.6.15. Parser.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <algorithm>
#include "Constants.h"
#include "Parser.h"
if (! converter.fail()) {
float auxTime;
converter >> auxTime;
currentStep = aux;
logger << "Parse successful. Step read: " << currentStep << std::endl;
for(int i = 0; i < this->probesCount; ++i) {
Cell value;
converter >> value;
probeValues[i] = value;
}
}
}
probes.seekg(0, std::ios::beg);
std::ifstream::pos_type posBegin = probes.tellg();
probes.seekg(-1, std::ios::end);
probes.seekg(-1, std::ios::cur);
} while (probes.tellg() != posBegin && probes.good() && currentStep > stepNumber);
if (currentStep == stepNumber)
return probeValues;
else
throw "El archivo de muestras no posee el paso indicado. Posiblemente aón no fue escrito y se deba
reintentar.";
}
try {
return readValuesForStep(probesFilepath, stepNumber);
}
catch(const char* msg) {
if (retries < MAX_RETRIES) {
sleep(SECS_BETWEEN_RETRIES);
logger << std::endl << "Step:" << stepNumber << " not found. Retrying parse: " << retries + 1 << std
::endl;
return readValuesWithRetry(probesFilepath, stepNumber, retries + 1);
}
else
throw;
}
}
F.6.16. SaturneCommunicator.h
#ifndef SATURNE_COMMUNICATOR__
#define SATURNE_COMMUNICATOR__
#include <iostream>
#include "Logger.h"
class SaturneCommunicator {
public:
int waitForStep(std::istream& semaphore, Logger& logger);
void send(std::ofstream& actuatorFile, Logger& logger, double value);
};
#endif
F.6.17. SaturneCommunicator.cpp
#include <sstream>
#include "SaturneCommunicator.h"
std::string strValue;
converter >> strValue;
logger << "Sending ’" << strValue << "’." << std::endl;
actuatorFile << strValue <<std::endl;
}
#define GAIN 1
#define DELAY 0 //ms
#define EXPOSURE_TIME 5 //ms
#define ROIX 2 //from 1 to 20
#define ROIY 2 //from 1 to 20
int camId;
CAMINFO camData[8];
int boardNumber = 0;
int error;
if (error = SELECT_CAMERA("pixelfly", boardNumber, &camId, camData))
showErrorAndClose(error);
else {
if (error = SETUP_CAMERA(camId, camData, 0, 0, 0, 1, ROIX, 1, ROIY, 1, 1, GAIN, DELAY,
EXPOSURE_TIME))
showErrorAndClose(error);
else {
time_t beginTime, endTime;
time(&beginTime);
int snapshotNumber = 0;
while (! error && snapshotNumber < totalSnapshots) {
if (error = SNAP(camId, camData, 0))
showErrorAndClose(error);
else {
if (error = GETIMAGE(camId, camData, 2000))
showErrorAndClose(error);
else
// image in memory at this point
}
snapshotNumber++;
}
time(&endTime);
std::cout << std::endl << "Tiempo Promedio por imagen: " << 1000.0 * (double)difftime(endTime,
beginTime) / (float)totalSnapshots << "ms." << std::endl;
}
CLOSE_CAMERA(camId, camData);
}
return 0;
}
212
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
G.1.2. Pulnix
#include <cstdio>
#include <iostream>
#include "pxd.h"
#include "iframe.h"
#define IMAGEWIDTH 738
#define IMAGEHEIGHT 484
CAMERA_TYPE *configInMem;
pxd.FreeFG (hFG);
return 0;
}
import com.artho.visart.plugins.minivis.internal.jni.MinivisFactory;
import com.artho.visart.util.TypedNetAddress;
import com.artho.visart.plugins.minivis.Proxy;
import com.artho.visart.plugins.minivis.internal.jni.CallbackConsumer;
import com.artho.visart.plugins.minivis.internal.jni.MDriverException;
import com.artho.visart.plugins.minivis.internal.jni.MFrameInfo;
System.out.println("Connecting camera...");
camera.connect();
System.out.println("Triggering camera...");
camera.trigger();
System.out.println("Getting image...");
MFrameInfo frameInfo = new MFrameInfo();
byte[] frameBytes = camera.getFrame(-1, -1, frameInfo);
System.out.println("Get Frame result: " + frameInfo.width + "x" + frameInfo.height + " - " +
frameBytes.length + " bytes.");
}
catch(MDriverException e) {
e.printStackTrace();
}
}
}
G.2.1. main.cpp
#include <iostream>
#include <sstream>
#include <fstream>
#include "common/CULAContext.h"
#include "common/Exception.h"
#include "common/Matrix.h"
#include "arxEngine/ArxSystemIdentification.h"
{
std::ifstream file(filepath.c_str());
if (file)
file >> target;
else
throw Exception("The file could not be opened for reading");
}
if (argc != 8)
{
std::cout << "ArxGSL usage:" << std::endl;
std::cout << "ArxGSL.exe <arx-order> <samples-qty> <input samples-filepath> <input-components-dimension
> <output samples-filepath> <output-components-dimension> <output-folder>" << std::endl;
std::cout << "Output: A0.txt A1.txt B0.txt B1.txt will be written into the <output-folder>" << std::
endl;
return -1;
}
else
{
CULAContext context;
int order = atoi(argv[1]);
int samples = atoi(argv[2]);
char* uFilepath = argv[3];
int inputDim = atoi(argv[4]);
char* yFilepath = argv[5];
int outputDim = atoi(argv[6]);
char* outputFolder = argv[7];
try
{
context.init();
Matrix<t_sample> input(samples, inputDim);
Matrix<t_sample> output(samples, outputDim);
readFromFile(uFilepath, input);
readFromFile(yFilepath, output);
calculate(order, input, output, outputFolder);
return 0;
}
catch(const std::exception& ex)
{
std::cerr << "There was an unexpected error:" << ex.what() << std::endl;
return -1;
}
}
}
G.2.2. arxEngine/ArxSystemIdentification.h
#ifndef ARXSYSTEMIDENTIFICATION__H
#define ARXSYSTEMIDENTIFICATION__H
#include "../common/Matrix.h"
#include <vector>
typedef float t_sample;
class ArxSystemIdentification
{
private:
size_t order;
size_t m;
size_t r;
size_t samples;
const Matrix<t_sample>& input;
const Matrix<t_sample>& output;
std::vector< Matrix<t_sample> > estimatedA;
std::vector< Matrix<t_sample> > estimatedB;
public:
ArxSystemIdentification(int order, const Matrix<t_sample>& input, const Matrix<t_sample>& output);
void estimateModel();
const Matrix<t_sample>& getAModel(int index) const;
const Matrix<t_sample>& getBModel(int index) const;
};
#endif
G.2.3. arxEngine/ArxSystemIdentification.cpp
#include "ArxSystemIdentification.h"
#include "../common/Exception.h"
if (output.getRows() != input.getRows())
throw Exception("Invalid dimensions. The input and output samples quantity should match");
else if (output.getRows() <= this->order + 1)
throw Exception("Not enough samples to compute the given order. The samples quantity should be higher
than the order plus 1.");
else
this->samples = output.getRows();
}
void ArxSystemIdentification::estimateModel()
{
/* Model definition:
y(k)+a_1*y(k-1)+a_2*y(k-2)+...a_na*y(k-na) = b_1*u(k)+b_2*u(k-1)+...+b_nb*u(k-(nb-1))
where
size_t na = this->order;
size_t nb = na + 1;
size_t N = this->samples;
/*
Let y : mxN / j-th column has the j-th time sample.
Let u : rxN / j-th column has the j-th time sample.
*/
Matrix<t_sample> y = this->output.transpose();
Matrix<t_sample> u =this->input.transpose();
/*
Let fi : na*m+nb*r x N -> Regresion vector for k time step being:
/ fi(k column) = [-y(k-1 to k-na time samples); u(k to k-(nb-1) time samples)]
= [-y(:,k-1); ...;-y(:,k-na);u(:,k);u(:,k-1);...;u(:,k-(nb-1))]
when k in [na+1,N] = [nb,N]
/ fi(k colum = [0; ... ; 0] when k in [1,na] = [1,nb-1]
*/
//iterates columns nb-1 to 0 for fiColumn=na and N-1 to N-na-1=N-nb for fiColumn=N-1
for(int uColumn = nb - 1 + columnOffset; uColumn >= 0 + columnOffset; --uColumn) {
for(size_t uRow = 0; uRow < r; ++uRow) {
fi.set(fiRow, fiColumn, u.get(uRow, uColumn));
++fiRow;
}
}
}
/*
Let reg: m*(na*m+nb+r) x m*(N-na) -> Regresion matrix
reg(k to column block) = [fi(1,na+1 + (k-1))*eye(m); fi(2,na+1 + (k-1))*eye(m);...; fi(na*m+nb*r, na
+1 + (k-1))*eye(m)] when k in [1,N-na]
and
}
}
Matrix<t_sample> Y(m*(N-na),1);
for(size_t yColumn = na; yColumn < N; ++yColumn) {
for(size_t yRow = 0; yRow < m; ++yRow) {
Y.set((yColumn-na)*m + yRow, 0, y.get(yRow, yColumn));
}
}
/*
Let F: m*(N-na) x m*(na*m+nb*r)+1)
F = [reg’ Y]
*/
Matrix<t_sample> F(m*(N-na), m*(na*m+nb*r)+1);
for(size_t regRow = 0; regRow < m*(na*m+nb*r); ++regRow) {
for(size_t regCol = 0; regCol < m*(N-na); ++regCol) {
F.set(regCol, regRow, reg.get(regRow, regCol));
}
}
for(size_t yRow = 0; yRow < m*(N-na); ++yRow) {
F.set(yRow, m*(na*m+nb*r), Y.get(yRow, 0));
}
/*
Compute the QR decomposition of F and keep the R part.
Then, collect R1 and R2 according to:
R1 = R(1:d, 1:d);
R2 = R(1:d, 1:d+1);
being d = na*m*m+nb*r*m
*/
int d = na*m*m+nb*r*m;
Matrix<t_sample> qr = F.decomposeQRGsl();
Matrix<t_sample> rDecomp = qr.getTriu();
Matrix<t_sample> r1 = rDecomp.getSubmatrix(0, 0, d-1, d-1);
Matrix<t_sample> r2 = rDecomp.getSubmatrix(0, d, d-1, d);
/*
Then, we disregard Q part and unnecesary R values to estimate the A and B coefficients:
th = pinv(R1) * R2;
*/
Matrix<t_sample> th = r1.invert().multiply(r2);
/*
Collect the A and B parameters from within th
*/
Matrix<t_sample> A0(m, m, true);
for(size_t i = 0; i < m; ++i)
{
A0.set(i,i,1);
}
this->estimatedA.push_back(A0);
for(size_t k = 0; k < na; ++k)
{
//Take the submatrix as per: a(:,:,j)=reshape(th(1+(j-1)*m*m:j*m*m),m,m);
Matrix<t_sample> Ak = th.getRow(k*m*m, (k+1)*m*m-1);
this->estimatedA.push_back(Ak.reshape(m,m));
}
return this->estimatedA.at(index);
}
/*
Source code in Matlab:
y = y’;
u = u’;
na = p;
nb = na+1;
%Modelo de partida:
% y(k)+a_1*y(k-1)+a_2*y(k-2)+...a_na*y(k-na)=
% =b_1*u(k)+b_2*u(k-1)+...+b_nb*u(k-(nb-1))
%donde
% y(k) es la salida en el tiempo k, vector de mx1
% u(k) es la entrada en el tiempo k, vector de rx1
% a_1,..a_na matrices de mxm
% b_1,...b_nb matrices de mxr
%venimos considerando na=nb-1
%De acuerdo con esta escritura, se considera
% N:cantidad de observaciones
% y: matriz de observaciones de las salidas, de mxN; es decir, en la
%columna j la salida en el tiempo j
% u: matriz de las observaciones de las entradas, de rxN; es decir, en la columna j la entrada en el
tiempo j
[m,N] = size(y);
[r,N] = size(u);
F = [reg’ Y];
R = triu(qr(F));
%d: cantidad de nómeros a determinar para armar las matrices %del modelo
d = na*m*m+nb*r*m;
R0 = R(1:d+1,1:d+1);
R1 = R0(1:d,1:d);
R2 = R0(1:d,end);
a = zeros(m, m, na);
b = zeros(m, r, nb);
for j=1:na
a(:,:,j)=reshape(th(1+(j-1)*m*m:j*m*m),m,m);
end
for j=1:nb
b(:,:,j)=reshape(th(1+na*m*m+(j-1)*m*r:1+na*m*m+(j-1)*m*r+m*r-1),m,r);
end
A = zeros(m, m, na+1);
A(:,:,1) = eye(m);
A(:,:,2:end) = a(:,:,:);
B = b;
*/
G.2.4. common/Matrix.h
#ifndef MATRIX__H
#define MATRIX__H
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <exception>
#include <cstring>
#include "../common/Exception.h"
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_permutation.h>
#include <gsl/gsl_blas_types.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_blas.h>
#include <cula_lapack.h>
#include <cula_blas.h>
#define GSL_DLL
#define PRINT_MATRIX_CELL_VALUE_PRECISION 10
#define MINIMUN_ACCEPTED_EIGENVALUE_ON_SVD 0.000001
}
}
return newShape;
}
free(aCula);
free(tauCula);
return resultTransposed.transpose();
}
//char jobu, char jobvt, int m, int n, culaFloat* a, int lda, culaFloat* s, culaFloat* u, int ldu,
culaFloat* vt, int ldvt);
//culaStatus status = culaSgesvd(’A’, ’A’, this->rows, this->columns, aCula, lda, sCula, uCula, ldu,
vtCula, ldvt);
culaStatus status = culaSgesvd(’A’, ’A’, this->rows, this->columns, aCula, lda, sCula, uCula, ldu,
vtCula, ldvt);
checkStatus(status);
//Inverting S//
//----------------------------------------------------------
// Matrix ’S’ is diagonal, so it is contained in a vector. We operate to convert the vector ’S’
//----------------------------------------------------------
//sInv should be columns x rows -> use transposed order for cula having ’columns’ qty of elements per
memory row
T* sInvCula = (T*)calloc(this->rows*this->columns*sizeof(T), true);
//THE PSEUDOINVERSE//
//----------------------------------------------------------
//Computation of the pseudoinverse of A as pinv(A) = V.pinv(S).trans(U)[nxn.nxm.mxm=nxm]
//----------------------------------------------------------
Matrix<T> pInvT(this->rows, this->columns);
T* sInvUtCula = multiplyCULANoneTransposed(sInvCula, uCula, this->columns, this->rows, this->rows, this
->rows);
T* pInvCula = multiplyCULATransposedNone(vtCula, sInvUtCula, this->columns, this->columns, this->
columns, this->rows);
free(aCula);
free(sCula);
free(uCula);
free(vtCula);
free(sInvUtCula);
pInvT.fromArrayRowMajor(pInvCula);
free(pInvCula);
return pInvT.transpose();
}
Matrix<T> pseudoInvertGsl()
{
//A = U S V^T where U:mxn, S:nxn, V:nxn
gsl_matrix * U = gsl_matrix_alloc (this->rows, this->columns); //[u] = mxn
gsl_matrix * V = gsl_matrix_alloc (this->columns, this->columns); //[v] = nxn
gsl_vector * S = gsl_vector_alloc (this->columns); //[s] = n
//Inverting S//
// Matrix ’S’ is diagonal, so it is contained in a vector.
// We operate to convert the vector ’S’ into the matrix ’SI’.
gsl_matrix * SI = gsl_matrix_calloc (this->columns, this->columns);
//THE PSEUDOINVERSE//
//----------------------------------------------------------
//Computation of the pseudoinverse of A as pinv(A) = V.pinv(S).trans(U)[nxn.nxn.nxm=nxm]
//----------------------------------------------------------
gsl_matrix * SIpUT = multiplyGslNoneTransponsed(SI, U); //[SIpUT] = nxm
gsl_matrix * pinv = multiplyGslNoneNone(V, SIpUT); //[pinv] = nxm
gsl_matrix_free(SI);
gsl_matrix_free(SIpUT);
gsl_matrix_free(V);
gsl_vector_free(S);
return Matrix<T>(pinv, true);
}
Matrix<T> invert()
{
if (this->rows != this->columns)
throw Exception("It is not possible to invert a non square matrix.");
gsl_matrix_free(matrixCopy);
gsl_permutation_free(p);
throw Exception(message.str().c_str());
}
T* atCula = this->toArrayRowMajor();
T* btCula = toMultiply.toArrayRowMajor();
T* resultTCula = multiplyCULATransposedTransposed(atCula, btCula, this->columns, this->rows, toMultiply
.columns, toMultiply.rows);
Matrix<T> resultT(toMultiply.columns, this->rows);
resultT.fromArrayRowMajor(resultTCula);
return resultT.transpose();
}
Matrix<T> getSubmatrix(size_t rowFrom, size_t columnFrom, size_t rowTo, size_t columnTo) const
{
this->validateRow(rowFrom);
this->validateColumn(columnFrom);
this->validateRow(rowTo);
this->validateColumn(columnTo);
if (rowFrom > rowTo || columnFrom > columnTo) {
std::stringstream message;
message << "Invalid column range. Row/Column From should be less than row/column to. RowFrom: " <<
rowFrom << ". ColumnFrom: " << columnFrom << ". RowTo: " << rowTo << ". ColumnTo: " << columnTo;
throw Exception(message.str().c_str());
}
~Matrix()
{
gsl_matrix_free(inner);
}
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
T get(size_t row, size_t column) const
{
validateCell(row, column);
return gsl_matrix_get(inner, row, column);
}
void set(size_t row, size_t column, T value)
{
validateCell(row, column);
return gsl_matrix_set(inner, row, column, value);
}
T* toArrayRowMajor() const
{
T* array = (T*)malloc(this->rows*this->columns*sizeof(T));
for(size_t i = 0; i < this->rows; ++i){
//memcpy(array + i*this->columns, inner->data + i * inner->tda, this->columns*sizeof(T));
for(size_t j = 0; j < this->columns; ++j){
*(array + i*this->columns + j) = (T)(*(inner->data + i * inner->tda + j));
}
}
return array;
}
}
}
return blasMultiplyCULA(aCula, ’T’, bCula, ’N’, nA, nB, mA, mA, mA);
}
T* multiplyCULANoneTransposed(T* aCula, T* bCula, int mA, int nA, int mB, int nB) const
{
if (nA != nB) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << nA << ". right matrix
rows: " << nB;
throw Exception(message.str().c_str());
}
return blasMultiplyCULA(aCula, ’N’, bCula, ’T’, mA, mB, nA, mA, mB);
}
T* multiplyCULATransposedTransposed(T* aCula, T* bCula, int mA, int nA, int mB, int nB) const
{
if (mA != nB) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << mA << ". right matrix
rows: " << nB;
throw Exception(message.str().c_str());
}
return blasMultiplyCULA(aCula, ’T’, bCula, ’T’, nA, mB, mA, mA, mB);
}
T* multiplyCULANoneNone(T* aCula, T* bCula, int mA, int nA, int mB, int nB) const
{
if (nA != mB) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << nA << ". right matrix
rows: " << mB;
throw Exception(message.str().c_str());
}
return blasMultiplyCULA(aCula, ’N’, bCula, ’N’, mA, nB, nA, mA, nA);
}
gsl_matrix* multiplyGslTransposedNone(gsl_matrix* a, gsl_matrix* b) const
{
if (a->size1 != b->size1) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << a->size1 << ". right
matrix rows: " << b->size1;
throw Exception(message.str().c_str());
}
return blasMultiplyGsl(a, b, CblasTrans, CblasNoTrans, a->size2, b->size1);
}
gsl_matrix* multiplyGslNoneTransponsed(gsl_matrix* a, gsl_matrix* b) const
{
if (a->size2 != b->size2) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << a->size2 << ". right
matrix rows: " << b->size2;
throw Exception(message.str().c_str());
}
return blasMultiplyGsl(a, b, CblasNoTrans, CblasTrans, a->size1, b->size1);
}
gsl_matrix* multiplyGslNoneNone(gsl_matrix* a, gsl_matrix* b) const
{
if (a->size2 != b->size1) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << a->size2 << ". right
matrix rows: " << b->size1;
throw Exception(message.str().c_str());
}
return blasMultiplyGsl(a, b, CblasNoTrans, CblasNoTrans, a->size1, b->size2);
}
/**
* T* blasMultiplyCULA(T* aCula, char opA, T* bCula, char opB, int m, int n, int k, int lda, int ldb)
* */
T* blasMultiplyCULA(T* aCula, char opA, T* bCula, char opB, int m, int n, int k, int lda, int ldb) const
{
T* cCula = (T*) malloc(m*n*sizeof(T));
//culaStatus culaSgemm(char transa, char transb, int m, int n, int k, culaFloat alpha, culaFloat* a,
int lda, culaFloat* b, int ldb, culaFloat beta, culaFloat* c, int ldc);
//C := alpha*op(A)*op(B)+beta*C, where op=[N(none), T(transposed), C(conjugate)]
culaStatus status = culaSgemm(opA, opB, m, n, k, 1, aCula, lda, bCula, ldb, 0, cCula, m);
checkStatus(status);
return cCula;
}
};
return input;
}
#endif
G.2.5. common/CULAContext.h
#ifndef CULACONTEXT_H_
#define CULACONTEXT_H_
#include <cula_lapack.h>
class CULAContext {
public:
CULAContext();
void init();
virtual ~CULAContext();
private:
void checkMinimumCulaRequirements();
void checkStatus(culaStatus status);
};
#endif /* CULACONTEXT_H_ */
G.2.6. common/CULAContext.cpp
#include "CULAContext.h"
#include "Exception.h"
#include <sstream>
CULAContext::CULAContext() {
culaStatus status = culaInitialize();
checkStatus(status);
}
void CULAContext::init() {
this->checkMinimumCulaRequirements();
}
CULAContext::~CULAContext() {
culaShutdown();
}
void CULAContext::checkMinimumCulaRequirements()
{
std::stringstream errorMessage;
G.2.7. common/Exception.h
#ifndef EXCEPTION_H_
#define EXCEPTION_H_
#include <string>
#include <exception>
#endif /* EXCEPTION_H_ */
G.2.8. common/Exception.cpp
#include "Exception.h"
y = y’;
u = u’;
if size(y,2) ~= size(u,2)
error(’lfd_control:input’,’Unable to determine current time step number: k. Samples in y(count: %d) and u(
count: %d) do not match’, size(y,2), size(u,2));
end
k = size(y,2);
%m=cantidad de componentes de y
%r=cantidad de componentes de u
m = size(y,1);
r = size(u,1);
control_state.p = p;
control_state.alpha = alpha;
control_state.mu = mu;
control_state.limits = limits;
control_state.s = s;
control_state.m = m;
control_state.r = r;
control_state.g = g;
control_state.k = k;
%k indica el paso a partir del cual se aplica el control; debe ser k-p-s >=1,
%k-s>=1
if k-p-s < 1
error(’lfd_control:k_validation’, ’Arguments error. TimeStep, Order and PredictionHorizon should match
the following rule: k-p-s>=1. k: %d,p: %d,s: %d.’, k_last_computation, p, s);
end
%Se define q=vector de m componentes para indicar el peso para cada componente.
%Se forma T’Q; se necesitan ónicamente las primeras r filas de T‘Q usando la notación de Juang
%por lo tanto no es necesario computar Q completa. Donde se supone Q=diag(repmat(q,1,s));
A=-A(:,:,2:end);
beta00=B(:,:,1);
beta0(:,:,1)=B(:,:,2)+A(:,:,1)*beta00;
for kk=2:s-1;
if kk<=p;
aux=zeros(size(beta00));for l=1:kk-1;aux=aux+A(:,:,l)*beta0(:,:,kk-l);end;aux=aux+A(:,:,kk)*beta00;
beta0(:,:,kk)=B(:,:,kk+1)+aux;
else
aux=zeros(size(beta00));for l=1:p;aux=aux+A(:,:,l)*beta0(:,:,kk-l);end;
beta0(:,:,kk)=aux;
end;
end;
control_state.TTQr = TTQr;
control_state.h_k = zeros(r,p*r+p*m);
control_state.u_k = zeros(1,r);
%tengo que tener tanto cada salida y como cada entrada u dados como
%vectores columna, es decir y de mxN, u de r*N, N=cantidad de
%observaciones
end
y = y’;
u = u’;
m = control_state.m;
r = control_state.r;
p = control_state.p;
s = control_state.s;
limits = control_state.limits;
alpha = control_state.alpha;
mu = control_state.mu;
TTQr = control_state.TTQr;
h_k_1 = control_state.h_k;
k = size(y,2)+1;
if m ~= size(y,1)
error(’lfd_control:input’,’Coordinates from state vector ’’y’’ do not match ’’m’’ previously defined. y
(coords= %d), m= %d’, size(y,1), m);
end
if r ~= size(u,1)
error(’lfd_control:input’,’Coordinates from actuation vector ’’u’’ do not match ’’r’’ previously
defined. u(coords= %d), r= %d’, size(u,1), m);
end
if size(y,2) ~= size(u,2)
error(’lfd_control:input’,’Unable to determine current time step number: k. Samples in y(count: %d) and
u(count: %d) do not match’, size(y,2), size(u,2));
end
%k indica el paso a partir del cual se aplica el control; debe ser k-p-s >=1,
%k-s>=1
if k-p-s < 1
error(’lfd_control:k_validation’, ’Arguments error. TimeStep, Order and PredictionHorizon should match
the following rule: k-p-s>=1. k: %d,p: %d,s: %d.’, k, p, s);
end
%According to Kegerise:
%3. Update the data vectors ys(k-s) and vp(k-p-s).
%4. Update h(k) according to Eq. 16. so h(kk + 1) = alpha*h(kk)-2mu*TTQr*ys(kk-s)*vp’(kk-p-s)
%5. Compute the control effort as: u(k) = hvp(k-p).
control_state.u_k = u_k;
control_state.h_k = h_k;
end
[2] Frédéric Archambeau, Namane Méchitoua, and Marc Sakiz. Code saturne: a finite volume
code for the computation of turbulent incompressible flows. International Journal on Finite
Volumes, 1, 2004.
[3] G. Artana, A. Cammilleri, J. Carlier, and E. Memin. Strong and weak constraint variational
assimilations for reduced order modelling for flow control. Physics of fluids, 8:3264–3288,
2012.
[4] G. Artana, R. Sosa, E. Moreau, and G. Touchard. Control of the near wake-flow around a
circular cylinder with electrohydrodynamic actuators. Experiments in Fluids, 35:580–588,
2003.
[5] Alexandre Barbagallo, Denis Sipp, and Peter J. Schmid. Closed-loop control of an open
cavity flow using reduced-order models. Journal of Fluid Mechanics, 641:1–50, 12 2009.
[6] J. F. Beaudoin, O. Cadot, J. L. Aider, and J. E. Wesfreid. Drag reduction of a bluff body
using adaptive control methods. Physics of Fluids, 18(085107), 2006.
[7] Thomas R. Bewley. Flow control: new challenges for a new renaissance. Progress in Aeros-
pace Sciences, 37(1):21 – 58, 2001.
[8] F.A. Brauer and C. Castillo-Chávez. Mathematical Models in Population Biology and Epi-
demiology. Texts in Applied Mathematics. Springer-Verlag, 2001.
[9] O. Cadot, B. Thiria, and J.F. Beaudoin. Passive drag control of a turbulent wake by local
disturbances. Solid Mechanics and its Applications, 14:529–537, 2009.
[11] Louis N. Cattafesta, Qi Song, David R. Williams, Clarence W. Rowley, and Farrukh S.
Alvi. Active control of flow-induced cavity oscillations. Progress in Aerospace Sciences,
44(7-8):479–502, 2008.
[12] CEI. EnSight User Manual for Version 10.0. Computational Engineering International,
Inc, 1 2012.
[13] H. Choi, W. Jeon, and J. Kim. Control of flow over a bluff body. Annual Review of Fluid
Mechanics, 40(1):113–139, 2008.
[14] D W Clarke, C Mohtadi, and P S Tuffs. Generalized predictive control - part 1. the basic
algorithm. Automatica, 23(2):137–148, March 1987.
234
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
[15] D W Clarke, C Mohtadi, and P S Tuffs. Generalized predictive control - part 2. extensions
and interpretations. Automatica, 23(2):149–160, March 1987.
[16] Kelly Cohen, Selin Aradag, Stefan Siegel, Jurgen Seidel, and Tom McLaughlin. A Metho-
dology Based on Experimental Investigation of a DBD-Plasma Actuated Cylinder Wake for
Flow Control, chapter 6, pages 117–138. InTech Europe, 2012.
[17] S. Scott Collis, Ronald D. Joslin, Avi Seifert, and Vassilis Theofilis. Issues in active flow con-
trol: Theory, control, simulation, and experiment. Progress in Aerospace Sciences, 40(1):237
– 289, 2004.
[18] Juan D’Adamo, Leo M. González, Alejandro Gronskis, and Guillermo Artana. The scenario
of two-dimensional instabilities of the cylinder wake under electrohydrodynamic forcing: a
linear stability analysis. Fluid Dynamics Research, 44(055501):20, 2012.
[20] T. Duriez, J.L. Aider, and J.E. Wesfreid. Self-sustaining process through streak generation
in a flat-plate boundary layer. Physical Review Letters, 103(14), 2009.
[22] HeinrichE. Fiedler. Control of free turbulent shear flows. In Mohamed Gad-el Hak and
Andrew Pollard, editors, Flow Control, volume 53 of Lecture Notes in Physics, pages 335–
429. Springer Berlin Heidelberg, 1998.
[23] Power Generation Fluid Dynamics and Environment Department Single Phase Thermal-
Hydraulics Group. Code Saturne 2.3.1 Theory Guide. EDF R&D, 12 2011.
[25] E. Gillies. Low-dimensional control of the circular cylinder wake. Journal of Fluid Mecha-
nics, 371:157–178, 1998.
[26] E. A. Gillies. Low-dimensional control of the circular cylinder wake. Journal of Fluid
Mechanics, 371:157–178, 9 1998.
[27] G. Godard and M. Stanislas. Control of a decelerating boundary layer. part 3: Optimization
of round jets vortex generators. Aerospace Science and Technology, 10(6):455–464, 2006.
[28] A. Gronskis, R. Sosa, and G. Artana. Modelling ehd actuation with a slip velocity. 2009.
[29] H.R. Hall. Governors and governing mechanism. The Technical Publishing Co., 287, Deans-
gate, Manchester, 1903.
[30] Aurelien Hervé, Denis Sipp, Peter J. Schmid, and Manuel Samuelides. A physics-based
approach to flow control using system identification. Journal of Fluid Mechanics, 702:26–
58, 2012.
[31] Shao-Ching Huang and John Kim. Control and system identification of a separated flow.
Physics of Fluids, 20(101509), 2008.
Bibliografı́a 235
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
[32] X.Y. Huang. Feedback control of vortex shedding from a circular cylinder. Experiments in
Fluids, 20(3):218–224, 1996.
[33] Jer-Nan Juang and Minh Phan. Deadbit predictive controllers. Technical Memorandum
112862, Nasa, 1997.
[34] T. Jukes and K. Choi. Control of unsteady flow separation over a circular cylinder using
dielectric-barrier-discharge surface plasma. Physics of fluids, 21(9):094106, 2009.
[35] Michael A. Kegerise, Randolph H. Cabell, and Louis N. Cattafesta. Real time feedback
control of flow-induced cavity tones - part 1: Fixed-gain control. Journal of Sound and
Vibration, 307:906–923, 2007.
[36] Michael A. Kegerise, Randolph H. Cambell, and Louis N. Cattafesta. Real time feedback
control of flow-induced cavity tones - part 2: Adaptive control. Journal of Sound and
Vibration, 307:924–940, 2007.
[37] David B. Kirk and Wen-mei W. Hwu. Programming Massively Parallel Processors: A
Hands-on Approach. Morgan Kaufmann Publishers Inc., San Francisco, CA, USA, 1st
edition, 2010.
[38] J. Kostas, J.M. Foucaut, and M. Stanislas. The flow structure produced by pulsed-jet vortex
generators in a turbulent boundary layer in an adverse pressure gradient. Flow, Turbulence
and Combustion, 78(3-4):331–363, 2007.
[40] Alexey Kozlov. Plasma actuators for bluff body flow control. PhD thesis, University of
Notre Dame, 2010.
[41] J.C. Lin. Review of research on low-profile vortex generators to control boundary-layer
separation. Progress in Aerospace Sciences, 38(4-5):389–420, 2002.
[42] Lennart Ljung. System Identification: Theory for the User. Prentice-Hall Inc., Englewood
Cliffs, N.J., 1987.
[44] D.Q. Mayne, J.B. Rawlings, C.V. Rao, and P.O.M. Scokaert. Constrained model predictive
control: Stability and optimality. Automatica, 36(6):789 – 814, 2000.
[45] M.L. Minsky and Massachusetts Institute of Technology. Artificial Intelligence Laboratory.
Matter, Mind and Models. AI memo. Massachusetts Institute of Technology, Project MAC,
1965.
[46] M. Munska and T. Mclaughlin. Circular cylinder flow control using plasma actuators. AIAA
paper 2005-0141, 2005.
[47] Katsuhiko Ogata. Modern Control Engineering. Prentice Hall PTR, Upper Saddle River,
NJ, USA, 4th edition, 2001.
[48] A.V. Oppenheim, R.W. Schafer, and J.R. Buck. Discrete-time signal processing. Prentice-
Hall signal processing series. Prentice Hall, 1999.
Bibliografı́a 236
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
[49] A.V. Oppenheim, A.S. Willsky, and S.H. Nawab. Signals and Systems. Prentice-Hall signal
processing series. Prentice-Hall International, 1997.
[50] A. E. Perry, M. S. Chong, and T. T. Lim. The vortex-shedding process behind two-
dimensional bluff bodies. Journal of Fluid Mechanics, 116:77–90, 2 1982.
[51] S.Joe Qin and Thomas A. Badgwell. A survey of industrial model predictive control tech-
nology. Control Engineering Practice, 11(7):733 – 764, 2003.
[52] J. Reece Roth. Prospective industrial applications of the one atmosphere uniform glow
discharge plasma. 1:–223 Vol.1, 2004.
[53] J. Richalet and D. O’Donovan. Predictive Functional Control: Principles and Industrial
Applications. Advances in industrial control. Springer London, Limited, 2009.
[54] A. Roshko. On the wake and drag of bluff bodies. J. Aeronaut. Sci., 22:124–132, 1955.
[55] Anatol Roshko. Experiments on the flow past a circular cylinder at very high reynolds
number. Journal of Fluid Mechanics, 10:345–356, 5 1961.
[56] J. Reece Roth, Daniel M. Sherman, and Stephen P. Wilkinson. Electrohydrodynamic flow
control with a glow-discharge surface plasma. AIAA Journal, 38(7):1166–1172, 2000.
[57] K. Roussopoulos. Feedback control of vortex shedding at low reynolds number. Journal of
Fluid Mechanics, 248:267–296, 1993.
[58] C. Rowley. Model reduction for fluid flows using balanced proper orthogonal decomposition.
Int. J. Bifurc. Chaos, 15:997–1013, 2005.
[59] H. Schlichting. Boundary-Layer Theory. MacGraw-Hill, 7th edition, 1979.
[60] D. Shiels and A. Leonard. Investigation of a drag reduction on a circular cylinder in rotary
oscillation. Journal of Fluid Mechanics, 431:297–322, 3 2001.
[61] C.A. Smith and A.B. Corripio. Principles and practice of automatic process control. Wiley,
2006.
[62] Roberto Sosa. Mecanismos de Acople en Actuadores EHD. PhD thesis, Facultad de Inge-
nierı́a, Universidad de Buenos Aires, 2007.
[63] R.B. Stull. An Introduction to Boundary Layer Meteorology. Atmospheric and oceanograp-
hic sciences library. Kluwer Academic Publishers, 1988.
[64] G. Tadmor, O. Lehmann, B.R. Noack, L. Cordier, J. Delville, J. Bonnet, and M. Morzyński.
Reduced-order models for closed-loop wake control. Philos Trans A Math Phys Eng Sci,
369(1940):1513–24, 2011.
[65] Gilead Tadmor, Oliver Lehmann, Bernd R. Noack, and Marek Morzynski. Mean field
representation of the natural and actuated cylinder wake. Physics of Fluids, 22(3):034102,
2010.
[66] B. Thiria, S. Goujon-Durand, and J.E. Wesfreid. The wake of a cylinder performing rotary
oscillations. Journal of Fluid Mechanics, 560:123–147, 2006.
[67] Lloyd Nicholas Trefethen. Finite difference and spectral methods for ordinary and partial
differential equations. Cornell University - Department of Computer Science and Center for
Applied Mathematics, 1996.
Bibliografı́a 237
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca
[68] N. Wiener. Cybernetics: Or, Control and Communication in the Animal and the Machine.
The @MIT paperback series: Massachusetts Institute of Technology. Mit Press, 1965.
[69] C H K Williamson. Vortex dynamics in the cylinder wake. Annual Review of Fluid Mecha-
nics, 28(1):477–539, 1996.
[71] M. M. Zhang, L. Cheng, and Y. Zhou. Closed-loop-controlled vortex shedding and vibra-
tion of a flexibly supported square cylinder under different schemes. Physics of Fluids,
16(5):1439–1448, 2004.
[72] K. Zhou and J.C. Doyle. Essentials of Robust Control. Prentice-Hall International editions.
Prentice-Hall International, 1998.
Bibliografı́a 238