Está en la página 1de 239

UNIVERSIDAD DE BUENOS AIRES

Facultad de Ingenierı́a

TESIS DE GRADO

Sistema de Control de Flujos a Lazo Cerrado Mediante


Controlador Lineal Basado en Imágenes

Presentada por:
Pablo Daniel Roca

Director: Dr. Ing. Guillermo Artana

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 Sı́ntesis del Estado del Arte 11

2.1 Introducción 12

2.2 Teorı́a de Control 13


2.2.1 Fundamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2 Estrategias de Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.2.1 Controlabilidad, Observabilidad y Estabilidad . . . . . . . . . . . . . . 17
2.2.3 Evolución de la Teorı́a Control . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.3.1 Teorı́a Control Clásica . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.3.2 Teorı́a Control Moderno . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2.4 Control Predictivo Basado en Modelo . . . . . . . . . . . . . . . . . . . 19

2.3 Control y Modelos de Fluidodinámica 24


2.3.1 Generalidades de Modelos de Fluidodinámica . . . . . . . . . . . . . . . 24
2.3.2 Modelos Basados en la Fı́sica . . . . . . . . . . . . . . . . . . . . . . . . 25
2.3.3 Modelos de Caja Negra . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.3.3.1 Identificación de Sistemas . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.3.3.2 Efectos de No-Linealidades . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.3.4 Avances en Aplicaciones de Control en el Dominio de la Fluidodinámica 30

2.4 Trabajo Interdisciplinario y Aspectos Computacionales 32


2.4.1 Discretización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.4.2 Tiempos de Procesamiento . . . . . . . . . . . . . . . . . . . . . . . . . 33

2.5 Problemática a Resolver 34

2.6 Conclusiones 35

3 Solución y Diseño de la Experiencia 36

3.1 Introducción 37

3.2 Sistema Fı́sico Bajo Estudio 38


3.2.1 Estela de un Cilindro . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.2.1.1 Desprendimiento de Vórtices . . . . . . . . . . . . . . . . . . . . . . . . 38
3.2.1.2 Regı́menes de Escurrimiento . . . . . . . . . . . . . . . . . . . . . . . . 41
3.2.2 Actuación sobre el Cilindro . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.2.2.1 Actuadores por Rotación . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.2.2.2 Actuadores de Plasma . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.2.3 Aplicaciones Particulares de Control sobre el Cilindro . . . . . . . . . . 43

3.3 Diseño y Objetivos de la Experiencia 45


3.3.1 Configuración y Dimensiones . . . . . . . . . . . . . . . . . . . . . . . . 45
3.3.2 Sensores y Actuadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.3.3 Sı́ntesis y Objetivos de la Experiencia . . . . . . . . . . . . . . . . . . . 49

3.4 Algoritmo de Identificación del Sistema 51

3.5 Algoritmo de Control a Lazo Cerrado 54

3.6 Conclusiones 58

4 Ensayo Experimental 59

4.1 Introducción 60

4.2 Mallado de la Experiencia 61


4.2.1 Tamaño de Celdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.2.2 Paso de Tiempo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

4.3 Simulación de la Experiencia 65


4.3.1 Configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.3.1.1 usini1.f90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.3.1.2 usclim.f90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.3.2 Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

4.4 Comunicación con el Sistema de Control 75


4.4.1 Lenguajes Utilizados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.4.2 Interacción entre Módulos . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.4.3 Implementación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

4.5 Identificación del Sistema 81


4.5.1 Entrenamiento del Sistema . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.5.2 Implementación del Algoritmo . . . . . . . . . . . . . . . . . . . . . . . 83
4.5.3 Verificación del Modelo ARX . . . . . . . . . . . . . . . . . . . . . . . . 84

4.6 Sistema de Control a Lazo Cerrado 90


4.6.1 Implementación del Algoritmo . . . . . . . . . . . . . . . . . . . . . . . 90
4.6.1.1 Inicialización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.6.1.2 Iteración de Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.6.2 Resultados de Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.6.2.1 Análisis de Energı́a y RMS de las Fluctuaciones en la Estela . . . . . . 97
4.6.3 Pruebas de Robustez . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

4.7 Conclusiones 106


5 Conclusiones Generales y Perspectivas 108

5.1 Conclusiones Generales 109

5.2 Trabajos Futuros 111

Apéndices 112

A Reseña de Control de Fluidos 113


A.1 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
A.2 Evolución Histórica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

B Mallado de la Experiencia 115


B.1 Detalle del Mallado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
B.2 Efectos de Cambios Bruscos en la Malla durante la Simulación . . . . . 117

C Verificación de la Identificación del Sistema 119


C.1 Ajuste en Implementación Matlab . . . . . . . . . . . . . . . . . . . . . 119
C.2 Ajuste y Tiempos en Implementación C++ . . . . . . . . . . . . . . . . 119

D Avances Experimentales para Trabajos Futuros 122


D.1 Control Adaptativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
D.2 Control con Modelo ARX de Orden Elevado . . . . . . . . . . . . . . . 123
D.3 Captura de Imágenes Mediante Cámaras Digitales . . . . . . . . . . . . 125
D.3.1 PixelFly qe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
D.3.2 Pulnix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
D.3.3 SpeedCam Mini Vis e2 . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

E Publicaciones 127
E.1 Anales de la AFA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
E.2 Physics of Fluids . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

F Códigos Fuente 152


F.1 Extensión del Mallado 2D a 3D . . . . . . . . . . . . . . . . . . . . . . . 152
F.2 Conversión del Mallado Irregular a una Grilla Cartesiana . . . . . . . . 155
F.2.1 chrCleanFolderIfExists.m . . . . . . . . . . . . . . . . . . . . . . . . . . 155
F.2.2 chrComputeAverage.m . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
F.2.3 chrComputeVorticityAverageForGeoXY.m . . . . . . . . . . . . . . . . 156
F.2.4 chrExtractBinaryHeader.m . . . . . . . . . . . . . . . . . . . . . . . . . 156
F.2.5 chrFindFiles.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
F.2.6 chrFindFilesAndComputeAverage.m . . . . . . . . . . . . . . . . . . . . 157
F.2.7 chrGetAmountOfHeadingCharacters.m . . . . . . . . . . . . . . . . . . 157
F.2.8 chrReadBinaryContent.m . . . . . . . . . . . . . . . . . . . . . . . . . . 157
F.2.9 chrReadBinaryGeo.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
F.2.10 chrReadVelocity2D.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
F.2.11 chrWriteBinaryContent.m . . . . . . . . . . . . . . . . . . . . . . . . . . 158
F.2.12 chrWriteCaseFile.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
F.2.13 geoComputeIntersectionArea.m . . . . . . . . . . . . . . . . . . . . . . . 159
F.2.14 geoGetBoundingRectsForDelta.m . . . . . . . . . . . . . . . . . . . . . . 159
F.2.15 geoTransformContentToNonXY.m . . . . . . . . . . . . . . . . . . . . . 160
F.2.16 geoTransformContentToXY.m . . . . . . . . . . . . . . . . . . . . . . . 160
F.2.17 geoTransformMeshToXYGrid.m . . . . . . . . . . . . . . . . . . . . . . 160
F.2.18 polygonArea.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
F.2.19 polygonClip.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
F.3 Cálculo de Energı́a Cinética y RMS de las Fluctuaciones . . . . . . . . 163
F.3.1 plotEnergy.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
F.3.2 processEnergy.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
F.3.3 processRmsCriteria.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
F.3.4 computeReynoldsTensor.m . . . . . . . . . . . . . . . . . . . . . . . . . 167
F.3.5 computeRMS.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
F.3.6 selectIntegrationCoordinates.m . . . . . . . . . . . . . . . . . . . . . . . 167
F.4 Simulación en Code Saturne . . . . . . . . . . . . . . . . . . . . . . . . 167
F.4.1 usini1.f90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
F.4.2 usclim.f90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
F.5 Identificador del Sistema en Matlab . . . . . . . . . . . . . . . . . . . . 189
F.5.1 lfd arx.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
F.5.2 lfd compare.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
F.5.3 lfd training actuation.m . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
F.5.4 lfd training actuation gaussian.m . . . . . . . . . . . . . . . . . . . . . . 192
F.5.5 lfd training actuation multiple gaussian.m . . . . . . . . . . . . . . . . . 192
F.5.6 lfd training actuation pulse.m . . . . . . . . . . . . . . . . . . . . . . . 192
F.5.7 lfd training actuation ramp.m . . . . . . . . . . . . . . . . . . . . . . . 192
F.6 Controlador en C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
F.6.1 main.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
F.6.2 Config.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
F.6.3 configuration control.txt . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
F.6.4 configuration training.txt . . . . . . . . . . . . . . . . . . . . . . . . . . 196
F.6.5 Constants.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
F.6.6 Controller.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
F.6.7 Controller.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
F.6.8 Logger.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
F.6.9 lfd control lagrange init.m . . . . . . . . . . . . . . . . . . . . . . . . . 202
F.6.10 lfd control lagrange.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
F.6.11 MatlabExecutor.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
F.6.12 MatlabExecutor.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
F.6.13 Matrix.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
F.6.14 Parser.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
F.6.15 Parser.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
F.6.16 SaturneCommunicator.h . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
F.6.17 SaturneCommunicator.cpp . . . . . . . . . . . . . . . . . . . . . . . . . 211

G Códigos Fuente de Avances Experimentales 212


G.1 Pruebas de Concepto de Captura de Imágenes . . . . . . . . . . . . . . 212
G.1.1 PixelFly qe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
G.1.2 Pulnix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
G.1.3 SpeedCam Mini Vis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
G.2 Pruebas de Concepto de Ident. de Sist. en CUDA C/C++ y C++/GSL 214
G.2.1 main.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
G.2.2 arxEngine/ArxSystemIdentification.h . . . . . . . . . . . . . . . . . . . 216
G.2.3 arxEngine/ArxSystemIdentification.cpp . . . . . . . . . . . . . . . . . . 216
G.2.4 common/Matrix.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
G.2.5 common/CULAContext.h . . . . . . . . . . . . . . . . . . . . . . . . . . 229
G.2.6 common/CULAContext.cpp . . . . . . . . . . . . . . . . . . . . . . . . 229
G.2.7 common/Exception.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
G.2.8 common/Exception.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
G.3 Pruebas de Concepto de Controlador Adaptativo . . . . . . . . . . . . . 231
G.3.1 lfd control init.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
G.3.2 lfd control.m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Agradecimientos

A Claudia, por todo el tiempo compartido... y el que resta por compartir.


A mi familia, por estar siempre presente.
A los integrantes del Laboratorio de Fluidodinámica (UBA), por la colaboración constante,
desinteresada y oportuna que siempre me prestaron. En particular, un agradecimiento especial
a Guillermo Artana, Ada Cammilleri y Thomas Duriez que participaron activamente de las
experiencias y me guiaron en el desarrollo del presente trabajo.
A mis compañeros de trabajo, por todo lo que aprendı́ y crecı́ profesionalmente durante estos
años.
A mis compañeros de facultad, por compartir las dificultades que presenta carrera.
A mis compañeros del Proyecto Nahual, por demostrar que la computación también sirve
para cambiar algo.
A mis compañeros de ayudantı́a, por introducirme al mundo de la docencia.
A los que creen en la ciencia como camino para el desarrollo.
A la gente tenaz y trabajadora.

Pablo Daniel Roca, Octubre de 2013

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.

A continuación se describen las partes que componen el presente trabajo y su organización.


La Parte 2 resume el estado del arte de la Teorı́a de Control y del Control de Fluidos junto
con los conceptos generales que resultan indispensables para el trabajo en el área. Se focaliza
en los controladores predictivos y los escenarios de control a lazo cerrado debido al impacto que
tienen en aplicaciones reales. De igual forma, se hace mención a las técnicas de modelado pun-
tualizando los esquemas de caja negra y la identificación de dichos sistemas en base al muestreo
de experiencias. Por último, se especifican ciertos aspectos computacionales importantes en el
Control de Fluidos y se define la problemática a resolver.
La Parte 3 sintetiza los conceptos aplicados en el escurrimiento de un flujo sobre el cilindro
y las aplicaciones del estudio de dicha experiencia en la vida cotidiana. Luego, se establecen las

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

Sı́ntesis del Estado del Arte

11
2.1 Introducción

El presente capı́tulo introduce los conceptos fundamentales y definiciones de la Teorı́a de


Control ası́ como posibles clasificaciones para controladores de acuerdo a su tipo. A su vez, se
realiza una sı́ntesis sobre la evolución y etapas claves del control: Teorı́a de Control Clásica
y Teorı́a de Control Moderno, haciendo principal hincapié en el Control Predictivo Basado en
Modelo.
Una vez definidos los conceptos de control, se exploran las diferentes técnicas de modelización
para fenómenos de fluidodinámica tanto para aquellos basados en la fı́sica como los de caja negra.
Se profundiza en estas últimas y se ejemplifica su uso en distintas situaciones de control de fluidos
reforzando el impacto de las no-linealidades en la identificación del sistema y posterior uso del
modelo.
Luego, se hace foco en la sub-rama de Control de Fluidos. Se presentan los objetivos más
comunes, aplicaciones conocidas y la importancia del trabajo interdisciplinario junto con los
aspectos computacionales más importantes para el área.
Por último, se brinda una descripción de la problemática a tratar incluyendo una breve
definición de la experiencia prototipo elegida a modo de ejemplo.

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:

Sistema: combinación de componentes que interactúan con un cierto objetivo. El concepto de


sistema puede ser aplicado a elementos fı́sicos (como los sistemas biológicos o fenóme-
nos fı́sicos) o a nociones abstractas (como conceptos económicos, flujos de información o
algoritmos de procesamiento).

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.

Controlador: sistema encargado de determinar la necesidad de actuación para conseguir cierto


objetivo de proceso e informar dicha señal al actuador.

Variables Controladas: cantidad o condición que es medida y controlada. También se las


conoce como señales de salida del proceso a controlar o, simplemente, salidas.

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).

2.2.2. Estrategias de Control


Una posible clasificación de la estrategia de control elegida para un sistema depende de
la forma en que utiliza energı́a para su actuación. La división más básica que plantea esta
clasificación separa aquellos sistemas cuyos actuadores utilizan energı́a para poder forzar al
proceso en estudio de aquellos que no emplean energı́a. Se habla entonces de sistemas de control
activo y pasivo respectivamente [22].

Capı́tulo 2.2. Teorı́a de Control 14


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

El control pasivo consiste en la disposición de elementos fı́sicos dentro de la planta que


modifican la dinámica del proceso bajo estudio, acercándola a una configuración deseada. Este
esquema de actuación posee un interés menor para la teorı́a de control dada la complejidad
en modificar el objetivo de control durante su funcionamiento. Esta circunstancia presenta un
limitante importante para el uso del controlador ya que un cambio en el objetivo esperado
(aunque se trate de un pequeño ajuste en el valor deseado) suele requerir la redefinición del
actuador, colocación del nuevo dispositivo fı́sico y sucesivas pruebas y ajustes para obtener la
nueva dinámica deseada.
Por otro lado, el control activo utiliza energı́a para forzar las condiciones del fluido mediante
distintas técnicas de actuación. Este tipo de control acepta la posibilidad de variar parámetros
de actuación como la intensidad o frecuencia dentro de ciertos lı́mites en pleno ciclo de control,
es decir, sin necesidad de practicar cambios ni ajustes sobre los actuadores. Los ajustes pueden
hacerse manualmente, siendo un humano el que indica la variación, o mediante un controlador
que reaccione frente a los cambios que presente el sistema. Esta flexibilidad permite definir siste-
mas de control con cierto grado de inteligencia, esto es, con la posibilidad de variar la actuación
de forma dinámica sin indicaciones humanas. Se definen entonces dos tipos de estrategias de
control activo: el predeterminado y el reactivo. La Teorı́a de Control se centra en esquemas de
control reactivo mediante el estudio de distintos algoritmos, la medición de variables de planta
y la construcción de dispositivos de actuación que mejor ajustan al proceso bajo estudio.
A continuación se resume esta caracterización de controladores considerando su fuente de
energı́a [22]:

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

Capı́tulo 2.2. Teorı́a de Control 15


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 2.2. Teorı́a de Control 16


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

En el ejemplo de horno con temperatura automática, un posible sistema de control a lazo


abierto recibe del humano la temperatura esperada y activa el sistema de calefacción a cierta
intensidad precalculada. Un sistema de control a lazo cerrado, por el contrario, activarı́a la cale-
facción con una intensidad regulada por la diferencia entre la temperatura de referencia deseada
y la medida en el interior del horno. A medida que esta diferencia disminuye, la intensidad
de calefacción converge a un valor pero, en caso de aparecer un cambio brusco en la medición
(por ejemplo, al introducir un producto congelado que reduce la temperatura), el sistema ajusta
nuevamente la actuación. Por último, se puede pensar en un sistema que varı́a la intensidad de
calefacción dependiendo de la temperatura de referencia y de la temperatura exterior al horno,
entregando mayor calor en dı́as frı́os pero mediante un cálculo predefinido, independiente de la
temperatura real del interior del horno.

2.2.2.1. Controlabilidad, Observabilidad y Estabilidad


En el caso particular del control a lazo cerrado, resultan importantes las propiedades de con-
trolabilidad, observabilidad y estabilidad. Si bien es posible encontrar una definición matemática
apropiada para estos términos respecto de las ecuaciones de estado del sistema controlador [72],
resulta de suma utilidad comprender la naturaleza de cada uno desde un punto de vista intui-
tivo. La controlabilidad determina si todos los modos del sistema pueden ser influenciados
por el controlador de forma arbitraria. Se trata de una propiedad tanto del estado del sistema
como del sistema de actuación. De forma más especı́fica se puede hablar de la controlabilidad
de salida que indica el control de las variables de salida del sistema independientemente de si
puede controlar variables de estado intermedias o no. La observabilidad está relacionada con
la habilidad del sistema de sensado para medir los cambios de estado de forma confiable. El
sistema es observable si se puede determinar el estado en base a las mediciones de las salidas y
los valores conocidos de las entradas. Como ejemplo de sistema con observabilidad limitada se
puede suponer el caso de una olla a presión hogareña con indicadores de temperatura pero sin
sensores de presión y, por lo tanto, no es posible observar el conjunto de estados del sistema. La
estabilidad se asemeja a la controlabilidad pero en este caso exige únicamente que los modos
no estables puedan ser controlados. Esta diferenciación permite indicar en qué casos un sistema
estabilizable puede ser suficiente o cuando es necesario un sistema controlable debido a que los
modos estables poseen un papel importante en la respuesta final y se los desea manipular.

2.2.3. Evolución de la Teorı́a Control


A lo largo de los años, la evolución de la teorı́a de control denota distintas etapas en cuanto a
madurez y enfoque de las técnicas aplicadas. Durante ese avance continuo, se pueden identificar
dos tendencias que prevalecen y que presentan diferencias notorias respecto a los objetivos del
control: la Teorı́a de Control Clásica y la Teorı́a de Control Moderna.
Si bien existen estudios de control anteriores a la formalización de la teorı́a, se trata de
experiencias muy diversas y basadas en el empirismo. Con la revolución industrial aparece la
necesidad de máquinas automáticas y se acelera la investigación sobre estos métodos [21]. La
invención del regulador de presión del motor a vapor por parte de J. Watt (1736-1819) en 1769 fija
un caso de estudio de suma importancia que permite delinear las bases teóricas del control en los
años subsiguientes. El escenario de control es dominado entonces por el ámbito industrial hasta
la década de 1940, donde los conflictos bélicos enfocan la mayor parte del esfuerzo cientı́fico de
control en balı́stica y desarrollo aéreo y naval. Ya finalizando la década, la aparición del término
cybernetics (cibernética) para referirse al estudio de control y comunicaciones en animales y
máquinas marca un hito importante en el desarrollo de la teorı́a de control. Fue el matemático

Capı́tulo 2.2. Teorı́a de Control 17


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

2.2.3.1. Teorı́a Control Clásica


La Teorı́a de Control Clásica centra su estudio en técnicas en el dominio de la frecuencia.
Este enfoque utiliza técnicas provenientes de los avances matemáticos propuestos por Laplace
(1749-1827), Fourier (1768-1830) y Cauchy (1789-1857) para el análisis de sistemas Lineales
e Invariantes en el Tiempo (LTI) [47, 49]. A tal efecto se definen las variables dependientes
del tiempo y(t) y u(t) para referirse a la salida y entrada del sistema respectivamente. Si bien
es posible conocer la relación entre dichas variables respecto del tiempo, se define la función
transferencia del sistema según
Y (s)
H(s) =
U (s)
donde Y (s) es la transformada de Laplace de la salida y U (s) es la transformada de Laplace de
la entrada. Esta función es equivalente a la transformada de la respuesta del sistema al impulso
(h(t)) y, por lo tanto, caracteriza al sistema si este es LTI [47]. Para sistemas LTI con variables
de salida y entrada únicas (single-input, single-output o SISO), se puede utilizar H(s) junto con
propiedades de la transformada de Laplace y técnicas gráficas (diagramas de Bode, diagramas
de polos y ceros, lugar de las raı́ces, entre otras) [61] para determinar la respuesta del sistema
a distintas señales de entrada y variaciones de frecuencias. Estos mecanismos fueron usados de
forma exhaustiva en comunicaciones y electrónica para la solución de problemáticas particulares
de las redes de comunicación de larga distancia que se establecen durante la primer mitad del
siglo XX.
La rama de automatización y control industrial mostró grandes avances en sus aplicaciones
al incorporar el controlador Proporcional-Integral-Derivativo (PID) que aplica feedback sobre las
variables controladas en su valores actuales y pasados. Este controlador a lazo cerrado emplea
un componente proporcional (P) al error instantáneo, una parte integral (I) que aporta respecto
de la acumulación de error por sobre o por debajo de la referencia y un elemento derivativo (D)
que entrega sensibilidad ajustando la actuación en base a la velocidad con que varı́a el error
(Fig. 2.2.4). Este tipo de controlador sigue siendo de gran utilidad al igual que el concepto de
función de transferencia sobre el que se basa. Sin embargo, al aumentar la necesidad de controlar
situaciones de múltiples variables de entrada y salida (multiple-input, multiple-output o MIMO)
donde las variables están ligadas entre sı́, los procedimientos de la Teorı́a Clásica se mostraron
por demás engorrosos [61, 47] dando lugar a nuevos mecanismos.

Capı́tulo 2.2. Teorı́a de Control 18


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

2.2.3.2. Teorı́a Control Moderno


En contraste con la Teorı́a Clásica, la Teorı́a de Control Moderno realiza sus planteos básicos
en el dominio del tiempo y sobre sistemas MIMO con un manejo matricial en la matemática
de control que otorga transparencia sobre la multiplicidad de variables. Fue R. Kalman (1930-)
quien introdujo el concepto de estado como entidad matemática que intercede entre entradas y
salidas permitiendo la existencia de feedback múltiple entre las variables de forma natural. Se
define entonces el estado de un sistema dinámico según [24]:

“El estado de un sistema dinámico es un conjunto de cantidades fı́sicas cuya especificación


(en ausencia de excitaciones externas) determina por completo la evolución del sistema.”

Este concepto enfatiza la existencia de una estructura interna al sistema y la noción de


causalidad de su dinámica. Para un sistema de dimensiones finitas la representación del estado
está dada por una ecuación diferencial vectorial de dimensiones finitas tal que:

ẋ(t) = Ax(t) + Bu(t)


y(t) = Cx(t)

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.

2.2.4. Control Predictivo Basado en Modelo


El campo del control predictivo fue concebido en el ambiente industrial durante la década
de 1970 como respuesta para automatización de plantas quı́micas, de energı́a y refinerı́as al

Capı́tulo 2.2. Teorı́a de Control 19


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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)

Minimización de la variabilidad (que pretende evitar la disparidad en la calidad de pro-


ductos)

El controlador LQG presentado en 1960 es considerado pionero en el uso de ciertos conceptos


predictivos en controladores pero, aún demostrando buenos resultados en el campo de procesos
no lineales, no tuvo aceptación masiva por la industria. Una de las razones más importantes
de la poca penetración de mercado reside en barreras culturales con la comunidad industrial
que no vieron prácticos a los nuevos conceptos de control y prefirieron continuar con estrategias
clásicas que les resultaban más naturales [51]. Por el contrario, los avances en la teorı́a de
control en la década de 1970 que culminan en fundamentos del control predictivo resultaron de
fácil entendimiento y adaptables a la problemática industrial:

Uso de un modelo que permita predicciones sobre las salidas futuras.

Minimización de una función objetivo mediante actuación activa.

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].

Capı́tulo 2.2. Teorı́a de Control 20


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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).

Capı́tulo 2.2. Teorı́a de Control 21


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

Capı́tulo 2.2. Teorı́a de Control 22


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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:

y(k) + a1 y(k − 1) + · · · +ana y(k − na)


=b1 u(k − 1) + · · · + bnb u(k − nb)
ξ(k) ξ(k − 1) ξ(k − nc)
+ + c1 + · · · + cnc
∆ ∆ ∆
donde ξ(k) es un variable estocástica que modela el error por perturbaciones, ∆ es el operador
de diferencia y na, nb, nc son lı́mites de predicción para las salidas, entradas y perturbaciones.
Este modelo resulta apropiado para aplicaciones industriales donde las perturbaciones son no
estacionarias como en el caso de saltos de escalón aleatorios o movimientos Brownianos [14]
y es uno de los motivos por los que el GPC demuestra mayores áreas de aplicación que sus
competidores.

Capı́tulo 2.2. Teorı́a de Control 23


2.3 Control y Modelos de Fluidodinámica

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 [...]”

Pero la necesidad de forzar la condición de un fluido está asociado a un objetivo predefinido


en términos de las propiedades del fluido. La manipulación del arrastre, sustentación, separación
de la capa lı́mite, repegado de la capa lı́mite, retardo de la transición son considerados objetivos
particulares del control de fluidos que pueden combinarse de forma simultánea o en distintas
facetas de una experiencia para definir el objetivo general de control. El Apéndice A incluye una
breve reseña de la evolución histórica sobre esta rama de la fluidodinámica ası́ como el detalle
de objetivos particulares de control de flujos.
Como se explica en el Capı́tulo 2.2, un sistema de control a lazo cerrado requiere de un
modelo para predecir estados futuros de las variables. A continuación se detallan las distintas
técnicas de modelización utilizadas en fluidodinámica y los avances de aplicación conseguidos en
el área.

2.3.1. Generalidades de Modelos de Fluidodinámica


En su acepción más genérica, un modelo es una representación de algún concepto en térmi-
nos de elementos que existen en cierta área de estudio. El área de estudio determina el lenguaje
con el cual se describe el objeto en cuestión y por lo tanto, la información que se puede extraer
de él.
M. Minsky (1927-) brinda una definición concisa para modelo [45]:

“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

fı́sicos ha sido un arma de gran utilidad para su análisis y manipulación


En el estudio de fluidodinámica, la importancia de los modelos reside principalmente en la
capacidad de predecir la respuesta de un flujo frente a condiciones definidas y cómo cambia
la respuesta al modificarse las condiciones. Si el modelo puede responder a estas preguntas,
será posible estimar la actuación necesaria para obtener determinado objetivo respecto del flujo.
Las ecuaciones de Navier-Stokes proveen de un modelo matemático completo sobre los
problemas de fluidodinámica. Sin embargo, la complejidad de resolución que presenta el sis-
tema de ecuaciones que gobierna el fenómeno plantea la necesidad de aplicar simplificaciones
al modelo. Esto es debido a su no-linealidad y alto orden. Un esquema alternativo consiste en
inferir un modelo simplificado a partir de la observación de un flujo particular y la adopción de
suposiciones sobre su naturaleza. Existen básicamente dos estrategias para obtener modelos que
arreglen las observaciones mediante cierto patrón: modelos basados en la fı́sica e identificación
de sistemas.

2.3.2. Modelos Basados en la Fı́sica


Este tipo de modelos buscan una reducción de orden sobre el modelo de ecuaciones de Navier-
Stokes utilizando una descomposición modal. Una de las elecciones más usuales es considerar
una descomposición del tipo Proper Orthogonal Decomposition (POD) donde se identifican los
modos de mayor energı́a y se desechan aquellos que producen un menor impacto. Este esquema
plantea una descomposición del campo de velocidades del flujo u(x, t) en modos espaciales y
temporales según:
Xn
u(x, t) = ai (t)φi (x)
i=1

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

Capı́tulo 2.3. Control y Modelos de Fluidodinámica 25


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

2.3.3. Modelos de Caja Negra


En contraposición a los modelos basados en la fı́sica del problema, el esquema de identificación
de sistemas utiliza modelos de caja negra que responden al sistema fı́sico. En este caso se
emplean técnicas empı́ricas y un conjunto de mediciones sobre la experiencia para elegir una
parametrización adecuada y determinar los parámetros que mejor ajustan a los valores medidos.

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

donde y(k) representa la variable observable en el tiempo k, p es el horizonte de regresión y αi


es un coeficiente de peso para el tiempo k − i. El modelo tendrá un buen ajuste si la relación
fijada por los αi existe en el sistema fı́sico y se mantiene a medida que avanza el paso de tiempo
k dentro de la ventana definida por los p coeficientes αi . El modelo asume que no existe relación
con variables para i > k o que la misma posee un αi despreciable.

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:

y(k) + a1 y(k − 1) + · · · + aNa y(k − Na ) =


b0 u(k) + b1 u(k − 1) + · · · + bNb u(k − Nb )

que también puede expresarse como


Na
X Nb
X
y(k) + ai y(k − i) = bi u(k − i)
i=1 i=0

Capı́tulo 2.3. Control y Modelos de Fluidodinámica 26


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Figura 2.3.1: Diagrama de bloques de un modelo ARX.

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)

Capı́tulo 2.3. Control y Modelos de Fluidodinámica 27


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Figura 2.3.2: Diagrama de bloques de un modelo ARMAX.

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.

2.3.3.1. Identificación de Sistemas


La identificación de sistemas cobra gran relevancia como campo de estudio para la obtención
de modelos de caja negra que representen fielmente el sistema fı́sico. El modelo elegido suele ser
predefinido en base a preconceptos o suposiciones sobre la experiencia y sus caracterı́sticas. La
elección del tipo de modelo y sus parámetros básicos como orden u horizontes de tiempo suele
fundamentarse en los conocimientos sobre el fenómeno pero aceptando que serán necesarios
ajustes posteriores en base a la exactitud que demuestre el modelo.
A su vez, es necesario definir las variables de estado a medir y determinar cuales se consideran
dependientes (outputs para modelos auto-regresivos) y cuales independientes (inputs). Luego, se
realiza un muestreo dentro del ámbito de una experiencia controlada y el conjunto de vectores de
estado obtenidos son utilizados para estimar los parámetros del modelo matemático que mejor
los ajustan. A tal fin, las técnicas de estimación de parámetros suelen plantear la minimización
del error que se presenta entre el valor real medido y una predicción de dicho valor mediante
el uso del modelo matemático. La técnica de estimación por cuadrados mı́nimos (Least Squares
Estimates o LSE) y sus variaciones son las de mayor aceptación debido a caracterı́sticas como
convergencia de la estimación, estabilidad y robustez.
La aplicación práctica de estas técnicas al campo del control de fluidos suele requerir de la
medición del campo de velocidades del fluido en una etapa previa su uso en el control. Esta etapa
suele denominarse fase de entrenamiento y puede incluir la contemplación de la experiencia fı́sica
para su posterior caracterización o la necesidad de aplicar cierta actuación para forzar el flujo.

Capı́tulo 2.3. Control y Modelos de Fluidodinámica 28


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

2.3.3.2. Efectos de No-Linealidades


Un inconveniente conocido en las estrategias antes descritas es la suposición de linealidad
del modelo. En efecto, los modelos de caja negra ejemplificados (ARX y ARMAX) son lineales
y asumen que el fenómeno que modelan posee caracterı́sticas lineales o al menos, se puede
garantizar su linealidad dentro de un entorno de trabajo. La respuesta predictiva del modelo
de caja negra dejará de ser precisa fuera de ese entorno, mostrará grandes diferencias con el
fenómeno o divergirá; dependiendo de el sistema fı́sico bajo estudio. Existen modelos de caja
negra no lineales entre los que se destacan las redes neuronales, Wavelets y Kernel Estimators
[42] que no serán abordados en el presente trabajo.

Amplificadores de Ruido y Osciladores Auto-sostenidos


Si bien el carácter no lineal de la mayorı́a de los fluidos en estudio está relacionado con
las no-linealidades presentes en las ecuaciones de Navier-Stokes, esto no afecta con la misma
intensidad a todos los fenómenos. En efecto, la naturaleza inherente del flujo estudiado define dos
clasificaciones básicas con grandes diferencias en las no-linealidades presentes: los amplificadores
de ruido y los osciladores auto-sostenidos.
Los amplificadores de ruido son altamente sensibles a las perturbaciones que son trasladadas
fuertemente al resto del sistema. En estas experiencias, la modelización de las fuentes de ruido e
incertezas resulta fundamental para capturar la dinámica del proceso y poder predecir el estado
futuro del sistema. Se puede reconocer sistemas amplificadores de ruido en varias aplicaciones
como la separación de flujos de superficies planas, separación de la capa lı́mite o problemas como
el salto por escalón.
Algunos flujos de naturaleza oscilatoria, por otro lado, presentan inestabilidades globales
que sostienen sus fluctuaciones y los vuelven poco sensibles a perturbaciones externas. En estos
contextos, el modelado de las perturbaciones no resulta tan importante como la captura de
la dinámica de las inestabilidades propias. En el proceso de suprimir dichas inestabilidades y
amortiguar el proceso oscilatorio se refuerzan las caracterı́sticas no-lineales del sistema.

Control de Sistemas No-Lineales Mediante Modelos Lineales


Para captar la dinámica de los fenómenos en sistemas fuertemente no-lineales como los
osciladores auto-sostenidos, la elección más natural es el uso de modelos no-lineales. Sin embargo,
las dificultades computacionales y los problemas para relacionarlos con la fı́sica del sistema suelen
reducir sensiblemente los beneficios de este esquema. En [31] se encuentra una discusión sobre
distintos acercamientos al control de flujos no-lineales con sistemas de control lineales. En el
caso particular del control de la estela de un cilindro, se proponen estrategias basadas en redes
neuronales [16]. También es posible el uso de otras estrategias como algoritmos de identificación
adaptativos o la estabilización del flujo de forma previa a la identificación del sistema [11].

Capı́tulo 2.3. Control y Modelos de Fluidodinámica 29


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

En cualquiera de los casos, es importante remarcar que la construcción de un modelo simple


que permita un control efectivo y el uso de leyes de feedback es más importante que la precisión
y la exactitud con que describen el fenómeno [31].
En ese sentido, la posibilidad de utilizar simples modelos lineales de caja negra como ARX
y ARMAX resulta por demás atractiva. Es posible encontrar esfuerzos en estudios de teorı́a de
control que utilizan ARMAX como modelo del sistema [30]. Aunque esta elección entregarı́a
un sistema más robusto frente a la aparición de ruidos, el empleo de control mediante ARX fue
ampliamente utilizado [4, 35, 36, 31] debido a la mayor simpleza y buenos resultados conseguidos.

2.3.4. Avances en Aplicaciones de Control en el Dominio de la


Fluidodinámica
En la actualidad, los mayores esfuerzos de investigación están dirigidos al control reactivo
por las perspectivas a futuro que presenta su flexibilidad. Esto no significa que las técnicas de
control pasiva o activa predeterminada carezcan de utilidad. Al contrario, las estrategias de
control pasivas suelen tener una gran aceptación para aplicaciones reales debido a su bajo costo
de diseño, construcción y mantenimiento.
En dispositivos de control pasivo, la acción es permanente y no se encuentra preparada
para el ajuste dinámico de los parámetros de control durante la experiencia debido a su fuerte
vinculación con la estructura original del experimento. Esta metodologı́a puede ser encontrada
en la colocación de generadores de vórtices [41, 27, 20], placas de separación a lo largo de la lı́nea
central de la estela de un cilindro [54, 55] y cilindros de control de tamaño menor al cilindro
controlado [9].
Respecto del control predeterminado, es sabido que la mayor parte del trabajo experi-
mental de control de fluidos fue realizado con este esquema de lazo abierto [17]. El monitoreo
de estos estudios frente a variaciones en los parámetros de actuación permitió obtener un buen
nivel de conocimiento sobre las dinámicas de los distintos fenómenos antes de emprender es-
tudios a lazo cerrado. Ejemplos tı́picos de actuadores involucrados en este tipo de control son
los j ets pulsados sintéticos [27, 38], dispositivos mecánicos ajustables, cilindros rotantes [66] o
actuadores de plasma [18, 4, 46, 34, 56]. Es importante destacar que estas experiencias de control
pueden ser adaptadas y utilizar algoritmos de lazo cerrado gracias a las conclusiones obtenidas
durante su instrumentación a lazo abierto.
En contraposición al control predeterminado, el uso de control reactivo deberı́a implicar
menores cantidades de energı́a empleada. Más aún, deberı́a permitir su aplicación en un amplio
entorno de operaciones, dado que el controlador adapta su respuesta en pos de conseguir un
objetivo prefijado. Tanto los algoritmos de feedforward como los de feedback deben vincular los
valores de la salida medida en los sensores con la definición de entradas para el actuador.
Se conocen trabajos a lazo cerrado con distintas técnicas de actuación y algoritmos de control.
Se tiene referencias sobre actuaciones de succión/soplado para contrarrestar la separación del
flujo sobre una superficie plana [31] (ARX y control optimal lineal), transpiración normal de
pared (mediante succión/soplado) para cancelar la interacción con vórtices incidentes [39] (ley
de control lineal sobre un arreglo de sensores), inyección de cantidad de movimiento para reducir
la separación de la capa lı́mite en una superficie plana [30] (ARMAX y control LQG) y controlar
las fluctuaciones de presión en una cavidad de tonos mediante el movimiento mecánico de sus
bordes [35, 36] (ARX y control GPC). Se conocen además, escenarios de control aplicados a
la experiencia prototipo de cilindros. En esta lı́nea se han utilizado técnicas como inyección de
sonido en las paredes de un cilindro para cancelar el desprendimiento de vórtices mediante el
sensado del flujo de masa [32] (amplificación y corrimiento de fase sobre medición en sensor) y
actuadores piezoeléctricos sobre cilindros flexibles [71] (control PID).

Capı́tulo 2.3. Control y Modelos de Fluidodinámica 30


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 2.3. Control y Modelos de Fluidodinámica 31


2.4 Trabajo Interdisciplinario y Aspectos
Computacionales

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

a la discretización como una necesidad de la rama de control dentro de la fluidodinámica. El


factor más importante en este sentido está dado por el empleo de control reactivo y la fuerte
necesidad de utilizar computadoras o microcontroladores para definir sus bucles de control.
Estos dispositivos no admiten el manejo de magnitudes continuas sino que requieren algún tipo
de conversión analógico-digital de las señales de entrada y salida.
En este contexto, el desarrollo de los distintos esquemas de control de fluidos requiere la
discretización de las ecuaciones de Navier-Stokes, en tiempo continuo, consideradas básicas para
el estudio de la fluidodinámica [31]. Como alternativa a la discretización de ecuaciones, es posible
optar por modelos de caja negra basados en muestras del proceso bajo estudio que establecen
de forma natural el entorno de trabajo digital para algoritmos de control [31].

2.4.2. Tiempos de Procesamiento


Es importante destacar que muchas de las experiencias sobre las que fueron ideadas las
distintas estrategias que propone la teorı́a de control poseen tiempos caracterı́sticos elevados y
una cantidad reducida de puntos de observación. Esto se observa claramente en las experiencias
que demuestran la efectividad del controlador GPC [15] donde el tiempo de muestreo es 1s con
tiempos de respuesta de 160 muestras. Si bien se verificó la efectividad de las estrategias de
control y de los sistemas implementados bajo dichos entornos, existen ordenes de magnitud de
diferencia respecto de los fenómenos usuales de fluidodinámica. Trabajos recientes de control de
turbulencias muestran perı́odos de 0,67s para el fenómeno caracterı́stico de la experiencia, en
este caso el desprendimiento de vórtices en un cilindro [18]. Otra implementación de laboratorio,
que implica velocidades de muestreo de menor perı́odo para captar la dinámica del sistema
refiere perı́odos caracterı́sticos de 0,098s con frecuencias de muestreo de 1Khz para obtener un
controlador a lazo cerrado del tipo PID para la reducción del efecto de arrastre sobre un cuerpo
romo [6].
Estas caracterı́sticas limitan la cantidad de información que puede ser procesada en tiempo
real para garantizar que el controlador actúe dentro de los lapsos de tiempo previstos.
Varios investigadores han sugerido que hasta que se observen mejoras en las condiciones de
cómputo y la relación con el costo asociado, no serı́a factible el uso de sistemas de control con
tales caracterı́sticas [22]. En este sentido, el avance en el poder de cómputo obtenido durante los
últimos años tanto en supercomputadoras como en equipos convencionales alcanzó capacidades
que permiten pensar procesamiento de información de fluidos en tiempo real. Las mejoras en
velocidad de procesamiento, espacios de almacenamiento y capacidades de concurrencia fueron
capitalizadas en mejores herramientas para simular y tratar casos no de flujos no estacionarios.
De todas formas, esta expansión de horizontes aún no permite resolver el conjunto de aplicaciones
que las distintas ramas de ingenierı́a requieren [17].

Capı́tulo 2.4. Trabajo Interdisciplinario y Aspectos Computacionales 33


2.5 Problemática a Resolver

El presente trabajo centra su análisis en el estudio de un sistema de control lineal a lazo


cerrado sobre sistemas de fluidodinámica no lineales. Esto plantea avances en el área de control
de fluidos debido a la simplicidad de los modelos lineales frente a los no lineales y la falta de
resultados positivos a la fecha sobre su uso en sistemas netamente no lineales. Aunque se tiene
referencia de trabajos similares, se entiende que la experiencias sobre las cuales se desarrollaron
poseen no-linealidades de carácter débil por tratarse de sistemas amplificadores de ruido. En
contraposición, se escoge como fenómeno fı́sico a controlar un sistema de oscilaciones auto-
sostenido, que presenta marcadas no-linealidades.
A su vez, se estudia una metodologı́a de sensado que relaje las condiciones necesarias para
poder realizar la experiencia fuera de laboratorios. En tal sentido, se opta por plantear un
controlador basado en la medición de propiedades sobre imágenes de la experiencia suponiendo
la inyección de humo u otro trazador pasivo aguas arriba.
Como sistema fı́sico bajo control se selecciona el escurrimiento de un cilindro inmerso en
un flujo uniforme con el objetivo de controlar su estela. El forzado del flujo es producido por
actuadores de plasma colocados en la superficie del cilindro. A fines prácticos, se utilizan veloci-
dades del fluido tales que la estela presente desprendimiento de vórtices y un carácter netamente
laminar como se verá en los siguientes capı́tulos.
Se utiliza un modelo ARX para expresar la dinámica de la estela del cilindro a través de
un vector de estado cuyas coordenadas son la intensidad del escalar pasivo observado en ciertos
puntos de la imagen y la intensidad de actuación. El controlador elegido posee un esquema
GPC para minimizar las fluctuaciones de la estela dentro de un horizonte de predicción. Como
paso de verificación previo a la implementación real de la experiencia, se simula numéricamente
el fenómeno, garantizando la ausencia de interferencias con señales externas y otras formas
de ruido. Los resultados del controlador son integrados dentro del código de simulación para
sincronizar el momento de actuación con los pasos de la simulación propiamente dicha.

34
2.6 Conclusiones

Durante el presente capı́tulo se introdujeron los conceptos fundamentales necesarios para el


trabajo en sistemas de control de fluidos. Se realizó una breve reseña sobre el desarrollo histórico
de la Teorı́a de Control y el Control de Fluidos con el fin de entender el camino transitado hasta
alcanzar los niveles de complejidad actuales.
Se clasificaron las distintas estrategias de control en cuanto a bucles de control y actuadores
utilizados ejemplificando en cada caso con distintas experiencias del área del control de fluidos.
En ese escenario se remarcó la importancia de los actuadores reactivos y en especial de lazo
cerrado (o feedback ) debido a su flexibilidad frente a cambios en las condiciones del sistema. A
su vez, se detallaron las distintas estrategias de modelización para fenómenos de fluidodinámica
focalizando en las de caja negra. En ese tipo de modelos resulta indispensable la identificación
de sistemas en base a fases de entrenamiento.
Por último, se expuso la problemática a tratar, siendo fundamental la participación de un
equipo interdisciplinario. En ese contexto se detallaron los avances conocidos a la fecha y la
importancia de obtener un control a lazo cerrado, lineal y basado en imágenes. A tal fin, se
estableció la experiencia de control sobre la estela de un cilindro como caso prototipo y se
definieron los detalles generales del experimento numérico.

35
Parte 3

Solución y Diseño de la Experiencia

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.

3.2.1. Estela de un Cilindro


Se distinguen distintas regiones del flujo sobre el cilindro donde se originan fenómenos aso-
ciados con la perturbación (Fig. 3.2.1). Se estudiará únicamente su estela, donde el fenómeno de
desprendimiento de vórtices y la turbulencia asociada tienen un carácter oscilatorio marcado.

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.

3.2.1.1. Desprendimiento de Vórtices


El fenómeno de desprendimiento de vórtices resulta principalmente de la desaceleración del
fluido más cercano a la superficie del cuerpo y su imposibilidad de mantener la velocidad poten-
cial del flujo más alejado (Fig. 3.2.2). Dependiendo del Re de la experiencia, es posible observar

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.

Capı́tulo 3.2. Sistema Fı́sico Bajo Estudio 39


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

3.2.1.2. Regı́menes de Escurrimiento


Los distintos regı́menes que pueden tener lugar en el flujo alrededor de un cilindro se clasifican
en función del número de Reynolds [69]. A medida que éste aumenta, el régimen alterna entre
los modos laminar permanente (5 < Re < 49), desprendimiento laminar de vórtices (49 < Re <
200), transición de las capas de corte (200 < Re < 3 · 105 ), desprendimientos asimétricos y
simétricos (3 · 105 < Re). La transición entre los distintos regı́menes no es abrupta y los efectos
de las regiones vecinas pueden estar presentes si se utilizan rangos cercanos.
Como se verá en la sección 3.3, el presente estudio se centra en valores de 219 < Re < 282
y por lo tanto en la transición de las capas de corte. Este régimen se caracteriza por tener
una estela del flujo turbulenta aunque en la zona de separación se mantiene el flujo laminar.
Aún fuera de la región de desprendimiento laminar de vórtices, se mantienen sus caracterı́sticas
variando gradualmente hacia una estela completamente turbulenta a medida que aumenta Re.
Como agregado, en las capas de corte comienzan a desarrollarse estructuras tridimencionales
(3D) como consecuencia de la complejidad del escurrimiento. Sin embargo, se decide estudiar
los efectos 2D del fenómeno ya que está demostrado que frente a la actuación sincronizada sobre
el cilindro se mantienen las caracterı́sticas regulares bidimensionales (2D) del fenómeno hasta
valores Re ≈ 450 [19].

3.2.2. Actuación sobre el Cilindro


Existen una gran cantidad de estudios de control activo sobre el cilindro con el objetivo de
estabilizar su estela. A continuación se describe el modelo de actuación más usual que consiste
en forzar la rotación del cilindro. En contraposición, se presenta el esquema de actuación por
inyección de plasma, de gran aceptación en los últimos años debido a ciertas ventajas experi-
mentales.

3.2.2.1. Actuadores por Rotación


Se trata de uno de los mecanismos de control de cilindros más estudiados. Consiste en
forzar la rotación del cilindro sobre su propio eje. Esta rotación puede ser completa o a modo de
oscilaciones temporales siendo este esquema el más utilizado. Los movimientos rotatorios pueden
variar en frecuencia o en amplitud provocando distintos efectos sobre la estela resultante. El
mecanismo de rotación oscilatoria provoca un retardo temporal en la separación que disminuye
el efecto de arrastre [60].
En [66] se estudia el retardo en la aparición de vórtices bajo un sistema de control oscilatorio
concluyendo que las oscilaciones forzadas participan en la generación de vórtices adicionales
que interactúan con los naturales. Esta contribución puede resultar constructiva o destructiva
a la generación global de vórtices dependiendo de la diferencia de fase entre las oscilaciones y
el desprendimiento natural del sistema. Se demuestra entonces que el efecto de las oscilaciones
puede amplificar o reducir las fluctuaciones en la estela del cilindro dependiendo de la frecuencia
y amplitud de oscilación. La Fig. 3.2.4 y 3.2.5 dan ejemplo del efecto estabilizador con la elección
adecuada de parámetros.

Capı́tulo 3.2. Sistema Fı́sico Bajo Estudio 41


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).

3.2.2.2. Actuadores de Plasma


Dentro de las técnicas de actuación activas para el control de flujos se puede clasificar a
la actuación por plasma (medio gaseoso ionizado) frı́os como sistema emergente y en plena
expansión [56, 52, 62]. El mecanismo fundamental de estos actuadores consiste en forzar la
migración de cargas mediante la disposición de electrodos que provocan la ionización del gas
circundante. La inyección de cantidad de movimiento junto a las paredes del cuerpo bajo estudio
puede ser utilizada para reducir el arrastre por fricción de la superficie y retardar la separación
de la capa lı́mite.
En la Fig. 3.2.6 se puede observar una posible configuración de actuadores de plasma sobre
un cilindro. Las Fig. 3.2.7 muestra la misma configuración de actuadores en funcionamiento
sobre una experiencia de laboratorio y la comparación con el escenario no actuado [40].

Capı́tulo 3.2. Sistema Fı́sico Bajo Estudio 42


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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].

3.2.3. Aplicaciones Particulares de Control sobre el Cilindro


Se pueden identificar básicamente dos ramas de la industria donde la aplicación de control
sobre estructuras comparables al cilindro cobra importancia: vehı́culos (industria del automóvil,

Capı́tulo 3.2. Sistema Fı́sico Bajo Estudio 43


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

aeroespacial y náutica) y balı́stica.


En el ámbito del transporte son conocidos los grandes esfuerzos de investigación sobre las
condiciones aerodinámicas (o hidrodinámicas) de las superficies en contacto con el fluido. Estos
casos de control pasivo, donde se plantean estructuras con poca resistencia al fluido o superfi-
cies que generan poca turbulencia en su estela, fueron indispensables para reducir el gasto de
combustible y aumentar las velocidades de los automóviles, aeronaves y navı́os.
Sin embargo, existen casos donde se deben ubicar ciertas estructuras por sobre el fuselaje de
la aeronave para que puedan operar correctamente (emisores y receptores de señales, cámaras
de video, sensores infrarrojos, estructuras portantes, etc.). Estas superficies excedentes suelen
poseer una longitud en dirección del flujo similar a su longitud en dirección perpendicular al flujo.
Esa relación de medidas les otorga un arrastre por fricción despreciable respecto al arrastre por
presión que ofrece su forma. Estos elementos son conocidos como cuerpos romos o bluff bodies.
A modo de ejemplo en automóviles, se puede mencionar a los espejos retrovisores que re-
sultan imprescindibles debido a su utilidad. Por otro lado, en los nuevos modelos de aviones
no tripulados (unmanned aerial vehicles o UAVs) se pueden encontrar varias estructuras cla-
ves como las cámaras infrarrojas y los emisores de señales (Fig. 3.2.8) que resultan de extrema
importancia para el manejo de la aeronave.

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.

Capı́tulo 3.2. Sistema Fı́sico Bajo Estudio 44


3.3 Diseño y Objetivos de la Experiencia

Se considera el flujo alrededor de un cilindro con el objetivo de estabilizar su estela redu-


ciendo el desprendimiento de vórtices y la energı́a cinética de las fluctuaciones. Como fuera
explicado, esta configuración posee principal importancia por su carácter de experiencia pro-
totipo ampliamente estudiada. Respecto de intentos de control sobre la estela del cilindro, es
posible encontrar una revisión sobre distintas experiencias con feedback en [13].
Se conocen casos donde, aún bajo importantes interacciones no-lineales entre los modos
globales y la entrada de control, se logra la supresión de oscilaciones en las señales de los
sensores utilizados para la experiencia [25, 57]. Si bien no existe una relación directa entre las
oscilaciones en los sensores y la energı́a cinética de las fluctuaciones del flujo en su totalidad,
se puede afirmar la posibilidad de utilizar modelos lineales para controlar ciertas cantidades de
forma local. Con estas consideraciones se puede formular el objetivo de control centrado en la
manipulación de las variables en torno a ciertos puntos en lugar de pretender un control sobre la
dinámica total de los modos oscilatorios del sistema. Una forma de conseguir esto es observando
las lı́neas de emisión del flujo, que se denotan mediante la acumulación de trazador pasivo, y
restringiendo su dinámica a cierto patrón en la estela del objeto.
En el caso particular del escurrimiento del cilindro, se conoce que la estabilización produce
una estela más angosta y larga. Entonces, al forzar la estela a que cumpla este patrón, se
espera que la energı́a de las fluctuaciones disminuya. Con ese fin, se disponen varios sensores
formando un “túnel” que demarca los lı́mites pretendidos para las lı́neas de emisión aguas abajo
del cilindro.

3.3.1. Configuración y Dimensiones


La experiencia consta de un flujo entrante uniforme, de velocidad constante, que atraviesa
un cilindro centrado respecto del eje perpendicular al flujo. El cilindro será modelado con un
disco unitario en 2D. Se establece el centro del sistema de coordenadas cartesianas en el centro
del disco. El eje de abscisas se define del mismo sentido que el flujo entrante (Fig. 3.3.1). La si-
mulación numérica es planteada con magnitudes adimensionales para posibilitar su escalamiento
a las dimensiones reales en el caso de implementar la experiencia en un laboratorio. La correcta
extensión a un escenario real requiere entonces que se respeten las proporciones y relaciones
adimensionales prefijadas (como el número de Reynolds).

45
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Figura 3.3.1: Estructura y dimensiones de la experiencia. El dominio de simulación es medido proporcional al


tamaño del disco que se considera unitario. Se fijan los lı́mites de la simulación en 27.5 x 25 diámetros con el disco
centrado verticalmente a 7.5 diámetros de la entrada del flujo.

La velocidad constante de entrada se define como unitaria y se deja variable al flujo de


salida para que fluctúe dependiendo de los resultados de simulación de las celdas más cercanas.
La presión de referencia se decide colocar en el borde de salida y con valor nulo. Respecto de
las condiciones de borde restantes, los laterales plantean simetrı́a mediante la variación nula
de presión y velocidad respecto de la componente normal a los mismos. De forma análoga,
la condición de flujo entrante (inlet) posee variación nula de la velocidad y presión respecto
de la normal. Por otro lado, la condición de flujo saliente (outlet) define como nula sólo a la
variación de la velocidad normal. Cabe aclarar que al aplicar una variación nula respecto de
la normal a cierto borde, se pretende modelar una extensión infinita de la superficie en dicha
dirección. En el caso del flujo saliente, una variación nula de la velocidad permite repetir el valor
simulado para las celdas interiores en las celdas exteriores (fuera de los lı́mites de la simulación).
Las condiciones de borde donde se fija el valor de la magnitud, como en el caso del inlet son
conocidas como Condiciones de Dirchlet. Por otro lado, cuando se fija el valor de la variación (es
decir, del gradiente), como el caso del outlet, se trata de una Condición de Neumann. El detalle
de las condiciones de borde y las dimensiones del problema son indicadas en la Fig. 3.3.2.

Capı́tulo 3.3. Diseño y Objetivos de la Experiencia 46


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

Luego de establecer los parámetros generales de la experiencia, es posible estimar la frecuencia


de desprendimiento de vórtices mediante una aproximación del número de Strouhal. Se conoce la
relación entre Re y St mediante la tabulación de distintas experiencias y la elaboración de curvas
3.3.3. Esta relación presenta discontinuidades marcadas y, por lo tanto, no puede encontrarse
una forma funcional que la sintetice a menos que se la defina por tramos. Sin embargo, en
regiones de trabajo acotadas es posible aproximar el número de Strouhal mediante una función
del Re. Para el Re elegido, se puede aproximar un valor de St = 0,1814 gracias a la relación
matemática que resulta válida en entornos de Re ≈ 250:
   
19,7 19,7
St = 0,198 1 − = 0,198 1 −
Re 235
≈ 0,1814

Capı́tulo 3.3. Diseño y Objetivos de la Experiencia 47


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Figura 3.3.3: Evolución del número de Strouhal en función del número de Reynolds (Williamson, 1996) [69].

3.3.2. Sensores y Actuadores


Un filamento de trazador pasivo de concentración unitaria es inyectado en la entrada del
fluido. Este trazador modela la inyección de humo que difunde a través del escurrimiento permi-
tiendo el sensado de su concentración en la estela del cilindro. A fines prácticos de la simulación,
se colocarán puntas de medición (o probes) dentro de la aplicación de simulación para obtener la
concentración en ciertos puntos. En un escenario real, se pueden sensar estos valores mediante
la captura de imágenes en escala de grises y la comparación de las intensidades en dichos puntos
con la del punto de inyección (concentración patrón unitaria).
Se dispone de 2 lı́neas de sensores, simétricas respecto del eje X de la simulación, con 4
sensores cada una para capturar los valores de concentración del escalar difundido aguas abajo
del cilindro (Fig. 3.3.2). Las posiciones elegidas para los sensores pretenden demarcar un “túnel”
a través del cual se debe canalizar el escalar inyectado en un caso de control óptimo. En el caso
no estabilizado, los sensores captarán el desplazamiento de los vórtices y las fluctuaciones de
velocidad por la turbulencia de la estela. Es importante remarcar que la elección de la posición
de cada sensor y la cantidad de sensores utilizados resulta del ajuste luego de ejecutar varias
experiencias de control. El algoritmo y parámetros de configuración propuestos en las siguientes
secciones demostraron ser altamente sensibles a la configuración de la experiencia. De todas
formas, se destaca que el concepto de “túnel” y sensado por visión propuestos resultan genéricos
y adaptables a una gran variedad de experiencias.
Se definen entonces las variables yi (k) con i = 1.,8 para el valor medido en cada sensor en
el paso de tiempo k suponiendo un muestreo discreto. Dado que el trazador introducido posee
concentración unitaria en el punto de inyección, se espera que las variables yi posean valores
entre 0 y 1. Asimismo, se define el vector genérico y(k) = (y1 (k) . . . ym (k))T ∈ Rm con m = 8

Capı́tulo 3.3. Diseño y Objetivos de la Experiencia 48


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

3.3.3. Sı́ntesis y Objetivos de la Experiencia


A modo de sı́ntesis se resumen los parámetros importantes del sistema fı́sico a simular. En
cada caso se incluye su valor y una reseña de la variable utilizada, en caso de existir (Tabla
3.3.1):

Propiedad Variable Valor (adimensional)


Reynolds Re 235
Strouhal estimado St 0,1814
Diámetro Cilindro D 1
Viscosidad Fluido ν 235−1
Vel. Flujo Entrada U 1 Cte. (Cond. Dirichlet)
Vel. Flujo Salida Gradiente Nulo (Cond. Neumann)
Entradas y(k) Concent. de Escalar en el tiempo k
Salidas u(k) Amplitud de actuación en el tiempo k

Tabla 3.3.1: Sı́ntesis de variables utilizadas en la experiencia de simulación.

En las siguientes secciones se define el algoritmo de identificación del sistema, planteando


como vector de estado del sistema al conjunto de las variables y(k) y u(k) para cada paso de

Capı́tulo 3.3. Diseño y Objetivos de la Experiencia 49


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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”.

El sistema fı́sico elegido como escenario de verificación plantea dificultades importantes en


el terreno de la identificación del sistema y la definición del controlador. Se trata de un sistema
con oscilaciones auto-sostenidas que posee un carácter no-lineal marcado. Esta caracterı́stica
es reforzada por el número de Reynolds elegido dentro de una zona de transición, en la cual
se presentan fenómenos mixtos de desprendimiento laminar de vórtices y turbulencia. En ese
contexto, se espera que las no-linealidades sean aún más notorias.
Por otro lado, el esquema de sensado y control elegidos plantean ciertas ventajas sobre otros
trabajos de control para escenarios similares. En primer lugar, el empleo de trazadores pasivos
como elemento de medición en lugar de otras variables fı́sicas (presión, campo de velocidades,
etc) desvı́a el foco de la dinámica instantánea a una medida más general del sistema, donde
las no-linealidades no resultan tan evidentes. En segundo lugar, se relaja el objetivo de control
al proponer el desvı́o de los trazadores dentro de un “túnel” que se conoce como una solución
factible para el problema en estudio. Esto acota los grados de libertad de la experiencia dentro
de ciertos lı́mites que admiten una solución de control conocida.
Por último, es importante recalcar que aunque se demuestra la efectividad del algoritmo de
control en el caso de 8 variables de salida simultaneas y 1 variable de entrada, su definición es
genérica y como consecuencia se lo puede clasificar como un sistema de control MIMO.

Capı́tulo 3.3. Diseño y Objetivos de la Experiencia 50


3.4 Algoritmo de Identificación del Sistema

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.

Figura 3.4.1: Esquema de bloques de la fase de 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

muestras de entrenamiento utilizando p + 1 ≤ k ≤ N . Se asume el inicio del muestreo en k = 1


teniendo disponibles los valores de y(1), . . . , y(N ), u(1) . . . , u(N ):
 −1
N N
LS 1 X 1 X
θ̂N = Ξ(k)ΞT (k) Ξ(k)y(k). (3.4.3)
N −p N −p
k=p+1 k=p+1

Dado que la matriz N T


P
k=p+1 Ξ(k)Ξ (k) puede resultar mal condicionada, es decir que está cer-
ca de ser no inversible debido a su valor o a la precisión numérica, se considera un método más
efectivo para estimar los parámetros [42]. Se define entonces

ΦT := (Ξ(p + 1) . . . Ξ(N )) ∈ Rd×(N −p)m ,


YT := (y T (p + 1) . . . y T (N )) ∈ R1×(N −p)m .

Finalmente, la estimación de θ se obtiene de una descomposición QR de la matriz [ΦY ] ∈


R(N −p)m×(d+1) en la cual las primeras d columnas corresponden a las columnas de Φ y la última
columna es el vector Y .
Con estas definiciones, el problema consiste en obtener un θ que minimice kY − Φθk2 . Se
considera una descomposición QR dada por [ΦY ] = QR, con Q ortonormal de (N − p)m × (N −
p)m y R triangular superior de (N − p)m × (d + 1) tal que
 
R1 R2
R =  0 R3 
0 0

siendo R1 una matriz d × d triangular superior, R2 un vector d × 1 y R3 un escalar. Es posible


demostrar que la minimización de kY − Φθk2 es equivalente a minimizar kQT (Y − Φθ)k2 . Como
QT Φ corresponde a las primeras d columnas de R y QT Y a la última columna de R, se obtiene
que  
  R2
R1 θ
QT Φθ = , QT Y =  R3 
0
0

Capı́tulo 3.4. Algoritmo de Identificación del Sistema 52


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

 
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 )

Tabla 3.4.1: Sı́ntesis de variables utilizadas en la identificación del sistema.

Capı́tulo 3.4. Algoritmo de Identificación del Sistema 53


3.5 Algoritmo de Control a Lazo Cerrado

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.

Figura 3.5.1: Esquema de bloques del algoritmo propuesto.

Siendo s ∈ N el horizonte de predicción, se definen ys ∈ Rsm , us ∈ Rsr and vp ∈ Rp(m+r)


tales que    
y(k) u(k)
ys (k) :=  .. ..
 , us (k) :=  ,
   
. .
y(k + s − 1) u(k + s − 1)
 
y(k − 1)
 .. 

 . 

 y(k − p) 
vp (k − p) := 
 u(k − 1)  .

 
 .. 
 . 
u(k − p)
De acuerdo con la Ec. 3.4.1 se puede obtener una expresión matricial para predecir las salidas
futuras del sistemas [33]
ys (k) = T us (k) + Ψvp (k − p) (3.5.1)
donde T es una matriz de Toeplitz definida según
 
β0
 β (1) β0 
 0 
T :=  β0(2) β0
(1)
β0 (3.5.2)
 

 
 ... ... ... ... ... 
(s−1) (1)
β0 ... ... β0 β0
(1) (s−1)
y los coeficientes β0 , β0 , . . . β0 son conocidos como los parámetros del sistema de Markov
(system Markov parameters) [33]. T y Ψ son matrices de ms×sr y ms×p(m+r) respectivamente
y son obtenidas por una serie de relaciones recursivas según se describe en [33].

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

mientras que la matriz Ψ se define tal que


 
α1 α2 ... αp β1 β2 ... βp
(1) (1) (1) (1) (1) (1)
 α1 α2 ... αp β1 β2 ... βp
 
Ψ :=  (3.5.3)

 ... ... ... ... ... ... ... ...


(s−1) (s−1) (s−1) (s−1)
α1 ... ... αp β1 ... ... βp

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

Luego, se calculan los β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 ,

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 .

El algoritmo de control se basa en un esquema Generalized Predictive Controller (GPC)[14,


15, 35] cuya función objetivo consiste en reducir la concentración de escalar medida en los

Capı́tulo 3.5. Algoritmo de Control a Lazo Cerrado 55


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

J = ysT (k)Qys (k) + λuTs (k)us (k) (3.5.4)

donde Q es una matriz diagonal de sm × sm con bloques Qi tales que

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.

De ellas se determina que

K = −(T T QT + λIsr )−1 T T QΨ (3.5.5)

donde Isr representa la matriz identidad de sr × sr, y entonces

us (k) = −(T T QT + λIsr )−1 T T QΨvp (k − p) (3.5.6)

Capı́tulo 3.5. Algoritmo de Control a Lazo Cerrado 56


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

u(k) = {−(T T QT + λIsr )−1 }r T T QΨvp (k − p). (3.5.7)

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:

Algorithm 1 Algoritmo de control propuesto.


Require: p: orden del modelo, s: horizonte de predicción, λ: costo del actuador
Ensure: Sistema de control bajo estudio
1: Medir los valores de la fase de entrenamiento
2: Calcular el modelo ARX de orden p
3: Definir el controlador con s, λ y el modelo ARX
4: Definir el vp inicial con los valores de y y u hasta el paso k − 1
5: for all paso de tiempo k do
6: Usar Ec. 3.5.7 para obtener u(k)
7: Aplicar la actuación u(k) calculada
8: Medir y(k), la salida resultante para el paso de tiempo k
9: Actualizar vp con y(k) y u(k)
10: end for

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

Tabla 3.5.1: Sı́ntesis de las variables utilizadas en el control a lazo cerrado.

Capı́tulo 3.5. Algoritmo de Control a Lazo Cerrado 57


3.6 Conclusiones

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

El presente capı́tulo establece el mallado a utilizar durante la experiencia numérica, inclu-


yendo tipos y tamaños de celda junto con la relación que poseen con el paso de tiempo de la
simulación. Luego de definir la configuración fı́sica y numérica de la simulación, se obtienen los
primeros resultados que son contrastados con las predicciones realizadas sobre el fenómeno fı́sico
bajo estudio.
Ya verificada la validez del mallado y configuración de la simulación, se implementa un
esquema de comunicación con Code Saturne que permite obtener la información de cada paso
de tiempo y generar una respuesta de actuación acorde. Este mecanismo es puesto a prueba
durante una fase de entrenamiento del sistema donde se fuerza un pulso de actuación y se
recolecta la respuesta en los distintos sensores. Las mediciones son luego relacionadas con un
modelo ARX identificado mediante el algoritmo de mı́nimos cuadrados propuesto en el Capı́tulo
3.4. El modelo identificado es puesto a prueba para asegurar la capacidad de predicción futura
respecto de distintas frecuencias de actuación.
En la fase de control, se utiliza el modelo ARX para calcular la actuación óptima frente
a cada paso de tiempo. Se desarrolla el algoritmo de control definido en el Capı́tulo 3.5 y se
ajustan los parámetros para obtener un control apropiado para la experiencia. Luego, se practica
un análisis sobre la energı́a cinética y las fluctuaciones de la estela del cilindro para verificar
la bondad del controlador desarrollado. Para ello se convierte la estructura de malla irregular
utilizada para la simulación en una grilla cartesiana que permite la manipulación de variables
fı́sicas (como la concentración del escalar o el campo de velocidades) de manera uniforme.
Finalmente, se realiza una serie de simulaciones con condiciones fuera de diseño para verificar
la robustez del sistema de control.
La implementación de los algoritmos de identificación y de control son realizadas en C++
y Matlab. A su vez, se realizaron pruebas de concepto de la identificación del sistema escrito
ı́ntegramente en CUDA C/C++ (lenguaje de GPGPU para tarjetas Nvidia) con el objetivo de
demostrar la versatilidad del esquema propuesto y la posibilidad de realizar un sistema de alta
performance para implementar la experiencia en laboratorios [37].

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].

4.2.1. Tamaño de Celdas


Resulta intuitivo que a menor tamaño de celda, mayor es la precisión de cálculo de la re-
solución DNS. Sin embargo, un elevado número de celdas producto de un mallado fino implica
mayores capacidades de cómputo para cada paso de tiempo a simular. Estos aspectos deben
mantener una relación de equilibrio, disminuyendo el tamaño de celdas en las zonas donde se
requiere mayor precisión y aumentándolo en aquellas donde no es necesario un alto detalle.
La geometrı́a del sistema fue mallada en 2D utilizando el aplicativo GID para generación de
grillas no-estructuradas [43]. Se optó por el empleo de triángulos como tipo de polı́gono para las
celdas (Fig. 4.2.1) ya que permiten un fácil encastre entre elementos sin necesidad de grandes
deformaciones. Si bien los triángulos no son necesariamente equiláteros, se puede tomar como
tamaño caracterı́stico a la longitud de sus lados. La malla se diseña de forma tal de ser fina en la
circunferencia del cilindro (Fig. 4.2.2) y aumentar en grosor con la distancia a su centro. Lejos
del cilindro, se define un tamaño medio uniforme de celdas que se extiende al resto de dominio
(Fig. 4.2.3).

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

Capı́tulo 4.2. Mallado de la Experiencia 62


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Ya generada la malla 2D de triángulos utilizando GID, se adaptan sus nodos a un formato 3D


para ser empleado por Code Saturne. Existen varias alternativas para realizar dicha extensión, en
este caso se opta por agregar una nueva dimensión al conjunto de celdas mediante la proyección
de sus lados. Se extiende entonces cada triángulo a un pentaedro de altura 0,005 para mantener
relación con el orden de magnitud utilizado en las celdas más pequeñas. A tal fin, se realiza
un script de Matlab que interpreta el archivo de salida de GID, extiende cada triángulo de la
malla y genera un nuevo archivo de malla con formato .msh que puede ser consumido por Code
Saturne. El código fuente de dicha rutina puede encontrarse en el Apéndice F.1. En la Fig. 4.2.4
se puede apreciar el agregado de una dimensión ficticia a la malla original en 2D generando un
pentaedro por cada triángulo existente.

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.

4.2.2. Paso de Tiempo


Para garantizar la estabilidad de este mecanismo, la discretización temporal (entre pasos
de tiempo sucesivos) y espacial (al definir los lı́mites de cada celda) deben permitir que el
movimiento de cada partı́cula de fluido sea de una fracción de la celda. De esta forma, se consigue
una propagación suave de los distintos cambios en las magnitudes y se evitan las variaciones
bruscas que provocan errores de cálculo numérico.
Si estas condiciones no se cumplen, el sistema tiende a ser inestable durante la simulación y,
eventualmente, diverge. Esto suele ocurrir en puntos con gran intercambio de fluidos o sectores
del mallado con celdas de tamaño muy dispares. En cualquiera de los casos el flujo simulado no
recorre las celdas de forma gradual y el desacople entre los valores de distintas celdas desestabiliza
las magnitudes diferenciales simuladas que no pueden converger. En el Apéndice B.2 se puede
encontrar un caso de divergencia de la simulación como consecuencia de cambios bruscos en las
dimensiones de las celdas del mallado.
Por otra parte, el estudio matemático detallado de la resolución numérica de ecuaciones
diferenciales en derivadas parciales contempla distintos criterios de convergencia. Uno de los

Capı́tulo 4.2. Mallado de la Experiencia 63


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

más utilizados es la Condición de Courant-Friedrich-Lewy (CFL), a saber:

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

Capı́tulo 4.2. Mallado de la Experiencia 64


4.3 Simulación de la Experiencia

Ya definido el mallado, el paso de tiempo de simulación (∆t = 0,061) y las condiciones de


contorno, se construye un caso de estudio en Code Saturne para obtener las primeras mediciones.

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
...

A continuación se definen las variables fı́sicas aplicables al fluido: la viscosidad dinámica


(viscl0 ), las tres componentes de gravedad (gx , gy y gz ), la densidad (ro0 ), el calor especı́fico,
el valor de referencia de temperatura (t0 ) y de presión (p0 ). Salvo la viscosidad que tiene un
impacto directo en el número de Reynolds, las otras variables fueron anuladas o llevadas a un
valor unitario para simplificar el desarrollo de la experiencia.
...
gx = 0.d0
gy = 0.d0
gz = 0.d0
...
ro0(iphas) = 1.d0
viscl0(iphas) = 1.d0/235.D0
cp0(iphas) = 1.d0
t0(iphas) = 1.d0
p0(iphas) = 0.d0
...

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)

Capı́tulo 4.3. Simulación de la Experiencia 66


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

probesAreas(1) %xStart = 0.0


probesAreas(1) %xEnd = 20.0
probesAreas(1) %yStart = 1.0
probesAreas(1) %yEnd = 1.0
probesAreas(1) %separation = 0.5
probesAreas(2) %xStart = 0.0
probesAreas(2) %yStart = -1.0
probesAreas(2) %xEnd = 20.0
probesAreas(2) %yEnd = -1.0
probesAreas(2) %separation = 0.5

La colección de áreas es recorrida y se almacena las coordenadas de cada sonda en xyzcap,


con coordenada Z nula:
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)

xProbe = probesAreas(iProbeArea) %xStart


do while (((xSeparationProbe.ge.0).and.(xProbe.le.probesAreas(iProbeArea) %xEnd)) &
.or.((xSeparationProbe.lt.0).and.(xProbe.ge.probesAreas(iProbeArea) %xEnd)))

yProbe = probesAreas(iProbeArea) %yStart


do while (((ySeparationProbe.ge.0).and.(yProbe.le.probesAreas(iProbeArea) %yEnd)) &
.or.((ySeparationProbe.lt.0).and.(yProbe.ge.probesAreas(iProbeArea) %yEnd)))

iProbe = iProbe + 1
xyzcap(1,iProbe) = xProbe
xyzcap(2,iProbe) = yProbe
xyzcap(3,iProbe) = 0.00d0

yProbe = yProbe + ySeparationProbe


end do
xProbe = xProbe + xSeparationProbe
end do
end do
ncapt = iProbe

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

!Código de color, Nombre de Capa, Tipo de Lómite en CodeSaturne


!2, entrada, ientre + inyección de escalar
!3, salida, isolib
!4, pared, iparoi
!5, simetria, isymet
!7, actuador, iparoi + inyección de cantidad de movimiento

Capı́tulo 4.3. Simulación de la Experiencia 67


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

!simetria -> isymet


call getfbr(’5’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)

do iphas = 1, nphas
itypfb(ifac,iphas) = isymet
enddo
enddo

La salida requiere configuraciones particulares sobre ciertos tipos de condiciones de borde


(icodcl ) y sus respectivos valores (rcodcl ) para magnitudes en las caras como ser la presión
(ipr ), velocidad en X (iu), Y (iv ) y Z (iw ).
!salida -> isolib
call getfbr(’3’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)
iel = ifabor(ifac)
do iphas = 1, nphas
itypfb(ifac,iphas) = isolib

icodcl(ifac,ipr(iphas)) = 1 !dirichlet condition on pressure -> fixed value


icodcl(ifac,iu(iphas)) = 3 !neumann condition on velocity -> fixed gradient
icodcl(ifac,iv(iphas)) = 3
icodcl(ifac,iw(iphas)) = 3

rcodcl(ifac,ipr(iphas),1) = 0.0d0 !dirichlet value fixed to pressure=0


rcodcl(ifac,iu(iphas),3) = 0.0d0 !neumann value fixed to grad(u,normal) = 0
rcodcl(ifac,iv(iphas),3) = 0.0d0
rcodcl(ifac,iw(iphas),3) = 0.0d0
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

Capı́tulo 4.3. Simulación de la Experiencia 68


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

!actuador -> iparug


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) = 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

Capı́tulo 4.3. Simulación de la Experiencia 69


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.3. Simulación de la Experiencia 70


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.3. Simulación de la Experiencia 71


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Dado que la velocidad de muestreo es equivalente al paso de tiempo de la simulación (∆t =


0,061), resulta más apropiado realizar los gráficos en función de esta magnitud. La Fig. 4.3.5
muestra los valores en cada uno de los sensores en función del paso de tiempo.

Capı́tulo 4.3. Simulación de la Experiencia 72


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

Capı́tulo 4.3. Simulación de la Experiencia 73


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.3. Simulación de la Experiencia 74


4.4 Comunicación con el Sistema de Con-
trol

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.

4.4.1. Lenguajes Utilizados


Se plantea entonces un sistema externo a Code Saturne, escrito en C++, que resuelva el
control de la experiencia mediante la lectura de los sensores y el cálculo de actuación requerida. A
fines prácticos, se utiliza Matlab como utilitario de calculo matricial para resolver los algoritmos
de identificación del sistema y de control por su alto contenido matemático. Cabe aclarar que
el objetivo principal de este esquema es obtener un entorno adecuado para implementar los
algoritmos descritos en los Capı́tulos 3.4 y 3.5 debido a la complejidad matemática que poseen
y a la flexibilidad necesaria para verificar la correctitud de los resultados.
Aunque es conocida la diferencia en velocidad de ejecución entre programas de Matlab y
C++, no se fijan requerimientos de performance particulares por tratarse de la etapa de si-
mulación de la experiencia. De todas formas, se entiende que todo el código escrito en rutinas
de Matlab puede ser incluido en el sistema principal en C++ de una forma adecuada y, más
aún, con la posibilidad de optimizar los tiempos de procesamiento de las secuencias altamente
paralelizables mediante GPGPU. Ese esquema posee grandes ventajas para una implementación
real-time en laboratorio. La Fig. 4.4.1 presenta un esquema simplificado de la relación entre los
distintos sistemas ideados que se detallan en las siguientes secciones.

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).

4.4.2. Interacción entre Módulos


En primer lugar es importante comprender que la amplitud de actuación en la pared del
cilindro se establece mediante las variables upperActuatorValue y lowerActuatorValue que
configuran las condiciones de borde en el archivo usclim.f90 (ver Capı́tulo 4.3.1). Para el
objetivo particular de la experiencia elegida, se asume que ambas variables están sincronizadas
y presentan la misma actuación a cada instante de tiempo pero, de todas formas, el código del
controlador está preparado para soportar variables independientes.
Dado que se desarrolla el controlador en un sistema externo, el problema se resume en
encontrar un mecanismo que detenga la ejecución detallada en usclim.f90 frente a cada paso de
tiempo, notifique su número al sistema externo, espere la respuesta de actuación y modifique los
valores de upperActuatorValue y lowerActuatorValue. La Fig. 4.4.2 ilustra la dependencia
entre el sistema simulador y el controlador mediante un diagrama de actividades simple.

Capı́tulo 4.4. Comunicación con el Sistema de Control 76


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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).

Capı́tulo 4.4. Comunicación con el Sistema de Control 77


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Figura 4.4.3: Diagrama de colaboración de la fase de entrenamiento.

Figura 4.4.4: Diagrama de colaboración de la fase de control.

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

Capı́tulo 4.4. Comunicación con el Sistema de Control 78


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

call system("mkfifo semaphore")


call system("mkfifo act.upper")
call system("mkfifo act.lower")
call system("./controller act.upper.csv act.lower.csv" &
//" probes_Scalar1.dat < semaphore &")
open(unit=103, file="semaphore", action="write")
open(unit=104, file="act.upper", action="read")
open(unit=105, file="act.lower", action="read")

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;
}
}
...

Resulta interesante observar que la implementación de los métodos de espera (waitForS-


tep) y envı́o (send ) que posee la clase SaturneCommunicator se implementan con simples
operaciones de lectura y escritura bloqueantes en los archivos que representan los pipes:

Capı́tulo 4.4. Comunicación con el Sistema de Control 79


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

int SaturneCommunicator::waitForStep(std::istream& semaphore) {


unsigned int semaphoreStepNumber;
semaphore >> semaphoreStepNumber;
if (semaphore.good()) {
return semaphoreStepNumber;
else
return 0;
}

void SaturneCommunicator::send(std::ofstream& actuatorFile, double value) {


std::stringstream converter;
converter << value;

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.

Capı́tulo 4.4. Comunicación con el Sistema de Control 80


4.5 Identificación del Sistema

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.

4.5.1. Entrenamiento del Sistema


Como señal de entrenamiento se escoge un pulso de gran altura y corta duración. Este tipo
de señal es ampliamente utilizada para evaluar la respuesta de sistemas debido a la variedad de
frecuencias que posee. La duración del pulso se establece en 10 pasos de tiempo y la amplitud
en 10. Estos valores demuestran de forma empı́rica que son suficientes para obtener un cambio
significativo en la dinámica de la estela con un efecto estabilizador durante un lapso corto de
tiempo.
La identificación del sistema se realiza con una medición de N = 1090 muestras totales y con
un pulso iniciado en el paso de tiempo 90. Como fuera descrito en el Capı́tulo 3.3, la cantidad
de sensores que define al sistema es de m = 8 mientras que la cantidad de componentes de la
actuación es r = 1. Los resultados pueden observarse en la Fig. 4.5.1.

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

Capı́tulo 4.5. Identificación del Sistema 82


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

gradualmente a medida que el sensor se aleja.


El orden del modelo ARX, p, define la cantidad de muestras para el horizonte de autoregre-
sión y debe ser establecido de forma tal que el modelo capture las relaciones entre los distintos
componentes del vector de estado. En efecto, el valor de p, establece una ventana temporal
donde las mediciones y actuación se vinculan mediante los coeficientes del modelo. Si la ventana
es muy pequeña, el modelo no captura efectos que cierta variable (por ejemplo, la actuación)
causa en otra (por ejemplo, un sensor arbitrario) en casos donde la reacción posee un retardo
mayor al tamaño de ventana. Una ventana muy grande, además de requerir cantidades excesivas
de procesamiento para el cálculo y uso del modelo, puede resultar innecesaria si los efectos de
una variable sobre otra tienen retrasos temporales mucho menores a la ventana. Como agre-
gado se conoce que a mayor p se obtiene un mejor ajuste del modelo frente a la respuesta del
entrenamiento con el costo de aumentar su sensibilidad frente a ruidos.
A fines prácticos se elige un valor de p = 90, levemente mayor al perı́odo natural de la
experiencia. Como se puede observar en el Apéndice C.1, este valor de p asegura un ajuste
promedio del 99,7 % entre los valores reales obtenidos de la fase de entrenamiento y los valores
de predicción que puede realizar el modelo ARX.

4.5.2. Implementación del Algoritmo


El cálculo del modelo escrito en Matlab se dispara desde el sistema controlador en C++
utilizando la interfaz provista por las librerı́as MEX de Matlab. Este comportamiento es encap-
sulado en la clase MatlabExecutor que interactúa con la interfaz MEX transmitiendo datos
y operaciones. Para facilitar su uso, se construye la abstracción Matrix que almacena valores
double en formato matricial. La interfaz de MatlabExecutor incluye operaciones para definir
variables matriciales, obtener su valor o evaluar expresiones matemáticas como se muestra a
continuación:
class MatlabExecutor {
private:
Engine *ep;
//...
public:
MatlabExecutor(/* ... */);
~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);
};

La implementación completa, las clases Matrix y MatlabExecutor , ası́ como su modo de


uso puede encontrarse en el Apéndice F.6.
El caso particular de la identificación del sistema se resuelve evaluando la función lfd arx ,
de Matlab. La función calcula las matrices A y B de orden p del modelo ARX en base a las
mediciones y y u indicadas por el sistema controlador:
function [A B] = lfd_arx(y, u, p)

Se definen las variables na y nb respecto del orden del modelo p y se obtiene m, r , N de


las dimensión de los vectores de muestras para agrupar sus valores en la variable ϕ(k), llamada
phi , según la Ec. 3.4.2:
na = p;
nb = na+1;
[m,N] = size(y);

Capı́tulo 4.5. Identificación del Sistema 83


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

[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

Finalmente, se obtiene R de una descomposición QR sobre la matriz de regresión y las


entradas para estimar el valor de θ̂, llamado th, según la Ec. 3.4.4:
yna = y(:, na+1:end);
Y = reshape(yna, m*(N-na), 1);
R = triu(qr([reg’ Y]));
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);
th = pinv(R1) * R2;

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.

4.5.3. Verificación del Modelo ARX


Para verificar la validez del modelo se utiliza una señal de excitación distinta a la empleada
durante la fase de entrenamiento y se simula su respuesta mediante Code Saturne. Las mediciones
resultantes de concentración de escalar son comparadas con predicciones obtenidas del modelo
ARX. En tal sentido se plantea el uso de la rutina compare de Matlab para predecir los valores
de yi (k) y disponerlos gráficamente juntos a los medidos. La predicción utiliza un horizonte de
s = 90 pasos de tiempo en dos escenarios distintos donde se utiliza como entrada de actuación

Capı́tulo 4.5. Identificación del Sistema 84


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

a la superposición de ciertas señales gaussianas de la forma:


(t−µ)2
g(t) = A · e−( 2·σ 2
)

donde A indica la amplitud, µ la media de la campana y σ su desvı́o estándar. El valor de µ difiere


entre las distintas señales para desplazarlas entre sı́. Se utiliza cierto perı́odo de repetición para
el corrimiento de las señales que permite calcular una frecuencia caracterı́stica de la actuación
resultante.
El primer escenario superpone gaussianas de A = 0,55 y σ = 20 con un desplazamiento entre
1
µ de 70 pasos de tiempo. Esto implica una frecuencia caracterı́stica de = 0,2342 que
70 · 0,061
equivale aproximadamente a un 125 % de la frecuencia natural de la experiencia (0,1884). Esta
diferencia de frecuencias es pequeña y permite lock-in entre la dinámica del desprendimiento
de vórtices y la frecuencia impuesta por el actuador. En esos casos se observa que el sistema
modifica su frecuencia de oscilación debido a la influencia de la señal de excitación y su frecuencia
(Fig. 4.5.2).

Capı́tulo 4.5. Identificación del Sistema 85


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

En el segundo caso se utiliza A = 0,60 y σ = 20 con un desplazamiento entre µ de 45 pasos


1
de tiempo. Esto implica una frecuencia de = 0,3643 equivalente a 193 % de la frecuen-
45 · 0,061
cia original. Se observa un comportamiento satisfactorio del modelo pudiendo reproducir las
frecuencias principales de las oscilaciones de la experiencia. La concordancia de las predicciones
con la respuesta fı́sica resulta evidente en la etapa sin actuación forzada y disminuye al iniciar el
control pero sin observarse diferencias considerables. El sistema resulta estable durante el lapso
de actuación y retorna al estado de equilibrio al finalizar (Fig. 4.5.3).

Capı́tulo 4.5. Identificación del Sistema 86


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Realizando un análisis de frecuencia de la señales simuladas en comparación con las pre-


dicciones, se encuentra una gran similitud en los patrones de frecuencia resultantes. En ambos
casos se analiza el número de Strouhal de la experiencia entendiendo que, por las dimensiones
utilizadas para la simulación, St = f . Las frecuencias caracterı́sticas de la experiencia se mo-
difican levemente durante el perı́odo de control, hecho que es captado por las predicciones del
sistema (Fig. 4.5.4 y 4.5.5).

Capı́tulo 4.5. Identificación del Sistema 87


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.5. Identificación del Sistema 88


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.5. Identificación del Sistema 89


4.6 Sistema de Control a Lazo Cerrado

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.

4.6.1. Implementación del Algoritmo


4.6.1.1. Inicialización
Al entrar en la fase de control, el sistema C++ inicia el estado del subsistema Matlab cal-
culando control state. Esta estructura almacena los parámetros básicos del controlador, p, s,
q y λ, junto con la matriz de control, K, calculada en base al modelo ARX (Ec. 3.5.5). La
implementación incluye una variable limits que permite definir mı́nimo y máximo permitidos
para la actuación.
function [ control_state ] = lfd_control_lagrange_init(y, u, p, lambda, A, B, limits, q)

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

Con estos valores se conforma T según Ec. 3.5.2:


T=zeros(m*s,r*s);
T_column =zeros(m*s,r);

T_column(1:m,:)=beta00;
for j=2:s;
T_column((j-1)*m+1:j*m,:)=beta0(:,:,j-1);
end;

for column = 1:s


T(m*(column-1)+1:m*s, r*(column-1)+1:r*column) = T_column(1:(m*s - (column-1)*m),:);
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

qué permiten definir Ψ, llamada psi , según la Ec. 3.5.3:


psi(1:m,:) = [reshape(a, m, m*p) reshape(b(:,:,2:end), m, r*p)];
for j=2:s
psi((j-1)*m+1:j*m,:) = [reshape(alpha(:,:,j-1,:), m, m*p) reshape(beta(:,:,j-1,:), m, r*p)];
end

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 91


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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;

4.6.1.2. Iteración de Control


Ya inicializado el estado del control, se ingresan los valores y(k) medidos en los sensores y
el u(k) utilizado en un paso de tiempo para calcular u(k + 1), la actuación del siguiente paso.
La función lfd control lagrange recibe dichos valores y retorna control state modificado
incluyendo la actuación calculada:
function control_state = lfd_control_lagrange(control_state, y, u)

En primer lugar, se define el paso de tiempo k sobre el cual se realizará el cálculo y se


recuperan las variables de la estructura del estado para facilitar su uso:
k = size(y, 2) + 1;
limits = control_state.limits;
p = control_state.p;
m = control_state.m;
r = control_state.r;
K_r = control_state.K_r;

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;

u_k = K_r * vp;

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

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 92


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Parámetro Variable Valor


Orden del Modelo p 90
Horizonte de Predicción s 270
Paso de Tiempo Simulación ∆t 0.061
Peso de Sensores Sup. q1 , q2 , q3 , q4 1,4, 1,4, 1,4, 1,4
Peso de Sensores Inf. q5 , q6 , q7 , q8 1,4 1,4 1,4 1,4
Costo del Controlador λ 0,4

Tabla 4.6.1: Valores definidos para los distintos parámetros de control del sistema.

4.6.2. Resultados de Control


A fines de verificar la respuesta del algoritmo de control, se ejecuta una nueva simulación en
la cual se activa el controlador luego de acumular las suficientes muestras para calcular y utilizar
la matriz de control. En el sistema C++ se incluye la posibilidad de almacenar y recuperar el
modelo ARX debido a sus altos tiempos de computación respecto de las operaciones de control.
Se emplea entonces el modelo ARX calculado en la fase de entrenamiento, previamente guardado
en archivos de datos Matlab, y se activa el controlador obteniendo una actuación que estabiliza
la estela (Fig. 4.6.1).

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 93


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 94


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

La frecuencia de oscilación de la entrada genera entonces una oscilación en la salida. Es


interesante observar que las oscilaciones caracterı́sticas del fenómeno se mantienen con una
frecuencia similar a la original dentro de la envolvente de menor frecuencia. En la Fig. 4.6.4
se puede observar el espectro de frecuencias de actuación con un componente muy marcado en
torno a frecuencias de 0,05 correspondiente al 26 % de la frecuencia caracterı́sticas del fenómeno
(0,1884). Las Figs. 4.6.5 y 4.6.6 entregan una comparación de la frecuencias de la salida medida
en los sensores 1, 2, 3 y 4 para los casos sin actuación y con actuación. En el segundo caso se

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 95


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

puede observar la aparición de un componente de 0,05 inducido por la actuación, preponderante


sobre las otras frecuencias. La frecuencia caracterı́stica original (Aprox. 0,19) y sus armónicos
(0,38, 0,57, Etc.) de menor amplitud se pueden encontrar en las señales controladas pero con
una importante dispersión en torno a sus valores originales.

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.).

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 96


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.).

Es importante destacar la reducción en la amplitud de los componentes de frecuencia, indi-


cando una disminución del trazador captado por los sensores. Se puede atribuir este resultado al
comportamiento de las lı́neas de misión que se concentran ahora dentro del “túnel” de sensores.
A su vez, esto coincide con el descenso en el valor medio detectado en cada sensor según se puede
observar en la Tabla 4.6.2.

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.

4.6.2.1. Análisis de Energı́a y RMS de las Fluctuaciones en la Estela


Un posible criterio de estabilización de flujos consiste en el cálculo de la energı́a cinética
de la turbulencia (Turbulent Kinetic Energy o TKE) en el estado original y compararlo con la
obtenida durante el ciclo de control. El cálculo de la TKE se basa en el principio de separación
de variables en las partes media y turbulenta de cierta señal [63]. La parte media es constante y
caracteriza el comportamiento estacionario del flujo mientras que la parte turbulenta depende
del tiempo y, por lo tanto, se relaciona a la dinámica del mismo. Con este esquema es posible
describir la velocidad u(t) de una partı́cula según:

u(t) = u + u0 (t)

donde u es la velocidad media y u0 (t) representa la velocidad de perturbaciones o turbulencias


(Fig. 4.6.7). Luego, el cálculo de la energı́a cinética sobre la componente fluctuante de la velocidad
entrega la TKE. En el caso de 2D y sumando los aportes de cada partı́cula serı́a:
1X 0 2 2
T KE(t) = (ux (t) + u0y (t) )
2

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 97


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 98


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 99


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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].

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 100


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

4.6.3. Pruebas de Robustez


Se realizan distintas simulaciones para considerar la validez del algoritmo de control fuera del
escenario de diseño. Se consideran escenarios con ruido pseudo-aleatorio agregado en la entrada
del flujo, la inyección de trazador y las mediciones en los sensores. En todos los casos se realizan
cambios en los códigos de simulación para agregar el ruido calculado como el producto entre
una variable pseudo-aleatoria (con valores entre 0 y 1) y cierto porcentaje sobre la magnitud a
modificar. Luego de aplicados los cambios, se ejecutan las simulaciones y se calcula el TKE para
compararlo con el obtenido en el control original, sin el agregado del ruido.

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.

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 101


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 102


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 103


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 104


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Capı́tulo 4.6. Sistema de Control a Lazo Cerrado 105


4.7 Conclusiones

Durante el presente capı́tulo fue definida la malla utilizada al simular la experiencia en


Code Saturne ası́ como las variables numéricas requeridas. Luego de obtener los resultados de la
simulación, se verifica satisfactoriamente la frecuencia caracterı́stica esperada para la experiencia
(St = 0,1884) y la existencia de desprendimiento de vórtices según el régimen definido para
Re = 235.
Se presenta luego el sistema de control en C++ y el modelo de comunicación con el simulador
escrito en Fortran. El sistema permite el control a lazo abierto que es utilizado con la actuación
de un pulso a modo de fase de entrenamiento. Se procede con la identificación del sistema
sobre los resultados de la fase de entrenamiento para obtener un modelo ARX que represente
al sistema. El modelo ARX es validado mediante simulaciones a control a lazo abierto con
distintas frecuencias de actuación. En todos los casos se obtiene una respuesta aceptable de las
predicciones, sin un ajuste preciso pero respetando las frecuencias y comportamiento cualitativo
verificado en las simulaciones. En el caso de actuaciones con frecuencia de 193 % respecto de la
frecuencia caracterı́stica, se detectaron componente de alta frecuencia en las predicciones que no
son agregados de forma directa por la actuación. Se presume que dichas diferencias provienen
de la saturación de la dinámica del flujo producto de las no-linealidades que el modelo ARX no
contempla.
En la fase de control a lazo cerrado, se utiliza el modelo ARX para calcular la actuación ópti-
ma frente a cada paso de tiempo. Se desarrolla el algoritmo de control y se ajustan los parámetros
para obtener un control apropiado de la experiencia. Los resultados arrojados demuestran que
los patrones de lı́neas de misión se circunscriben al “túnel” de sensores, estabilizando las con-
diciones de la estela del cilindro. El análisis de frecuencia sobre los resultados demuestra que
las frecuencias naturales de la experiencia persisten, atenuadas, luego de activado el controla-
dor. Como agregado, se detecta cierto carácter oscilatorio en la actuación cuya frecuencia es
trasladada a la dinámica del sistema y, por lo tanto, a los valores medidos de escalar.
Se practica entonces un análisis sobre la energı́a cinética y las fluctuaciones de la estela
para verificar la bondad del controlador desarrollado. Para ello la estructura de malla irregular
utilizada para la simulación es convertida en una grilla cartesiana que permite la manipulación
de variables fı́sicas. Esta transformación posibilita el análisis sobre la Energı́a Cinética de la
Turbulencia (TKE) que demuestra una reducción de aproximadamente un 85 % respecto de
la energı́a del caso sin actuación. De la misma forma, se verifica la dispersión de los valores
de velocidad demostrando que el RMS de las fluctuaciones fue reducido. Más aún, fue posible
comprobar de forma cualitativa y cuantitativa que la zona con mayor dispersión se concentra en
torno del eje X, dentro del “túnel” de sensores.
Por último, la robustez del controlador fue puesta a prueba frente al agregado de ruido
pseudo-aleatorio en distintos puntos de la experiencia. En todos los casos, el controlador res-
pondió de forma estable y el TKE resultante se mantuvo dentro de los rangos del escenario de
control original. Asimismo, se aplicó el sistema de control en escenarios con variaciones en el Re
respecto del valor de diseño (Re = 235) consiguiendo buenos resultados en todos los casos. En

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).

Capı́tulo 4.7. Conclusiones 107


Parte 5

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.

El armado de la experiencia numérica, implementación de los algoritmos, construcción del


sistema de control y verificación de los resultados obtenidos implicó un alto contenido de pro-
gramación y habilidades en distintos lenguajes/tecnologı́as.
El uso de Matlab para la implementar los algoritmos de identificación y control permitió re-
ducir la cantidad de operaciones necesarias y reutilizar construcciones existentes ampliamente
probadas. De esta forma, se intentó minimizar la existencia de errores en las primeras implemen-
taciones de los algoritmos que, en una etapa temprana de la experiencia, carecı́an de resultados
previos que permitieran su constrastación.
Como agregado, sus caracterı́sticas de lenguaje utilitario y de scripting, resultaron claves
para operaciones de pre y post-procesamiento del mallado. Entre ellos se encuentra la extensión
del mallado 2D generado con GID a uno 3D en un formato aceptado por el simulador Code
Saturne, la conversión de la malla irregular en una grilla regular para el cómputo del TKE y
RMS de las fluctuaciones junto con diversas actividades de verificación de resultados.
Respecto del sistema de control, la elección de C++ demostró ser acertada pudiendo integrar
las distintas partes bajo un aplicativo robusto. La flexibilidad del lenguaje y gran soporte para la
integración quedó expuesta al comunicar el sistema Fortran del simulador y las implementaciones
de los algoritmos en Matlab. A su vez, su empleo facilitó la inclusión experimental de técnicas

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.

Capı́tulo 5.1. Conclusiones Generales 110


5.2 Trabajos Futuros

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.

Repegado de la Capa Lı́mite (reattachment): Al ocurrir la separación de la capa lı́mite,


las lı́neas de corriente próximas al cuerpo son deflectadas y se forma una estela. Depen-
diendo de las caracterı́sticas de la experiencia, las lı́neas de corriente pueden converger
y adherirse nuevamente formando una burbuja entre el punto de separación y de read-
herencia. Este fenómeno involucra además una zona de recirculación de fluido que queda
confinada al espacio de la burbuja y resulta deseable por la reducción de los efectos nega-
tivos de la estela.

113
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Retardo en Transición (transition delay ): La transición en el régimen del fluido denota la


zona donde el fluido deja de comportarse de forma laminar para adoptar caracterı́sticas
turbulentas. En el primer caso se pueden identificar capas paralelas definidas por las lı́neas
de corriente. El flujo es ordenado y no ocurre mezcla entre las distintas capas. Por el
contrario, en régimen turbulento, el movimiento del fluido es caótico y se intensifica el
intercambio de materia entre las distintas capas. Dependiendo de los fines del control, la
transición temprana puede ser beneficiosa para facilitar cierta mezcla de materia aunque
en la mayorı́a de los casos se opta por retardar su efecto debido al costo energético asociado
con la aparición de un flujo turbulento.

A.2. Evolución Histórica


A lo largo de los años, el control de fluidos ha presentado una evolución constante marcada
por etapas. Los primeros estadı́os son definidos por una fase empı́rica de técnicas e instrumentos
que finaliza con los primeros estudios de L. Prandtl (1975-1953) que en 1904 introduce la teorı́a
de la capa lı́mite e inicia la era cientı́fica del control de fluidos. Durante esta etapa se obtuvieron
avances teóricos importantes en dispositivos de control mediante la aplicación de conceptos
fı́sicos y principios racionales en contraposición a la prueba y error que proliferaba en la era
anterior. Ya comenzada la Segunda Guerra Mundial y durante la carrera armamentista de las
décadas subsiguientes (perı́odo 1940-1970), el ritmo de progreso acelerado fue marcado por las
necesidades militares en los campos de balı́stica, aeroespacial y naval, entre otros. Fue la crisis
energética de 1973 la que da inicio a una nueva era regida en esta oportunidad por el sector civil.
Las necesidades de reducción de costos en procesos industriales o transporte aéreo, terrestre y
naval implicaron grandes inversiones de agencias gubernamentales y privadas en investigación
de control de fluidos. Por último, la década de 1990 da inicio a una nueva etapa que continúa a
la actualidad donde los avances alcanzados tanto en fluidodinámica como en teorı́a de control,
computación, sistemas fı́sicos y electrónicos amplı́an los horizontes del control de fluidos. En este
contexto se incrementa la complejidad de las prácticas y prepondera el uso de control reactivo
por la versatilidad que posee [22].
Además del avance en técnicas especı́ficas, las necesidades económicas suelen dirigir los esfuer-
zos cientı́ficos de este sector de forma directa o indirecta. A modo de ejemplo de las implicancias
económicas que pueden causar los avances en control de fluidos, se estima que una reducción del
1 % en el consumo mundial de combustible aeronáutico por aplicaciones de control implicarı́a
1,25 millones de dólares diarios de ahorro en costos directos (valores estimado al año 2002) y
reducirı́a considerablemente el impacto ambiental de ese tipo de transporte [17].
Aun cuando existe un progreso continuo en la tecnologı́a y métodos aplicados para el control
de fluidos, persisten ciertas diferencias entre teorı́a, resultados simulados y aplicaciones reales.
Esta circunstancia da origen a la frase “El Arte del Control de Fluidos”, refiriéndose a la mezcla
de innovación y experiencia con los que se llevan a cabo muchos de los ensayos que permiten el
progreso de la disciplina [17].

Apéndice A. Reseña de Control de Fluidos 114


B Mallado de la Experiencia

B.1. Detalle del Mallado


La Fig. B.1 muestra un histograma acumulativo de las cantidades de celdas utilizadas de
acuerdo a la superficie que presentan. Se puede observar la cantidad de elementos triangulares
utilizados dependiendo del volumen ocupado por los mismos con un incremento importante en
aquellos que presentan un tamaño cercano a 0,1, es decir, con superficie aproximada de 0,005.

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.

El total de celdas triangulares utilizadas en la malla es de 169507. El detalle de la configu-


ración puede observarse en las Fig. B.2 y B.3.

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).

Apéndice B. Mallado de la Experiencia 116


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

B.2. Efectos de Cambios Bruscos en la Malla durante la Simu-


lación
Las Fig. B.4, B.5 y B.6 muestran una secuencia de simulación donde la existencia de cambios
bruscos en las dimensiones de las celdas del mallado generan errores de cálculo localizados. Estos
errores se propagan rápidamente a través de las celdas vecinas generando la divergencia de la
simulación.

Apéndice B. Mallado de la Experiencia 117


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Apéndice B. Mallado de la Experiencia 118


C Verificación de la Identificación del Sis-
tema

C.1. Ajuste en Implementación Matlab


El criterio utilizado para definir el orden del modelo ARX para el algoritmo de control
consiste en verificar el nivel de ajuste que poseen las predicciones del modelo respecto de las
muestras utilizadas para generarlo. Si bien se conocen rutinas pre-existentes en Matlab tanto para
la identificación del sistema (llamada arx ) como para realizar una comparación visual sobre el
grado de ajuste del modelo calculado (llamada compare), se decide realizar una implementación
propia de cada uno. En el primer caso, se pretende comprobar la efectividad del algoritmo
definido y la posibilidad de una implementación que soporte alto paralelismo en CUDA C/C++.
En el segundo caso se requiere control sobre los resultados del ajuste de cada variable, mientras
que la rutina existente tiene una clara orientación a la comparación visual.
El código fuente del desarrollo propio de la identificación del sistema (lfd arx.m) y de la
comparación sobre el porcentaje de ajuste que posee lfd compare.m pueden encontrarse en el
Apéndice F.5. El algoritmo de comparación utiliza la función predict de Matlab para predecir
los valores yi (k) futuros según el modelo ARX utilizando un horizonte de predicción s para cada
paso de tiempo.
A continuación se presentan los resultados del ajuste calculado para distintos órdenes del
modelo (p) incluyendo la media del porcentaje de ajuste de todas las variables yi , ası́ como los
valores mı́nimo y máximo obtenidos. Como horizonte de predicción se utiliza el valor aproximado
de medio perı́odo natural, s = 43 . Se utiliza la simulación de entrenamiento de 1090 muestras
con la actuación de un pulso.

Ajuste Matlab Ajuste Ajuste Ajuste


Orden (p) Prom. [ %] Prom. [ %] Mı́n. [ %] Máx. [ %]
20 83,39 83.39 62.21 90.21
30 91,28 91.31 83.09 95.35
40 96,54 96.53 95.51 97.93
50 98,08 98.08 97.21 99.16
60 98,78 98.78 98.05 99.35
70 99,32 99.32 98.96 99.59
80 99,57 99.57 99.27 99.70
90 99,70 99.70 99.44 99.82
100 99,75 99.73 99.36 99.94

C.2. Ajuste y Tiempos en Implementación C++


A continuación se resumen las pruebas de concepto realizadas sobre el desarrollo del algoritmo
de identificación del sistema en Matlab en comparación su versión en C++.

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.

Tiempo Ajuste Ajuste Ajuste


Orden (p) Lenguaje [s] Prom. [ %] Mı́n. [ %] Máx. [ %]
10 Matlab 1,7 57,0 50,4 67,7
10 C++ (CUDA/CULA) 1,5 56,9 50,5 67,6
10 C++ (GSL) 55,5 56,9 50,5 67,6
20 Matlab 13,6 61,6 49,1 72,7
20 C++ (CUDA/CULA) 3,4 61,4 48,7 72,8
20 C++ (GSL) 330,1 61,4 48,7 72,8
40 Matlab 118,9 88,0 66,8 93,6
40 C++ (CUDA/CULA) 12,4 87,9 66,8 93,6
40 C++ (GSL) 1952,1 87,9 66,8 93,6
50 Matlab 229,3 90,4 67,2 95,9
50 C++ (CUDA/CULA) 19,0 90,4 67,2 95,9
50 C++ (GSL) 3497,9 90,4 67,2 95,9
60 Matlab 403,9 91,6 67,4 97,8
60 C++ (CUDA/CULA) 28,0 91,6 67,4 97,8
60 C++ (GSL) 5746,2 91,6 67,4 97,8
70 Matlab 646,7 92,2 67,4 99,0
70 C++ (CUDA/CULA) 40,7 92,2 67,4 99,0
70 C++ (GSL) 8614,6 92,2 67,4 99,0
80 Matlab 951,7 92,4 67,4 99,4
80 C++ (CUDA/CULA) 53,5 92,4 67,4 99,4
80 C++ (GSL) 12317,8 92,4 67,4 99,4
90 Matlab 1349,6 92,5 67,4 99,6
90 C++ (CUDA/CULA) 70,2 92,5 67,4 99,6
90 C++ (GSL) 16957,2 92,5 67,4 99,6

Se observa un incremento importante del tiempo de ejecución a medida que se aumenta p


para todos los sistemas. Sin embargo, la versión que utiliza capacidades de GPGPU resulta
sensiblemente más rápida resolviendo el caso de identificación de sistema utilizado en el sistema
de control (p = 90) en tiempos cercanos al minuto mientras el código Matlab utiliza aproxi-
madamente 22 minutos. Por otra parte, la implementación del sistema en GSL demostró un
rendimiento muy pobre con órdenes de magnitud de diferencia en cuanto a los tiempos de eje-
cución para todo p.

Apéndice C. Verificación de la Identificación del Sistema 120


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Cabe destacar que el nivel de ajuste se mantiene similar en todos los casos.

Apéndice C. Verificación de la Identificación del Sistema 121


D Avances Experimentales para Trabajos
Futuros

D.1. Control Adaptativo


Se realizaron pruebas experimentales sobre leyes de control adaptativo. En este esquema, la
matriz de control se adapta a cada paso de simulación en base a ajustes evaluados contra la
función objetivo. En el escenario ideal, la matriz de control converge hacia valores óptimos de
control. Las experiencias realizadas (Fig. D.1) muestran un posible escenario de convergencia
donde el actuador se acerca asintóticamente a su óptimo.
Aunque posee resultados prometedores, este tipo de controlador presenta grandes complica-
ciones en cuanto al tuning de parámetros debido a la combinación de varias variables sobre el
peso del control. Otro factor importante consiste en la necesidad de realizar largas simulaciones
hasta contar con la suficiente información para determinar la convergencia o no de la actuación
(Fig. D.2). El código fuente utilizado en este esquema de pruebas fue basado en [36] y se puede
encontrar en el Apéndice G.3.

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.

D.2. Control con Modelo ARX de Orden Elevado


Con el objetivo de comprobar el efecto de modificaciones drásticas en el orden del modelo
ARX sobre el sistema controlador, se realizaron distintas pruebas experimentales con un nuevo
mallado. En este caso, se definió una malla fina en el centro pero con celdas de mayor tamaño en
la periferia. De esta forma se obtuvo una menor cantidad total de celdas que permitió extender
el mallado aguas abajo de la experiencia para mejorar la resolución numérica. Las Figs. D.3 y
D.4 muestran el detalle del mallado.

Figura D.3: Tamaño en la separación del nuevo mallado para las lı́neas de la geometrı́a.

Apéndice D. Avances Experimentales para Trabajos Futuros 123


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Parámetro Variable Valor


Orden del Modelo p 150
Paso de Tiempo Simulación ∆t 0,061
0.122 (1 muestra
Paso de Tiempo Muestreo cada 2 pasos de Sim.)
Peso de Sensores Sup. q1 , q2 , q3 , q4 1,1 0,75 0,5 0,25
Peso de Sensores Inf. q5 , q6 , q7 , q8 1,1 0,75 0,5 0,25
Costo del Controlador λ 0,00045

Tabla D.1: Valores definidos para los distintos parámetros de control del sistema.

Apéndice D. Avances Experimentales para Trabajos Futuros 124


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

D.3. Captura de Imágenes Mediante Cámaras Digitales


Se realizaron trabajos experimentales con las distintas cámaras digitales del Laboratorio de
Fluidodinámica de la Facultad de Ingenierı́a (UBA), donde se realizó el proyecto de investigación.
En todos los casos se intentó medir los tiempos de respuesta de las cámaras para tomar y
transferir imágenes a un posible sistema controlador. Se adjuntan los resultados obtenidos que

Apéndice D. Avances Experimentales para Trabajos Futuros 125


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

pueden ser de utilidad en futuras implementaciones de la experiencia en tiempo real. La Tabla


D.2 incluye el detalle de las propiedades de cada cámara evaluada. Los códigos fuente utilizados
se encuentran en el Apéndice G.1.

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:

Imágenes Capturadas 200


FPS 50
Tiempo Total 4000ms
Tiempo Promedio 20ms. Equivalente a 50 FPS (tiempo de transferencia despreciable).

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:

Imágenes Capturadas 120


FPS 30
Tiempo Total 4000ms
Tiempo Promedio 33, 3ms. Equivalente a 30 FPS (tiempo de transferencia despreciable).

D.3.3. SpeedCam Mini Vis e2


La SpeedCam no posee una API de acceso programático. Tampoco permite sacar fotogramas
de forma unitaria, sólo es posible sacar una ráfaga que es almacenada en el buffer interno de la
cámara y luego transmitido a la PC.
La cámara posee código hecho en Java del cual se pueden obtener los .jar para emplearlos en
un código de prueba. Se consulta al soporte de fábrica sobre manuales o información de utilidad
para utilizar las librerı́as sin mayores resultados.
Luego de realizar distintos trabajos de re-ingenierı́a mediante la decompilación del sistema
que utiliza la cámara, se elabora un código que permite obtener las siguientes mediciones:

Imágenes Capturadas 200


FPS 2500
Tiempo Total 7800ms (únicamente de transferencia)
Tiempo Promedio 39ms. Equivalente a 25 FPS.

Apéndice D. Avances Experimentales para Trabajos Futuros 126


E Publicaciones

E.1. Anales de la AFA


Publicación presentada durante el mes de Diciembre de 2012 en los Anales de la Asociación
Fı́sica Argentina (AFA) bajo el tı́tulo “Control a Lazo Cerrado de la Estela de un Cilindro” en
coautorı́a con Thomas Duriez, Ada Cammilleri y Guillermo Artana.

E.2. Physics of Fluids


Publicación presentada durante el mes de Septiembre de 2013 en la revista Physics of Fluids
de la American Institute of Physics bajo el tı́tulo “A visualization-based flow control system”
en coautorı́a con Thomas Duriez, Ada Cammilleri, Lionel Mathelin y Guillermo Artana.

127
Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

CONTROL A LAZO CERRADO DE LA ESTELA DE UN CILINDRO

CYLINDER WAKE CLOSED-LOOP CONTROL SYSTEM


Pablo Roca, Thomas Duriez, Ada Cammilleri, Guillermo Artana

Laboratorio de Fluidodinámica, Facultad de Ingeniería, Universidad de Buenos Aires


cada@fi.uba.ar

Recibido: 13/12/2012; aceptado: 14/03/2013


Se introduce un sistema de control a lazo cerrado sobre el escurrimiento de un cilindro basado en el
procesamiento de imágenes. Dentro de una simulación numérica directa, se considera el flujo que contornea un
cilindro y se procura disminuir las fluctuaciones en su estela. Trazadores pasivos son inyectados en el sistema
para construir un modelo matemático de identificación de sistema tipo ARX con su concentración medida en
ciertos puntos de las imágenes. Luego, mediante el empleo de un algoritmo de control GPC, se actúa inyectando
cantidad de movimiento tangencial al cilindro para forzar el flujo y reducir las fluctuaciones de la estela.
Palabras clave: cilindro, estela, simulación, imágenes, control, lazo cerrado, ARX, GPC.
A closed-loop control system is introduced to stabilize a cylinder wake based on image processing. A direct
numerical simulation is used to compute the fluid flow through a cylinder and stabilize its wake. Passive scalar
tracers are injected in the system to constitute an AutoRegressive with eXogenous input (ARX) mathematical
model by sensing its concentration on certain image sectors. A Generalized Predictive Controller (GPC)
algorithm is used to calculate the necessary actuation to stabilize the wake by adding momentum tangentially to
the cylinder wall.
Keywords: cylinder, wake, simulation, images, control, closed-loop, ARX, GPC.

base a mediciones para retroalimentar al sistema de


I. INTRODUCCIÓN
control y poder ajustar los parámetros en tiempo real. Se
Es conocida la importancia que reviste la disciplina trata de un control activo con la capacidad de adaptar
de control de fluidos tanto para el ámbito científico los parámetros de control y la energía utilizada en base a
como para la industria. A los objetivos clásicos de teoría los resultados medidos en el sistema, el objetivo
de control como el seguimiento de valores de referencia, definido y la modelización matemática que se realizó
rechazo de perturbaciones y de errores de medición se sobre el sistema.
suman aplicaciones específicas como la reducción de Es en este contexto donde la modelización del
fuerzas de arrastre o la supresión de inestabilidades que sistema físico recubre un carácter fundamental para
resultan de gran valor por sus aplicaciones prácticas. estimar la actuación a aplicar en busca de un objetivo
El estudio de control de fluidos se caracteriza por definido. Algunas estrategias implican el uso de
buscar las partes sensibles de un flujo que permitan ecuaciones fundamentales de la mecánica como es el
obtener modificaciones que lleven el flujo a un estado caso de las ecuaciones de Navier-Stokes que son
deseado en base a pequeñas perturbaciones linealizadas para construir un modelo de orden reducido
intencionales conocidas como actuación. Un sistema de que permita estimar el flujo8. Otros modelos se
control se puede caracterizar por el esquema de concentran en propiedades globales como el consumo
actuación empleado según sea pasivo, activo o reactivo. de energía para realizar control por búsqueda de
El control pasivo consiste en realizar modificaciones extremos9 donde se busca un mínimo a la función global
en el entorno de operación de forma de parametrizar de costo determinada por el estudio de un control activo
ciertos cambios respecto de la modificación que se forzado (lazo abierto). Finalmente existen los modelos
observa en el flujo. En este esquema, una vez empíricos de caja negra basados en la observación del
establecido el entorno no es posible cambiar la sistema en un proceso de control a lazo abierto. Un
parametrización. Ejemplos típicos son generadores de ejemplo de este escenario consta en la identificación de
vórtices1,2,3 y pequeños objetos físicos dentro de la sistemas basados en modelos AutoRegressive (AR) que
estela del fluido4. En control activo se aplica energía determinan una relación entre el estado del sistema
durante la actuación para adaptar la respuesta del fluido actual y el medido en tiempos pasados. En el pasado se
a un resultado deseado. En este caso, las condiciones de realizaron experiencias de control basadas en modelos
la experiencia pueden cambiar a lo largo del tiempo autoregresivos ARX10,11,12,13 y autoregresivos
siendo necesario adaptar los parámetros de actuación ARMAX 14
que permiten utilizar algoritmos de
definidos. Ejemplos típicos son controles tipo jet predicción y optimización sobre ciertas funciones
(pulsados o sintéticos)5,6, dispositivos mecánicos definidas como objetivo para el control.
ajustables y cilindros rotantes7. El control reactivo El presente trabajo desarrolla un sistema de control
implica que el estado del flujo es medido o estimado en de fluidos reactivo basado en el procesamiento de

ANALES AFA Vol. 23 FLUIDOS (29-33) BUENOS AIRES 2012 29

Apéndice E. Publicaciones 128


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

imágenes para obtener un modelo a caja negra ARX que


permita describir y predecir el sistema físico. Se elige el
experimento prototípico del escurrimiento sobre un
cilindro a fin de efectuar las pruebas correspondientes
sobre el algoritmo y bloques de control.
II. MODELO FÍSICO SIMULADO
Como modelo físico bajo estudio se toma el
escurrimiento del fluido sobre un cilindro y se plantea el
objetivo de estabilizar su estela. Filamentos de escalar Figura 3. Vorticidad computada en la simulación luego de
alcanzar el estado estacionario (Re:235).
pasivo son inyectados aguas arriba del experimento para
medir luego la concentración en ciertos puntos y definir
un vector de estado del sistema con dichos valores. Se
colocan dos actuadores en la pared del cilindro con el
objetivo de agregar cantidad de movimiento de forma
tangencial para forzar el flujo y controlar la estela. Se
simula una actuación del tipo plasma15 con inyección de
cantidad de movimiento a través de un mecanismo de
impacto iónico. La acción es homogénea, simultánea y
simétrica a lo largo de dos semiarcos de 5% de
Figura 4. Concentración de escalar medida en el sensor 1
circunferencia del cilindro, en una posición cercana al
durante la fase de inicio de inicio del sistema. Al llegar al
punto de separación. (Fig. 1) régimen estacionario se puede apreciar la periodicidad en la
concentración con un T aproximado de 90 pasos de
simulación (Re:235).

III. IDENTIFICACIÓN DEL SISTEMA


Para representar la dinámica del escurrimiento
elegimos considerar un modelo lineal en tiempo discreto
dado por

(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

Figura 2. Concentración de escalar computada en la


simulación luego de alcanzar el estado estacionario (Re:235). la Ec. 1 pueda ser escrita de la forma

30 ANALES AFA Vol. 23 FLUIDOS (29-33) BUENOS AIRES 2012

Apéndice E. Publicaciones 129


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

siendo conocidos como


A fin de estimar , se define una fase de parámetros de Markov del sistema10, y es una matriz
entrenamiento donde la actuación es forzada mientras se de ms x sr definida por una serie de relaciones
mide la respuesta del sistema físico. Luego, se utilizan recursivas a partir de los parámetros del modelo.
las N muestras de entrenamiento junto al criterio de Se establece un algoritmo de control basado en el
estimación por cuadrados mínimos para determinar un algoritmo Generalizado de control predictivo (GPC)11
estimador de según con el objetivo de disminuir la concentración de escalar
medida en los sensores.
Se determina entonces la función de costo apropiada
para describir la ley de control

donde es una matriz de sm x sm, diagonal en


bloques , tales que y
Dado que la matriz puede estar
mal condicionada consideramos un método más efectivo representa el peso del sensor i, .
para estimar los parámetros16. Suponiendo una ley de control lineal, y utilizando el
método de Lagrange, la minimización del funcional
Si se define un vector de definido en la Ec. 4 sujeto a cumplir la Ec. 3 da como
que reune a todos los resultado
coeficientes de la matrices y , la Ec. 1 puede
también ser escrita de la forma
donde I representa a la matriz identidad de sr x sr.
Dado que se requiere el valor de actuación para el
paso de tiempo actual (k), es posible ahorrar tiempo de
Luego, la estimación de se obtiene a partir de la
cómputo determinando las primeras r filas del producto
descomposición QR de la matriz donde es de del primer término de la Ec. 5 según
Nm x d e Y es de Nm x 1 tales que

Una vez aplicada la actuación y obtenidas las


mediciones del paso de tiempo siguiente, se cierra el
lazo de control calculando e ingresando nuevamente
IV. ALGORITMO DE CONTROL A LAZO en la Ec. 6. La secuencia del sistema de control queda
CERRADO descripta en el Algortimo 1.
Siendo s el horizonte de predicción definimos de
sr x 1, de sm x 1 y de p(m+r) x 1 según ALGORITMO 1: ALGORITMO DE CONTROL PROPUESTO

Entrada: p: orden del modelo, s: horizonte de predicción,


: costo del actuador
Salida: Control del sistema en estudio
1: Medir valores del ciclo de entrenamiento
2: Obtener el modelo ARX de orden p
3: Definir el controlador con s, y el modelo ARX
4: Para cada Paso de tiempo k hacer
5: Medir los valores y para el paso k
6: Construir agregando los valores de y(k)
De la Ec. 1 podemos obtener una ecuación matricial 7: Utilizar Ec. 6. para obtener u(k)
que predice las futuras salidas del sistema10 8: Aplicar la actuación u(k)
9: Fin para

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).

ANALES AFA Vol. 23 FLUIDOS (29-33) BUENOS AIRES 2012 31

Apéndice E. Publicaciones 130


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Figura 8. Vorticidad resultante de la simulación del control


Figura 5. Fase de entrenamiento del sistema. Luego de en el instante de mínima concentración medida en los
aplicar el pulso de actuación, el valor de concentración sensores (Re:235).
medido en las líneas de sensores se reduce abruptamente
producto de la estabilización de la estela.
Luego de realizada la calibración de los distintos VI. CONCLUSIONES
parámetros de control, se simula el sistema físico con el Se desarrolló un sistema de control a lazo cerrado en
controlador ya entrenado obteniendo una actuación de una simulación numérica. Se verificó su correcto
control que estabiliza la estela del cilindro (Fig. 6, 7 y funcionamiento con la experiencia prototípica del
8). escurrimiento del cilindro. La estela del cilindro fue
De la misma forma se pudo verificar la sensada a través de la medición de la concentración del
adaptabilidad del algoritmo frente a condiciones fuera escalar inyectado y estabilizada gracias a la actuación de
de diseño. A tal fin se modificó la velocidad del flujo de respuesta. El sistema de control definido resulta lo
entrada de forma temporal observando la capacidad del suficientemente genérico para ser adaptado a otros
control para encontrar un nuevo punto de actuación experimentos e implementado con un esquema de
óptima. Luego de cierto período de transición, el captura de imágenes.
sistema cambia su señal de control y logra estabilizar la
estela (Fig. 9).

Figura 9. Cambios en la condición de entrada. El sistema de


control adapta la respuesta de su actuador para estabilizar la
Figura 6. Lazo cerrado de control. La actuación se estela del cilindro bajo el cambio de las condiciones de
incrementa cuando el escalar medido crece y se reduce entrada indicadas por la referencia.
cuando su efecto estabiliza la estela y baja la concentración
de escala en los sensores. Queda pendiente para trabajos futuros el estudio de
métodos adaptativos de control12 y sus resultados con el
esquema propuesto.
Asimismo, procuraremos estudiar el incremento de
la cantidad de sensores utilizados, la medición de los
tiempos de cómputo requeridos, el análisis del
desempeño con posibles optimizaciones del algoritmo y
la implementación de la experiencia en laboratorio.
VI. REFERENCIAS
1- Lin J. Progress in Aerospace Sciences, 38(4-5), 389–420
(2002).
Figura 7. Vorticidad resultante de la simulación del control 2- Godard G. and Stanislas M. Aerospace Science and
en el instante de máxima concentración medida en los Technology, 10(6), 455–464 (2006).
sensores. En este momento, la actuación comienza a crecer 3- Duriez T., Aider J., and Wesfreid J. Physical Review
para compensar las oscilaciones en la estela (Re:235). Letters, 103(14) (2009).
4- Cadot O., Thiria B., and Beaudoin J. Solid Mechanics and
its Applications, 14, 529–537 (2009).
5- Godard G. and Stanislas M. Aerospace Science and
Technology, 10(6), 455–464 (2006).
6- Kostas J., Foucaut J., and Stanislas M. Flow, Turbulence
and Combustion, 78(3-4), 331–363 (2007).

32 ANALES AFA Vol. 23 FLUIDOS (29-33) BUENOS AIRES 2012

Apéndice E. Publicaciones 131


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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)

ANALES AFA Vol. 23 FLUIDOS (29-33) BUENOS AIRES 2012 33

Apéndice E. Publicaciones 132


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

A visualization-based flow control system


Pablo Roca,1 Thomas Duriez,1 Ada Cammilleri,1 Lionel Mathelin,2 and Guillermo Artana3, a)
1)
Laboratorio de Fluidodinámica, Facultad de Ingeniería, Universidad de Buenos Aires,
Argentina
2)
LIMSI, CNRS, Orsay, France
3)
CONICET, Laboratorio de Fluidodinámica, Facultad de Ingeniería, Universidad de Buenos Aires,
Argentina
(Dated: October 24, 2013)
A closed-loop control system is introduced to stabilize a cylinder wake flow based on images of streaklines.
Passive scalar tracers are injected upstream the cylinder and their concentration is monitored downstream
at certain image sectors of the wake. An AutoRegressive with eXogenous inputs (ARX) mathematical model
is built from these images and a Generalized Predictive Controller (GPC) algorithm is used to compute
the actuation required to stabilize the wake by adding momentum tangentially to the cylinder wall through
plasma actuators. The methodology is demonstrated on a numerical simulation and the provided results show
that good performances are achieved.

PACS numbers: 47.85.L

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.

a) Electronic mail: gartana@fi.uba.ar

Apéndice E. Publicaciones 133


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

A. Scope of the paper

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.

II. PSEUDO-EXPERIMENTAL SET-UP

We consider a two-dimensional flow around a circular cylinder and the control objective of stabilizing the wake
(suppression of the vortex shedding).

Apéndice E. Publicaciones 134


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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).

III. SYSTEM IDENTIFICATION

To describe the flow dynamics we consider a linear time-invariant model given by

y(k) + α1 y(k − 1) + · · · + αp y(k − p) = β0 u(k) + β1 u(k − 1) + · · · + βp u(k − p) (1)

Apéndice E. Publicaciones 135


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Apéndice E. Publicaciones 136


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

Apéndice E. Publicaciones 137


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Apéndice E. Publicaciones 138


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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).

IV. CLOSED-LOOP CONTROL ALGORITHM

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),

Apéndice E. Publicaciones 139


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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,

ys (k) = T us (k) + Ψvp (k − p) (3)

where T is a Toeplitz matrix given by

Apéndice E. Publicaciones 140


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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:

Apéndice E. Publicaciones 141


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

The matrix Ψ is defined as


 
α1 α2 . . . αp β1 β2 . . . βp
 α(1) (1)
α2 . . . αp
(1)
β1
(1) (1)
β2 . . . βp
(1) 
Ψ := 
 ...
1 
... ... ... ... ... ... ... 
(s−1) (s−1) (s−1) (s−1)
α1 ... . . . αp β1 ... . . . βp

with the following relations for α1k , βkj and αkj :

Apéndice E. Publicaciones 142


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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:

Apéndice E. Publicaciones 143


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

12

Algorithm 1 Proposed control algorithm.


Require: p: model order, s: prediction horizon, λ: actuator cost.
Ensure: Control of the system under study.
1: Take measurements during a training cycle.
2: Compute an ARX model with order p.
3: Define the controller K from s, λ, and the ARX model.
4: Define the initial vp from y and u values up to step k − 1.
5: for all time step k do
6: Use Eq. (6) to obtain u(k).
7: Apply the computed actuation u(k).
8: Measure y(k), the resulting output for the time step k.
9: Update vp from y(k) and u(k).
10: end for

V. CONTROL SYSTEM RESULTS

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

Apéndice E. Publicaciones 144


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

Apéndice E. Publicaciones 145


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Apéndice E. Publicaciones 146


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Apéndice E. Publicaciones 147


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Apéndice E. Publicaciones 148


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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.

Apéndice E. Publicaciones 149


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

Science and Technology 10, 455–464 (2006).


3 T. Duriez, J. Aider, and J. Wesfreid, “Self-sustaining process through streak generation in a flat-plate boundary layer,” Physical Review

Letters 103 (2009).


4 A. Roshko, “On the wake and drag of bluff bodies,” J. Aeronaut. Sci. 22, 124–132 (1955).
5 J. Kostas, J. 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, 331–363 (2007).
6 B. Thiria, S. Goujon-Durand, and J. Wesfreid, “The wake of a cylinder performing rotary oscillations,” Journal of Fluid Mechanics

560, 123–147 (2006).


7 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).


8 M. Munska and T. Mclaughlin, “Circular cylinder flow control using plasma actuators,” AIAA paper 2005-0141 (2005).
9 T. Jukes and K. Choi, “Control of unsteady flow separation over a circular cylinder using dielectric-barrier-discharge surface plasma,”

Physics of fluids 21, 094106 (2009).


10 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).


11 C. Rowley, “Model reduction for fluid flows using balanced proper orthogonal decomposition,” Int. J. Bifurc. Chaos 15, 997–1013 (2005).
12 A. Barbagallo, D. Sipp, and P. Schmid, “Why may reduced order models based on global modes not work for closed loop control?”

(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

control,” Journal of Sound and Vibration 307, 906–923 (2007).


15 M. A. Kegerise, R. H. Cambell, and L. N. Cattafesta, “Real time feedback control of flow-induced cavity tones - part 2: Adaptive

control,” Journal of Sound and Vibration 307, 924–940 (2007).


16 S.-C. Huang and J. Kim, “Control and system identification of a separated flow,” Physics of Fluids 20 (2008).
17 A. Herve, D. Sipp, P. J. Schmid, and M. Samuelides, “A physics-based approach to flow control using system identification,” Journal

of Fluid Mechanics 702, 26–58 (2012).


18 R. T. Fomena and C. Collewet, “Fluid flow control: a vision-based approach,” International Journal of Flow Control 3, 133–169 (2011).
19 M. Gharib, C. Willert, and M. Munson, “Real-time particle image velocimetry for closed-loop flow control applications,” (2010).
20 J. A. N. Gauthier, “Control of the detached flow behind a backward facing step by visual feedback,” ArXiv 1306.4554v (2013).
21 J. D’Adamo, L. M. Gonzalez, A. Gronskis, and G. Artana, “The scenario of two-dimensional instabilities of the cylinder wake under

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

flows,” International Journal on Finite Volumes 1 (2004).

Apéndice E. Publicaciones 150


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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,”

Physics of Fluids 22, 034102 (2010).


27 H. Choi, W. Jeon, and J. Kim, “Control of flow over a bluff body,” Annual Review of Fluid Mechanics 40, 113–139 (2008).
28 K. Cohen, S. Aradag, S. Siegel, J. Seidel, and T. McLaughlin, Low Reynolds Aerodynamics and Transition (edt by Mustafa Serdar

Genc, InTech Europe, 2012) Chap. 6, pp. 117–138.


29 L. N. Cattafesta, Q. Song, D. R. Williams, C. W. Rowley, and F. S. Alvi, “Active control of flow-induced cavity oscillations,” Progress

in Aerospace Sciences 44, 479–502 (2008).


30 E. Gillies, “Low-dimensional control of the circular cylinder wake,” Journal of Fluid Mechanics 371, 157–178 (1998).
31 K. Roussopoulos, “Feedback control of vortex shedding at low reynolds number,” Journal of Fluid Mechanics 248, 267–296 (1993).

Apéndice E. Publicaciones 151


F Códigos Fuente

F.1. Extensión del Mallado 2D a 3D

% 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

close all;clear all


%numero de layers: condiciones de borde
layers_number=6;
% %espesor de extrudado
dz=5*1e-3;
%factor de escala para cambiar la unidad de medida de todos los nodos procesados
escala=1;
%nombre del archivo inicial
unit1=’cilindro.noestructurado.dat’;
%nombre del archivo final
unit2=’cilindro.noestructurado.msh’;

% 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);

%deteccion del nro de BC asociado a simetria


Lnumber = -1;
for i=1:layers_number
name=char(layers{2}(i));
K=strcmp(name,’simetria’);
if K==1
Lnumber=layers{1}(i);
end
end
if Lnumber == -1
Lnumber=layers_number+1;
end

% Matriz de coordenadas de nodos: [nNodo x y z]


node_coordstot(1:nnodes{1},1)=node_coords{1};
node_coordstot(1:nnodes{1},2)=node_coords{2}*escala;
node_coordstot(1:nnodes{1},3)=node_coords{3}*escala;
node_coordstot(1:nnodes{1},4)=0.0*escala;
node_coordstot(nnodes{1}+1:2*nnodes{1},1)=node_coords{1}+nnodes{1};
node_coordstot(nnodes{1}+1:2*nnodes{1},2)=node_coords{2}*escala;
node_coordstot(nnodes{1}+1:2*nnodes{1},3)=node_coords{3}*escala;
node_coordstot(nnodes{1}+1:2*nnodes{1},4)=dz;

%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);

Apéndice F. Códigos Fuente 153


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

% Almacenamiento del archivo .msh


reng1=’$MeshFormat’;
reng2=’2 0 8’;
reng3=’$EndMeshFormat’;
reng4=’$Nodes’;
reng5=’$EndNodes’;
reng6=’$Elements’;
reng7=’$EndElements’;
reng8=’$PhysicalNames’;
reng9=’$EndPhysicalNames’;
fid2 = fopen(unit2,’w’);
fprintf(fid2, ’ %s\n’, reng1);
fprintf(fid2, ’ %s\n’, reng2);
fprintf(fid2, ’ %s\n’, reng3);
fprintf(fid2, ’ %s\n’, reng4);
fprintf(fid2, ’ %d\n’, nnodes{1}*2);
fprintf(fid2, ’ %d %g %g %g\n’, node_coordstot’);
fprintf(fid2, ’ %s\n’, reng5);

Apéndice F. Códigos Fuente 154


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

fprintf(fid2, ’ %s\n’, reng6);


fprintf(fid2, ’ %d\n’, nelemens_tot);
if n1>0
fprintf(fid2, ’ %d %d %d %d %d %d %d %d %d\n’, Elemconec1’);
end
if n2>0
fprintf(fid2, ’ %d %d %d %d %d %d %d %d\n’, Elemconec2’);
end
if n3>0
fprintf(fid2, ’ %d %d %d %d %d %d %d %d %d\n’, Elemconec3’);
end
if n4>0
fprintf(fid2, ’ %d %d %d %d %d %d %d %d %d %d %d\n’, Elemconec4’);
end
if n5>0
fprintf(fid2, ’ %d %d %d %d %d %d %d %d %d %d %d %d %d\n’, Elemconec5’);
end

fprintf(fid2, ’ %s\n’, reng7);


fprintf(fid2, ’ %s\n’, reng8);
layers_numbers=layers{1};
layers_names=char(layers{2});
for i=1:layers_number
number=layers{1}(i);
name=char(layers{2}(i));
fprintf(fid2, ’ %d %s\n’, number, name);
end
if K==0
number=Lnumber;
name=’simetria’;
fprintf(fid2, ’ %d %s\n’, number, name);
end
fprintf(fid2, ’ %s\n’, reng9);
fclose(fid2);

F.2. Conversión del Mallado Irregular a una Grilla Cartesiana


F.2.1. chrCleanFolderIfExists.m

function chrCleanFolderIfExists( folder )


if exist(folder, ’dir’)
rmdir(folder, ’s’);
end
mkdir(folder);

end

F.2.2. chrComputeAverage.m

function [ average ] = chrComputeAverage( filepaths , geo, isVector)


count = length(filepaths);
fprintf(’Computing average for %d files.\n’, count);
if count < 1
throw MException(’InvalidFileList:NotEnoughFiles’, ’It was not possible to compute the average for
the given file list’);
end

average = chrReadBinaryContent(filepaths{1}, geo, isVector);


for step = 2:count
content = chrReadBinaryContent(filepaths{step}, geo, isVector);
average = average + (content - average) / step;
end

Apéndice F. Códigos Fuente 155


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

fprintf(’Average computation finished.\n’);


end

F.2.3. chrComputeVorticityAverageForGeoXY.m

function [ vorticityZ ] = chrComputeVorticityAverageForGeoXY( filepaths , geo, geoXY)


count = length(filepaths);
fprintf(’Computing average vorticity for %d files.\n’, count);
if count < 1
throw MException(’InvalidFileList:NotEnoughFiles’, ’It was not possible to compute the average for
the given file list’);
end

average = chrComputeAverage(filepaths, geo, true);

fprintf(’Transforming average to XY...\n’);


averageXY = geoTransformContentToXY(average, geo, geoXY);

%content = chrReadBinaryContent(filepaths{1}, geo, true);


%contentXY = geoTransformContentToXY(content, geo, geoXY);

[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’;

fprintf(’Average Vorticity computation finished.\n’);


end

F.2.4. chrExtractBinaryHeader.m

function [ header ] = chrExtractBinaryHeader( filepath )


headerCharacters = chrGetAmountOfHeadingCharacters();
file = fopen(filepath, ’rb’);
if file < 1
throw(MException(’FileError:CannotOpenTheFile’, strcat(’There was an error trying to open the file:
"’, filepath, ’".’)));
end
header = fread(file, headerCharacters, ’char*1=>char’);
fclose(file);
end

F.2.5. chrFindFiles.m

function [ filepaths ] = chrFindFiles( settings )


filesFilter = strcat(settings.folder, ’/’, settings.filenamesFilter);
fprintf(’Seeking files under " %s"\n’, filesFilter);
filenamesStruct = dir(filesFilter);
filenames = {filenamesStruct.name};
filepaths = strcat(repmat(strcat(settings.folder,’/’), length(filenames),1),filenames’);
filepaths = sort(filepaths);
filepathsCount = length(filepaths);
fileMin = max(1, settings.filerangeFilter.min);
fileMax = min(filepathsCount, settings.filerangeFilter.max);
filepaths = filepaths(fileMin:fileMax);
end

Apéndice F. Códigos Fuente 156


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

F.2.6. chrFindFilesAndComputeAverage.m

function chrFindFilesAndComputeAverage( settings )


filepaths = chrFindFiles(settings);
geoFilepath = strcat(settings.folder, ’/’, settings.geoFilename);
if settings.isVector
outputFilename = ’chr.vectoraverage’;
else
outputFilename = ’chr.scalaraverage’;
end
outputFilepath = strcat(settings.outputFolder, ’/’, outputFilename);
outputCaseFilepath = strcat(settings.outputFolder, ’/CHR.case’);

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);

chrWriteCaseFile(outputCaseFilepath, outputFilename, settings.geoFilename, settings.isVector);


end

F.2.7. chrGetAmountOfHeadingCharacters.m

function [ headingCharacters ] = getAmountOfHeadingCharacters( )


headingCharacters = 80 ... % description line 1 (80 chars)
+ 80 ... % part (80 chars)
+ 4 ... % # (1 int)
+ 80; % coordinates (80 chars)
end

F.2.8. chrReadBinaryContent.m

function [ content ] = readBinaryContent( filepath, geo, isVector)


file = fopen(filepath, ’rb’);
if file < 1
throw(MException(’FileError:CannotOpenTheFile’, strcat(’There was an error trying to open the file:
"’, filepath, ’".’)));
end
if isVector
valuesPerCell = 3;
else
valuesPerCell = 1;
end

headerCharacters = chrGetAmountOfHeadingCharacters();
fseek(file, headerCharacters, -1);

content = fread(file, length(geo.cells) * valuesPerCell, ’float32=>double’);


content = reshape(content, length(geo.cells), valuesPerCell);
fclose(file);
end

F.2.9. chrReadBinaryGeo.m

function [ geo ] = chrReadBinaryGeo( filepath )

Apéndice F. Códigos Fuente 157


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

file = fopen(filepath, ’rb’);


if file < 1
throw(MException(’FileError:CannotOpenTheFile’, strcat(’There was an error trying to open the file:
"’, filepath, ’".’)));
end

headerCharacters = 80 + ... %CBinary format


80 + 80 + ... %Description lines
80 + ... %node id
80 + ... %element id %80 + ... %extends optional %6*4 + ... %min,max, etc optional
80 + ... %part
4 + ... %part number
80 + ... %description
80 ; %coordinates

fseek(file, headerCharacters, -1);


countCoordinates = fread(file, 1, ’int32=>int’);
coordinates = fread(file, countCoordinates*3, ’float32=>double’);
fseek(file, 80, 0); %penta6 assumed
countCells = fread(file, 1, ’int32=>int’);
cells = fread(file, countCells*6, ’int32=>double’);
fclose(file);
geo.coordinates = reshape(coordinates, countCoordinates, 3);
geo.cells = reshape(cells, 6, countCells)’;
end

F.2.10. chrReadVelocity2D.m

function [ velocity ] = chrReadVelocity2D(filepaths , geo, geoXY, clipArea)


isVector = true;
qtyFiles = length(filepaths);
fprintf(’Reading values and transforming to XY. %d files.\n’, qtyFiles);
if qtyFiles < 1
throw MException(’InvalidFileList:NotEnoughFiles’, ’It was not possible to compute the average for
the given file list’);
end

areaX = find(geoXY.gridValues.x >= clipArea.x1 & geoXY.gridValues.x <= clipArea.x2);


areaY = find(geoXY.gridValues.y >= clipArea.y1 & geoXY.gridValues.y <= clipArea.y2);
velocity.u = zeros(length(areaX), length(areaY), qtyFiles);
velocity.v = zeros(size(velocity.u));
for step = 1:qtyFiles
fprintf(’Reading file %d.\n’, step);
content = chrReadBinaryContent(filepaths{step}, geo, isVector);
contentXY = geoTransformContentToXY(content, geo, geoXY);
contentXY = contentXY(areaX, areaY,:);
velocity.u(:,:, step) = contentXY(:,:,1);
velocity.v(:,:, step) = contentXY(:,:,2);
end
fprintf(’Reading and transforming to XY finished.\n’);
end

F.2.11. chrWriteBinaryContent.m

function writeBinaryContent( header, content, outputFilepath )


file = fopen(outputFilepath, ’wb’);
if file < 1
throw(MException(’FileError:CannotWriteTheFile’, strcat(’There was an error trying to write the
file: "’, filepath, ’".’)));
end
fwrite(file, header, ’char*1’);
fwrite(file, content, ’float32’);
fclose(file);
end

Apéndice F. Códigos Fuente 158


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

F.2.12. chrWriteCaseFile.m

function chrWriteCaseFile( filepath, valuesFilename, geoFilename, isVector )


file = fopen(filepath, ’wt’);

fprintf(file, ’FORMAT\ntype: ensight gold\n\n’);


fprintf(file, ’GEOMETRY\nmodel: %s\n\n’, geoFilename);
if isVector
fprintf(file, ’VARIABLE\nvector per element: %s %s\n’, valuesFilename,valuesFilename);
else
fprintf(file, ’VARIABLE\nscalar per element: %s %s\n’, valuesFilename,valuesFilename);
end

fclose(file);
end

F.2.13. geoComputeIntersectionArea.m

function area = geoComputeIntersectionArea(xyTriangle, rect, delta, gridBounds)


x1 = rect(1)*delta + gridBounds.minX;
y1 = rect(2)*delta + gridBounds.minY;
x2 = (rect(1)+1)*delta + gridBounds.minX;
y2 = (rect(2)+1)*delta + gridBounds.minY;
% create a counter-clockwise rectangle for the clip operation
xyRect = [x1 y1; x2 y1; x2 y2; x1 y2];

clip = polygonClip(xyTriangle, xyRect);


if isempty(clip)
area = 0;
else
area = polygonArea(clip);
end
end

F.2.14. geoGetBoundingRectsForDelta.m

function rects = geoGetBoundingRectsForDelta(xyTriangle, delta, bounds, gridBounds)


maxX = max(xyTriangle(:,1));
minX = min(xyTriangle(:,1));
maxY = max(xyTriangle(:,2));
minY = min(xyTriangle(:,2));

xCellsUpToMin = floor((minX - bounds.minX) / delta);


xCellsUpToMax = floor((maxX - bounds.minX) / delta);
yCellsUpToMin = floor((minY - bounds.minY) / delta);
yCellsUpToMax = floor((maxY - bounds.minY) / delta);

xCellsUpToMin = max(xCellsUpToMin, gridBounds.minX);


xCellsUpToMax = min(xCellsUpToMax, gridBounds.maxX);
yCellsUpToMin = max(yCellsUpToMin, gridBounds.minY);
yCellsUpToMax = min(yCellsUpToMax, gridBounds.maxY);

rects = zeros((xCellsUpToMax - xCellsUpToMin + 1)*(yCellsUpToMax - yCellsUpToMin + 1), 2);


iiRect = 1;
for xx=xCellsUpToMin:xCellsUpToMax
for yy=yCellsUpToMin:yCellsUpToMax
rects(iiRect, :) =[xx, yy];
iiRect = 1 + iiRect;

Apéndice F. Códigos Fuente 159


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

end
end
end

F.2.15. geoTransformContentToNonXY.m

function [ content ] = geoTransformContentToNonXY( contentXY, geo, geoXY )


contentXYCoordinatesCount = size(contentXY,3);
rowCount = size(geo.cells,1);
content = zeros(rowCount, contentXYCoordinatesCount);
for ii=1:rowCount
cellRectAndRatios = geoXY.cellsRectTargetAndRatio{ii};
contentCoords = 1:contentXYCoordinatesCount;
cellContent = zeros(1,1,contentXYCoordinatesCount);
for jj=1:length(cellRectAndRatios)
x = cellRectAndRatios{jj}.rect(1)+1;
y = cellRectAndRatios{jj}.rect(2)+1;
cellContent = cellContent + contentXY(x,y,contentCoords)*cellRectAndRatios{jj}.
ratioIntersectionTri;
end
content(ii,:) = reshape(cellContent, 1,contentXYCoordinatesCount,1);
end
end

F.2.16. geoTransformContentToXY.m

function [ contentXY ] = geoTransformContentToXY( content, geo, geoXY )


contentCoordinatesCount = size(content,2);
contentXY = zeros(geoXY.gridBounds.maxX + 1, geoXY.gridBounds.maxY + 1, contentCoordinatesCount);
rowCount = size(content, 1);
for ii=1:rowCount
cellRectAndRatios = geoXY.cellsRectTargetAndRatio{ii};
contentCoords = 1:contentCoordinatesCount;
cellContent = reshape(content(ii, contentCoords), 1,1,contentCoordinatesCount);
for jj=1:length(cellRectAndRatios)
x = cellRectAndRatios{jj}.rect(1)+1;
y = cellRectAndRatios{jj}.rect(2)+1;
contentXY(x,y,contentCoords) = contentXY(x,y,contentCoords) + cellRectAndRatios{jj}.
ratioIntersectionRect * cellContent;

end

end
end

F.2.17. geoTransformMeshToXYGrid.m

function [ geoXY ] = geoTransformMeshToXYGrid( geo, xyStep)

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

Apéndice F. Códigos Fuente 160


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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;

cellsCount = size(geo.cells, 1);


rectArea = xyStep*xyStep;
cells = geo.cells;
xyCoordinates = geo.coordinates(:,1:2);
cellsRectTargetAndRatio = cell(cellsCount, 1);
parfor ii = 1:cellsCount
currentCell = cells(ii,:);
xyTriangle = xyCoordinates(currentCell(1:3),:);
triArea = polygonArea(xyTriangle);
boundingRects = geoGetBoundingRectsForDelta(xyTriangle, xyStep, bounds, gridBounds);
rectsCount = size(boundingRects, 1);
cellRectAndRatio = {};
iiCellRectAndRatio = 0;
for jj=1:rectsCount
rect = boundingRects(jj,:);
intersectionArea = geoComputeIntersectionArea(xyTriangle, rect, xyStep, bounds);
if intersectionArea > 0
iiCellRectAndRatio = iiCellRectAndRatio +1;
cellRectAndRatio{iiCellRectAndRatio}.rect = rect;
cellRectAndRatio{iiCellRectAndRatio}.ratioIntersectionRect = intersectionArea/rectArea;
cellRectAndRatio{iiCellRectAndRatio}.ratioIntersectionTri = intersectionArea/triArea;
end
end
cellsRectTargetAndRatio{ii} = cellRectAndRatio;
end
geoXY.gridValues = gridValues;
geoXY.gridBounds = gridBounds;
geoXY.bounds = bounds;
geoXY.step = xyStep;
geoXY.cellsRectTargetAndRatio = cellsRectTargetAndRatio;
end

F.2.18. polygonArea.m

function area = polygonArea(polygon)


%assumes clockwise orientation
%reference: http://alienryderflex.com/polygon_area/
area = 0;
points = size(polygon, 1);
jj = points;
for ii = 1:points
area = area + (polygon(jj, 1) + polygon(ii, 1))*(polygon(jj,2)-polygon(ii,2));
jj = ii;
end
area = area * 0.5;
%do not take care on clockwise or counterclockwise polygons, just take positive areas.
area = abs(area);
end

Apéndice F. Códigos Fuente 161


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

F.2.19. polygonClip.m

function clippedPolygon = polygonClip(subjectPolygon,clipPolygon)


%reference: http://rosettacode.org/wiki/Sutherland-Hodgman_polygon_clipping#MATLAB
% % Helper Functions
%computerIntersection() assumes the two lines intersect
function intersection = computeIntersection(line1,line2)

%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]]);

denominator = det([detL1x detL1y;detL2x detL2y]);

intersection(1) = det([detL1 detL1x;detL2 detL2x]) / denominator;


intersection(2) = det([detL1 detL1y;detL2 detL2y]) / denominator;

end %computeIntersection

%inside() assumes the boundary is oriented counter-clockwise


function in = inside(point,boundary)

pointPositionVector = [diff([point;boundary(1,:)]) 0];


boundaryVector = [diff(boundary) 0];
crossVector = cross(pointPositionVector,boundaryVector);

if ( crossVector(3) <= 0 )
in = true;
else
in = false;
end

end %inside

% % Sutherland-Hodgman Algorithm

clippedPolygon = subjectPolygon;
numVerticies = size(clipPolygon,1);
clipVertexPrevious = clipPolygon(end,:);

for clipVertex = (1:numVerticies)


if ~isempty(clippedPolygon)
clipBoundary = [clipPolygon(clipVertex,:) ; clipVertexPrevious];

inputList = clippedPolygon;

clippedPolygon = [];
previousVertex = inputList(end,:);

for subjectVertex = (1:size(inputList,1))

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,:);

Apéndice F. Códigos Fuente 162


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

elseif( inside(previousVertex,clipBoundary) )
subjectLineSegment = [previousVertex;inputList(subjectVertex,:)];
clippedPolygon(end+1,1:2) = computeIntersection(clipBoundary,subjectLineSegment);
end

previousVertex = inputList(subjectVertex,:);
clipVertexPrevious = clipPolygon(clipVertex,:);

end %for subject verticies


end %if not empty
end %for boundary verticies
end %sutherlandHodgman algorithm

F.3. Cálculo de Energı́a Cinética y RMS de las Fluctuaciones


F.3.1. plotEnergy.m

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’;

Apéndice F. Códigos Fuente 163


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

cacheFolder = ’/media/Datos/Pablo/Workspace/tmp/cache/0.045’;

% Actuation p90 - g4 - From step 1 to 50 (noAct) and 51 to 900 (act)


settings.name = ’p90_rate1_g4_q1.4_including_noactuation’;
%settings.folder = ’/Users/invitado/tmp/TESIS_RESULTS/16_KEGERISE_LAGRANGE_p90_g4_1.4_1.4_1.4_1.4/CHR.
ENSIGHT.01031126’;
settings.folder = ’/media/Datos/Pablo/Workspace/Saturne/TESIS_RESULTS/16_KEGERISE_LAGRANGE_p90_g4_1.4_1
.4_1.4_1.4_7000steps/CHR.ENSIGHT.03262049’;
settings.filerangeFilter.min = 1;
settings.filerangeFilter.max = Inf;
settings.clipArea.x1 = -5;
settings.clipArea.y1 = -5;
settings.clipArea.x2 = 20;
settings.clipArea.y2 = 5;
ntchr = 10;

integrationArea = struct(’x1’, -5, ’y1’, -5, ’x2’, 20, ’y2’, 5);

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’);

geoCacheFilename = sprintf(’geo.cache.xyStep. %.3f.mat’, xyStep);


if exist(geoCacheFilename, ’file’)
fprintf(’Loading geo files from cache ( %s)\n’, geoCacheFilename);
result = load(geoCacheFilename);
geo = result.geo;
geoXY = result.geoXY;
clear result;
else
fprintf(’Computing geo data\n’);
geo = chrReadBinaryGeo(geoFilepath);
fprintf(’Computing geoXY data\n’);
tic;
geoXY = geoTransformMeshToXYGrid(geo, xyStep);
toc;
fprintf(’Saving geo files to cache ( %s)\n’, geoCacheFilename);
save(geoCacheFilename, ’geo’, ’geoXY’);
end

if any( strcmp(fieldnames(settings), ’clipArea’ ))


clipAreaFlag = sprintf(’.clipped. %.1f. %.1f. %.1f. %.1f’, settings.clipArea.x1, settings.clipArea.y1,
settings.clipArea.x2, settings.clipArea.y2);
else
clipAreaFlag = ’’;
end
velocityXYCacheFilename = sprintf(’ %s/binaries.cache.xy. %s %s.mat’, cacheFolder, settings.name,
clipAreaFlag);
if exist(velocityXYCacheFilename, ’file’)
fprintf(’Loading velocityXY from cache ( %s)\n’, velocityXYCacheFilename);
result = load(velocityXYCacheFilename);
velocityXY = result.velocityXY;
clear result;
else
fprintf(’Cache ’’ %s’’ not found. Computing velocity data\n’, velocityXYCacheFilename);
tic;
velocityXY = chrReadVelocity2D(filepaths, geo, geoXY, settings.clipArea);
toc;
fprintf(’Saving velocityXY to cache ( %s)\n’, velocityXYCacheFilename);
save(velocityXYCacheFilename, ’velocityXY’);
end

Apéndice F. Códigos Fuente 164


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

[xIntegration, yIntegration] = selectIntegrationCoordinates(geoXY, settings.clipArea, integrationArea);


sizeVelocity = [1 1 size(velocityXY.u, 3)];
kineticEnergyPerturb = 0.5 * ((velocityXY.u(xIntegration, yIntegration,:)-repmat(mean(velocityXY.u(
xIntegration, yIntegration,:),3), sizeVelocity)).^2+ ...
(velocityXY.v(xIntegration, yIntegration,:)-repmat(mean(velocityXY.v(
xIntegration, yIntegration,:),3), sizeVelocity)).^2);
clear velocityXY;

kineticEnergyPerturbInt = sum(sum(kineticEnergyPerturb, 1), 2);


stepsQty = size(kineticEnergyPerturbInt, 3);
steps = 1:ntchr:stepsQty*ntchr;
integrationSurface = (integrationArea.x2-integrationArea.x1) * (integrationArea.y2-integrationArea.y1)/
xyStep^2;
kineticEnergyPerturbIntNormalized = reshape(kineticEnergyPerturbInt, stepsQty, 1)/integrationSurface;

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’;

% No Actuation - From step 1000 to step 11100


settings.name = ’noactuation’;
%settings.folder = ’/Users/invitado/tmp/TESIS_RESULTS/11_NO_ACTUATION_R235/CHR.ENSIGHT.01251100’;
settings.folder = ’/media/Datos/Pablo/Workspace/Saturne/TESIS_RESULTS/11_NO_ACTUATION_R235/CHR.ENSIGHT
.01251100’;
settings.filerangeFilter.min = 50;
settings.filerangeFilter.max = 250;
settings.minXToSeekForPeak = 0.5;
settings.minYToSeekForPeak = 0;

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’);

geoCacheFilename = sprintf(’geo.cache.xyStep. %.3f.mat’, xyStep);


if exist(geoCacheFilename, ’file’)
fprintf(’Loading geo files from cache ( %s)\n’, geoCacheFilename);
%result = load(geoCacheFilename);
%geo = result.geo;
%geoXY = result.geoXY;
%clear result;
else
fprintf(’Computing geo data\n’);
geo = chrReadBinaryGeo(geoFilepath);
fprintf(’Computing geoXY data\n’);
tic;
geoXY = geoTransformMeshToXYGrid(geo, xyStep);
toc;
fprintf(’Saving geo files to cache ( %s)\n’, geoCacheFilename);

Apéndice F. Códigos Fuente 165


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

save(geoCacheFilename, ’geo’, ’geoXY’);


end

velocityXYCacheFilename = sprintf(’ %s/binaries.cache.xy. %s.mat’, cacheFolder, settings.name);


if exist(velocityXYCacheFilename, ’file’)
fprintf(’Loading velocityXY from cache ( %s)\n’, velocityXYCacheFilename);
result = load(velocityXYCacheFilename);
velocityXY = result.velocityXY;
clear result;
else
fprintf(’Computing velocity data\n’);
tic;
velocityXY = chrReadVelocity2D(filepaths, geo, geoXY);
toc;
fprintf(’Saving velocityXY to cache ( %s)\n’, velocityXYCacheFilename);
save(velocityXYCacheFilename, ’velocityXY’);
end

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

Apéndice F. Códigos Fuente 166


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

F.3.4. computeReynoldsTensor.m

function [ UxUx ] = computeReynoldsTensor( velocityXY )


% compute <u’x u’x> or <u’y u’y> (use u for <u’x u’x> and v for <u’y u’y>)
% compute <u’x u’x> = <uxux> - <ux><ux> (cell to cell operations)
% notation: U means u’. u means u.
% then: <UxUx> = <uxux> - <ux>.*<ux>

uxux = mean(velocityXY.^2, 3);


ux = mean(velocityXY, 3);
UxUx = uxux - ux.*ux;
end

F.3.5. computeRMS.m

function [ rms ] = computeRMS( velocityXY )


rms = sqrt(mean(velocityXY.^2, 3));
end

F.3.6. selectIntegrationCoordinates.m

function [xIntegration, yIntegration] = selectIntegrationCoordinates(geoXY, clipArea, integrationArea)


xValues = geoXY.gridValues.x(find(geoXY.gridValues.x >= clipArea.x1 & geoXY.gridValues.x <= clipArea.x2
));
yValues = geoXY.gridValues.y(find(geoXY.gridValues.y >= clipArea.y1 & geoXY.gridValues.y <= clipArea.y2
));

xIntegration = find(xValues >= integrationArea.x1 & xValues <= integrationArea.x2);


yIntegration = find(yValues >= integrationArea.y1 & yValues <= integrationArea.y2);
end

F.4. Simulación en Code Saturne


F.4.1. usini1.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
!-------------------------------------------------------------------------------
! Purpose:
! -------

Apéndice F. Códigos Fuente 167


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! User subroutines for input of calculation parameters (Fortran commons).


! These subroutines are called in all cases.
! If the Code_Saturne GUI is used, this file is not required (but may be
! used to override parameters entered through the GUI, and to set
! parameters not accessible through the GUI).
! Several routines are present in the file, each destined to defined
! specific parameters.
! To modify the default value of parameters which do not appear in the
! examples provided, code should be placed as follows:
! - usipsu for numerical and physical options
! - usipes for input-output related options
! As a convention, "specific physics" defers to the following modules only:
! pulverized coal, gas combustion, electric arcs.
!===============================================================================
subroutine usipph &
!================
( nphmax, nphas , iihmpu, nfecra , iturb , icp , iverif )
!===============================================================================
! Purpose:
! --------
! User subroutine for input of parameters depending on the number of phases.
!-------------------------------------------------------------------------------
! Arguments
!__________________.____._____.________________________________________________.
! name !type!mode ! role !
!__________________!____!_____!________________________________________________!
! nphmax ! i ! <-- ! maximum number of phases !
! 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 !
! iturb(nphmax) ! ia ! <-> ! turbulence model !
! icp(nphmax) ! ia ! <-> ! flag for uniform Cp or not !
! 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, nphas, iihmpu, nfecra
integer iturb(nphmax), icp(nphmax)
integer iverif

! 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

! --- Variable specific heat (ICP=1) or not (ICP=0)


! for each phase IPHAS
! For these specific physics, ICP MUST NOT BE MODIFIED here, and the
! following options are forced:
! coal and combustion: constant CP constant;

Apéndice F. Códigos Fuente 168


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! electric arcs: variable CP.

! Caution: complete usphyv with the law defining Cp


! ========= if and only if variable Cp has been selected here
! (with icp(iphas)=1)
iphas = 1
icp(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.

Apéndice F. Códigos Fuente 169


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

!-------------------------------------------------------------------------------
! 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 &

Apéndice F. Códigos Fuente 170


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

!================
( 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

! --- Velocity/pressure coupling (0 : classical algorithm,


! 1 : transient coupling)
! Only in single-phase
ipucou = 0

! --- Handling of hydrostatic pressure


! (0 : usual algorithm
! 1 : specific handling)
! Only in single-phase
iphydr = 0

Apéndice F. Códigos Fuente 171


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! --- Estimators for Navier-Stokes (non-frozen velocity field)


! We recommend running a calculation restart on a few time steps
! with the activation of the most interesting of those.
! (=2 to activate, =0 to deactivate).
iphas = 1
iescal(iescor,iphas) = 0
iescal(iestot,iphas) = 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

Apéndice F. Códigos Fuente 172


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! --- Reference time step


! The example given below is probably not adapted to your case.
! the dt variable should complain with the {{CourantFriedrichsLewy (CFL) condition in order to avoid
divergency.
! u*dt/dx <= C
! being C an dimensionless constant depending on the solver algorithm.
!
! the condition can be also written as
! dt/(dx^2*re) <= C2
dtref = 0.061d0

! --- 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

! --- Calculation (restart) with frozen velocity field (1 yes, 0 no)


iccvfg = 0

! --- Vortex method for inlet conditions in L.E.S.


! (0: not activated, 1: activated)
! The vortex method only regards the L.E.S. models
! and is only valid with one phase.
! To use the vortex method, edit the ’usvort.f90’ user file.

! --- Convective scheme

! blencv = 0 for upwind (order 1 in space, "stable but diffusive")


! = 1 for centered/second order (order 2 in space)
! we may use intermediate real values.
! Here we choose:
! for the velocity of phase 1 and user scalars:
! an upwind-centered scheme with 100 % centering (blencv=1)
! for other variables
! the default code value (upwind standard, centered in LES)

! Specifically, for user scalars


! if we suspect an excessive level of numerical diffusion on
! a variable ivar representing a user scalar
! iscal (with ivar=isca(iscal)), it may be useful to set
! blencv(ivar) = 1.0d0 to use a second-order scheme in space for
! convection. For temperature or enthalpy in particular, we
! may thus choose in this case:
! blencv(isca(iscalt(iphas))) = 1.0d0

! For non-user scalars relative to specific physics (coal, combustion,


! electric arcs: see usppmo) implicitly defined by the model,
! the corresponding information is set automatically elsewhere:
! we do not modify blencv here.
iphas = 1
blencv(iu(iphas)) = 1.0d0
blencv(iv(iphas)) = 1.0d0
blencv(iw(iphas)) = 1.0d0
if (nscaus.ge.1) then
do ii = 1, nscaus
! first order diffusivity : blencv(isca(ii)) = 0.0d0
! second order diffusivity : blencv(isca(ii)) = 1.0d0
blencv(isca(ii)) = 0.0d0
idiff(isca(ii)) = 0.0d0
enddo
endif

! --- Linear solver parameters (for each unknown)


! iresol = -1: default

Apéndice F. Códigos Fuente 173


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! iresol = 1000*ipol +j: ipol is the degree of the Neumann polynomial


! used for preconditioning,
! j = 0: conjugate gradient,
! j = 1: Jacobi
! j = 2: bi-CgStab
! nitmax: maximum number of iterations for each unknown ivar
! epsilo: relative precision for the solution of the linear system.

! --- Algebraic multigrid parameters

! 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

! --- Reference fluid properties (for each phase)

! ro0 : density in kg/m3


! viscl0 : dynamic viscosity in kg/(m s)
! cp0 : specific heat in J/(degres kg)
! t0 : reference temperature in Kelvin
! p0 : total reference pressure in Pascal
! the calculation is based on a
! reduced pressure P*=Ptot-ro0*g.(x-xref)
! (except in compressible case)
! xyzp0(3,.) : coordinates of the reference point for
! the total pressure (where it is equal to p0)

! In general, it is not necessary to furnish a reference point xyz0.


! If there are outlets, the code will take the center of the
! reference outlet face.
! On the other hand, if we plan to explicitly fix Dirichlet conditions
! for pressure, it is better to indicate to which reference the
! values relate (for a better resolution of reduced pressure).

! Other properties are given by default in all cases.

! Nonetheless, we may note that:

! In the standard case (no gas combustion, coal, electric arcs,


! compressibility):
! ---------------------
! ro0, viscl0 and cp0
! are useful and represent either the fluid properties if they
! are constant, either simple mean values for the initialization
! if properties are variable and defined in usphyv.
! t0 is not useful
! p0 is useful but is not used in an equation of state. p0
! is a reference value for the incompressible solver
! which will serve to set the (possible) domain outlet pressure.
! We may also take it as 0 or as a physical value in Pascals.

! 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,

Apéndice F. Códigos Fuente 174


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! when it is constant, or a value which will be used during


! initializations (or in inlet turbulence conditions,
! depending on the user choice.
! cp0 is indispensable: it is the heat capacity, assumed constant
! in the thermodynamics available by default
! t0 is indispensable and must be in Kelvin (> 0).
! p0 is indispensable and must be in Pascal (> 0).
! With the thermodynamic law available by default,
! t0 and p0 are used for the initialization of the density.
! xyzp0 is not useful because the pressure variable directly
! represents the total pressure.

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

! We only specify XYZ0 if we explicitely fix Dirichlet conditions


! for the pressure.
! xyzp0(1,iphas) = 0.d0
! xyzp0(2,iphas) = 0.d0
! xyzp0(3,iphas) = 0.d0

! --- irovar, ivivar: density and viscosity constant or not ?

! When a specific physics module is active


! (coal, combustion, electric arcs, compressible: see usppmo)
! we DO NOT set variables ’irovar’ and ’ivivar’ here, as
! they are defined automatically.
! Nonetheless, for the compressible case, ivivar may be modified
! in the uscfx1 user subroutine.

! When no specific physics module is active, it is necessary to


! specify is the density and the molecular viscosity
! are constant (irovar=0, ivivar=0)
! or variable (irovar=1, ivivar=1)

! if they are variable, the law must be defined in usphyv;


! if they are constant, they take values ro0 and viscl0.

! as an example, we assume below that they are constant.

iphas = 1
irovar(iphas) = 0
ivivar(iphas) = 0

! --- Reference diffusivity visls0 in kg/(m s) for each


! USER scalar except those which represent the variance of another.

! For non-user scalars relative to specific physics (coal, combustion,


! electric arcs: see usppmo) implicitly defined in the model,
! the information is given automatically elsewhere:
! we do not modify visls0 here.

! For user scalars JJ which represent the variance of another user


! scalar, we do not define visls0(jj) here.
! This is the purpose of the test on iscavr(jj) in the example below.
! Indeed the diffusivity of the variance of a scalar is assumed
! identical to that scalar’s diffusivity.

! When no specific physics has been activated


! (coal, combustion, electric arcs) and if a user scalar represents
! the temperature or enthalpy:
! visls0(iscalt(iphas)) = Lambda/Cp

Apéndice F. Códigos Fuente 175


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! Here, as an example, we assign to viscl0 the viscosity of the


! carrier phase, which is fitting for passive tracers which
! follow the fluid.

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

! --- Reference velocity for turbulence initialization (m2/s)


! (useful only with turbulence)
iphas = 1
uref(iphas) = 1.d0

! --- Definition of moments


! (at the most nbmomx moments, correlations of maximum order ndgmox)

! We calculate temporal means of the type <f1*f2*f3*...*fn>


! The fi’s are cell-defined variables (arrays rtp and propce).

! idfmom(i,imom) ientifies the variable fi of moment imom


! if idfmom > 0 it is a resolved variable (rtp)
! if idfmom < 0 it is an auxiliary variable (propce)
! imoold(imom) defined in the case of a restart the number, in the
! previous calculation, of the moment to use to initialize moment
! imom of the new calculation (by default imoold(imom)=imom).
! Value -1 indicates the we must reinitialize moment imom.
! ntdmom(imom) defined the time step at which the moment calculation
! is started.

! 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.

! The test on iutile allows deactivation of the instructions


! (which are only given as an example).

iutile = 0
if (iutile.eq.1) then

! First moment: <u>


imom = 1
iphas = 1
idfmom(1,imom) = iu(iphas)
ntdmom(imom) = 1000
! Second moment: <rho u v>
imom = 2
iphas = 1
idfmom(1,imom) = -irom(iphas)
idfmom(2,imom) = iu(iphas)
idfmom(3,imom) = iv(iphas)
imoold(imom) = -1
ntdmom(imom) = 10000

endif

return
end subroutine

!===============================================================================

Apéndice F. Códigos Fuente 176


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

subroutine usipes &


!================
( nmodpp , iverif )
!===============================================================================
! Purpose:
! --------
! User subroutine for the input of additional user parameters for
! input/output.
!-------------------------------------------------------------------------------
! 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"
!===============================================================================
! Arguments
integer nmodpp
integer iverif
! Local variables
integer ii, iphas, ipp, imom, iutile

! Local variables - LFD


TYPE probes_area
double precision xStart
double precision yStart
double precision xEnd
double precision yEnd
double precision separation
END TYPE

TYPE probes_line
double precision xStart
double precision yStart
double precision xEnd
double precision yEnd
double precision separation
END TYPE

double precision xProbe, yProbe, xSeparationProbe, ySeparationProbe


integer iProbe, iProbeLine, iProbeArea

TYPE(probes_line) probesLines(0)
TYPE(probes_area) probesAreas(2)

! Should define TYPE(probes_area) probesAreas(2)


probesAreas(1) %xStart = 0.0
probesAreas(1) %xEnd = 20.0
probesAreas(1) %yStart = 1.0

Apéndice F. Códigos Fuente 177


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

probesAreas(1) %yEnd = 1.0


probesAreas(1) %separation = 0.5
probesAreas(2) %xStart = 0.0
probesAreas(2) %yStart = -1.0
probesAreas(2) %xEnd = 20.0
probesAreas(2) %yEnd = -1.0
probesAreas(2) %separation = 0.5
!===============================================================================

!===============================================================================
! 1. Input-output (entsor.h)
!===============================================================================
! --- write auxiliary restart file iecaux = 1 yes, 0 no
iecaux = 1

! Frequency of log output


ntlist = 25

! --- post-processing output


! ichrvl: post-processing of the fluid domain (yes 1/no 0)
! ichrbo: post-processing of the domain boundary (yes 1/no 0)
! ichrsy: post-processing of zones coupled with SYRTHES (yes 1/ no 0)
! ichrmd: indicates if the meshes output are:
! 0: fixed, 1: deformable with constant connectivity, ...

! fmtchr: output format, amid


! ’EnSight Gold’, ’MED’, or ’CGNS’
! optchr: options associated with the output format, separated by
! commas, from the following list:
! ’text’ (text format, for EnSight)
! ’binary’ (binary format, default choice)
! ...
ichrvl = 1
ichrbo = 0
ichrsy = 0
ichrmd = 0
fmtchr = ’EnSight Gold’
optchr = ’binary’

! --- chronological output step


! (-1: only one valua at calculation end)
! (strictly positive valeu: output periodicity)
ntchr = 10

! --- history output step


nthist = 1
ntsuit = 100

! --- Number of monitoring points (probes) and their positions


! (limited to ncaptm=100)

! 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

xProbe = probesLines(iProbeLine) %xStart

Apéndice F. Códigos Fuente 178


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

yProbe = probesLines(iProbeLine) %yStart


do while ((((ySeparationProbe.ge.0).and.(yProbe.le.probesLines(iProbeLine) %yEnd)) &
.or.((ySeparationProbe.lt.0).and.(yProbe.ge.probesLines(iProbeLine) %yEnd))) &
.and.(((xSeparationProbe.ge.0).and.(xProbe.le.probesLines(iProbeLine) %xEnd)) &
.or.((xSeparationProbe.lt.0).and.(xProbe.ge.probesLines(iProbeLine) %xEnd))))

iProbe = iProbe + 1
xyzcap(1,iProbe) = xProbe
xyzcap(2,iProbe) = yProbe
xyzcap(3,iProbe) = 0.00d0

yProbe = yProbe + ySeparationProbe


xProbe = xProbe + xSeparationProbe
end do
end do

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)

xProbe = probesAreas(iProbeArea) %xStart


do while (((xSeparationProbe.ge.0).and.(xProbe.le.probesAreas(iProbeArea) %xEnd)) &
.or.((xSeparationProbe.lt.0).and.(xProbe.ge.probesAreas(iProbeArea) %xEnd)))

yProbe = probesAreas(iProbeArea) %yStart


do while (((ySeparationProbe.ge.0).and.(yProbe.le.probesAreas(iProbeArea) %yEnd)) &
.or.((ySeparationProbe.lt.0).and.(yProbe.ge.probesAreas(iProbeArea) %yEnd)))

iProbe = iProbe + 1
xyzcap(1,iProbe) = xProbe
xyzcap(2,iProbe) = yProbe
xyzcap(3,iProbe) = 0.00d0

yProbe = yProbe + ySeparationProbe


end do
xProbe = xProbe + xSeparationProbe
end do
end do
ncapt = iProbe

! --- current variable


! As for other variables,
! if we do not assign the following array values,
! default values will be used
! nomvar( ) = variable name
! ichrvr( ) = chonological output (yes 1/no 0)
! ilisvr( ) = logging in listing (yes 1/no 0)
! ihisvr( ) = history output (number of probes and their numbers)
! if ihisvr(.,1) = -1, output for all probes
! Note: Only the fist 8 characters of a name will be used in the most
! detailed log.
iphas = 1

!ex ! pressure variable


ipp = ipprtp(ipr (iphas))
nomvar(ipp) = ’Pressure’
ichrvr(ipp) = 1
ilisvr(ipp) = 1
ihisvr(ipp,1) = -1

!ex ! variable v1x


ipp = ipprtp(iu (iphas))
nomvar(ipp) = ’VelocityX’
ichrvr(ipp) = 1
ilisvr(ipp) = 1
ihisvr(ipp,1) = -1

!ex ! v1y variable

Apéndice F. Códigos Fuente 179


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

ipp = ipprtp(iv (iphas))


nomvar(ipp) = ’VelocityY’
ichrvr(ipp) = 1
ilisvr(ipp) = 1
ihisvr(ipp,1) = -1

!ex ! v1z variable


ipp = ipprtp(iw (iphas))
nomvar(ipp) = ’VelocityZ’
ichrvr(ipp) = 1
ilisvr(ipp) = 1
ihisvr(ipp,1) = -1

! User scalar variables.


! We may modify here the arrays relative to user scalars, but scalars
! reserved for specific physics are handled automatically. This explains
! the tests on ’nscaus’, which ensure that the targeted scalars are
! truly user scalars.
! By specific physics, we mean only those which are handled in specific
! modules of the code, such as coal, combustion, electric arcs (see usppmo).

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),

Apéndice F. Códigos Fuente 180


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! and composite types (ex: ra real array)


! mode: <-- input, --> output, <-> modifies data, --- work array
!===============================================================================
implicit none
! Arguments
integer ncel , ncelet, nfac , nfabor, nnod
integer longia, longra
integer nideve, nituse, nrdeve, nrtuse
!===============================================================================

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.

Apéndice F. Códigos Fuente 181


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! string may contain:


! - references to colors (ex.: 1, 8, 26, ...)
! - references to groups (ex.: inlet, group1, ...)
! - geometric criteria (ex. x < 0.1, y >= 0.25, ...)
! These criteria may be combined using logical operators (’and’, ’or’) and
! parentheses.
! Example: ’1 and (group2 or group3) and y < 1’ will select boundary faces
! of color 1, belonging to groups ’group2’ or ’group3’ and with face center
! coordinate y less than 1.
! Operators priority, from highest to lowest:
! ’( )’ > ’not’ > ’and’ > ’or’ > ’xor’
! Similarly, interior faces and cells can be identified using the ’getfac’
! and ’getcel’ subroutines (respectively). Their syntax are identical to
! ’getfbr’ syntax.
! For a more thorough description of the criteria syntax, it can be referred
! to the user guide.
! Boundary condition types
! ========================
! Boundary conditions may be assigned in two ways.
! For "standard" boundary conditions:
! -----------------------------------
! (inlet, free outlet, wall, symmetry), one defines a code in the ’itypfb’
! array (of dimensions number of boundary faces, number of phases).
! This code will then be used by a non-user subroutine to assign the
! following conditions (scalars in particular will receive the conditions
! of the phase to which they are assigned). Thus:

! Code | Boundary type


! --------------------------
! ientre | Inlet
! isolib | Free outlet
! isymet | Symmetry
! iparoi | Wall (smooth)
! iparug | Rough wall

! These integers are defined elsewhere (in paramx.h header).


! Their value is greater than or equal to 1 and less than or equal to
! ntypmx (value fixed in paramx.h)

! In addition, some values must be defined:

! - Inlet (more precisely, inlet/outlet with prescribed flow, as the flow


! may be prescribed as an outflow):
! -> Dirichlet conditions on variables other than pressure are mandatory
! if the flow is incoming, optional if the flow is outgoing (the code
! assigns zero flux if no Dirichlet is specified); thus,
! at face ’ifac’, for the variable ’ivar’: rcodcl(ifac, ivar, 1)

! - Smooth wall: (= impermeable solid, with smooth friction)


! -> Velocity value for sliding wall if applicable
! at face ifac, rcodcl(ifac, iu, 1)
! rcodcl(ifac, iv, 1)
! rcodcl(ifac, iw, 1)
! -> Specific code and prescribed temperature value at wall if applicable:
! at face ifac, icodcl(ifac, ivar) = 5
! rcodcl(ifac, ivar, 1) = prescribed temperature
! -> Specific code and prescribed flux value at wall if applicable:
! at face ifac, icodcl(ifac, ivar) = 3
! rcodcl(ifac, ivar, 3) = prescribed flux

! Note that the default condition for scalars (other than k and epsilon)
! is homogeneous Neumann.

! - Rough wall: (= impermeable solid, with rough friction)


! -> Velocity value for sliding wall if applicable
! at face ifac, rcodcl(ifac, iu, 1)
! rcodcl(ifac, iv, 1)
! rcodcl(ifac, iw, 1)
! -> Value of the dynamic roughness height to specify in
! rcodcl(ifac, iu, 3)

Apéndice F. Códigos Fuente 182


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! -> Value of the scalar roughness height (if required) to specify in


! rcodcl(ifac, iv, 3) (values for iw are not used)
! -> Specific code and prescribed temperature value at wall if applicable:
! at face ifac, icodcl(ifac, ivar) = 6
! rcodcl(ifac, ivar, 1) = prescribed temperature
! -> Specific code and prescribed flux value at rough wall, if applicable:
! at face ifac, icodcl(ifac, ivar) = 3
! rcodcl(ifac, ivar, 3) = prescribed flux
! Note that the default condition for scalars (other than k and epsilon)
! is homogeneous Neumann.

! - Symmetry (= slip wall):


! -> Nothing to specify

! - Free outlet (more precisely free inlet/outlet with prescribed pressure)


! -> Nothing to prescribe for pressure and velocity. For scalars and
! turbulent values, a Dirichlet value may optionally be specified.
! The behavior is as follows:
! * pressure is always handled as a Dirichlet condition
! * if the mass flow is inflowing:
! one retains the velocity at infinity
! Dirichlet condition for scalars and turbulent values
! (or zero flux if the user has not specified a
! Dirichlet value)
! if the mass flow is outflowing:
! one prescribes zero flux on the velocity, the scalars,
! and turbulent values
! Note that the pressure will be reset to p0 on the first free outlet
! face found

! For "non-standard" conditions:


! ------------------------------
! Other than (inlet, free outlet, wall, symmetry), one defines
! - on one hand, for each face:
! -> an admissible ’itypfb’ value (i.e. greater than or equal to 1 and
! less than or equal to ntypmx; see its value in paramx.h).
! The values predefined in paramx.h:
! ’ientre’, ’isolib’, ’isymet’, ’iparoi’, ’iparug’ are in this range,
! and it is preferable not to assign one of these integers to ’itypfb’
! randomly or in an inconsiderate manner. To avoid this, one may use
! ’iindef’ if one wish to avoid checking values in paramx.h. ’iindef’
! is an admissible value to which no predefined boundary condition
! is attached.
! Note that the ’itypfb’ array is reinitialized at each time step to
! the non-admissible value of 0. If one forgets to modify ’typfb’ for
! a given face, the code will stop.
! - and on the other hand, for each face and each variable:
! -> a code icodcl(ifac, ivar)
! -> three real values rcodcl(ifac, ivar, 1)
! rcodcl(ifac, ivar, 2)
! rcodcl(ifac, ivar, 3)
! The value of ’icodcl’ is taken from the following:
! 1: Dirichlet (usable for any variable)
! 3: Neumann (usable for any variable)
! 4: Symmetry (usable only for the velocity and components of
! the Rij tensor)
! 5: Smooth wall (usable for any variable except for pressure)
! 6: Rough wall (usable for any variable except for pressure)
! 9: Free outlet (usable only for velocity)
! The values of the 3 ’rcodcl’ components are:
! rcodcl(ifac, ivar, 1):
! Dirichlet for the variable if icodcl(ifac, ivar) = 1
! Wall value (sliding velocity, temp) if icodcl(ifac, ivar) = 5
! The dimension of rcodcl(ifac, ivar, 1) is that of the
! resolved variable: ex U (velocity in m/s),
! T (temperature in degrees)
! H (enthalpy in J/kg)
! F (passive scalar in -)
! rcodcl(ifac, ivar, 2):
! "exterior" exchange coefficient (between the prescribed value

Apéndice F. Códigos Fuente 183


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! and the value at the domain boundary)


! rinfin = infinite by default
! For velocities U, in kg/(m2 s):
! rcodcl(ifac, ivar, 2) = (viscl+visct) / d
! For the pressure P, in s/m:
! rcodcl(ifac, ivar, 2) = dt / d
! For temperatures T, in Watt/(m2 degres):
! rcodcl(ifac, ivar, 2) = Cp*(viscls+visct/sigmas) / d
! For enthalpies H, in kg /(m2 s):
! rcodcl(ifac, ivar, 2) = (viscls+visct/sigmas) / d
! For other scalars F in:
! rcodcl(ifac, ivar, 2) = (viscls+visct/sigmas) / d
! (d has the dimension of a distance in m)
!
! rcodcl(ifac, ivar, 3) if icodcl(ifac, ivar) <> 6:
! Flux density (< 0 if gain, n outwards-facing normal)
! if icodcl(ifac, ivar)= 3
! For velocities U, in kg/(m s2) = J:
! rcodcl(ifac, ivar, 3) = -(viscl+visct) * (grad U).n
! For pressure P, in kg/(m2 s):
! rcodcl(ifac, ivar, 3) = -dt * (grad P).n
! For temperatures T, in Watt/m2:
! rcodcl(ifac, ivar, 3) = -Cp*(viscls+visct/sigmas) * (grad T).n
! For enthalpies H, in Watt/m2:
! rcodcl(ifac, ivar, 3) = -(viscls+visct/sigmas) * (grad H).n
! For other scalars F in:
! rcodcl(ifac, ivar, 3) = -(viscls+visct/sigmas) * (grad F).n

! rcodcl(ifac, ivar, 3) if icodcl(ifac, ivar) = 6:


! Roughness for the rough wall law
! For velocities U, dynamic roughness
! rcodcl(ifac, iu, 3) = roughd
! For other scalars, thermal roughness
! rcodcl(ifac, iv, 3) = rought

! Remarks
! =======

! Caution: to prescribe a flux (nonzero) to Rij, the viscosity to take


! into account is viscl even if visct exists
! (visct=rho cmu k2/epsilon)

! 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.

! Note how to access some variables (for phase ’iphas’


! variable ’ivar’
! scalar ’iscal’):

! Cell values (let iel = ifabor(ifac))

! * Density: propce(iel, ipproc(irom(iphas)))


! * Dynamic molecular viscosity: propce(iel, ipproc(iviscl(iphas)))
! * Turbulent viscosity: propce(iel, ipproc(ivisct(iphas)))
! * Specific heat: propce(iel, ipproc(icp(iphas))
! * Diffusivity(lambda): propce(iel, ipproc(ivisls(iscal)))

! Boundary face values

! * Density: propfb(ifac, ipprob(irom(iphas)))


! * Mass flux (for convecting ’ivar’): propfb(ifac, ipprob(ifluma(ivar)))

! * For other values: take as an approximation the value in the adjacent cell
! i.e. as above with iel = ifabor(ifac).

!-------------------------------------------------------------------------------

Apéndice F. Códigos Fuente 184


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! 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, *) ! ! ! !

Apéndice F. Códigos Fuente 185


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

! rcodcl ! ra ! --> ! boundary condition values !


! (nfabor,nvar,3) ! ! ! rcodcl(1) = Dirichlet value !
! ! ! ! rcodcl(2) = exterior exchange coefficient !
! ! ! ! (infinite if no exchange) !
! ! ! ! rcodcl(3) = flux density value !
! ! ! ! (negative for gain) in w/m2 or !
! ! ! ! roughness height (m) if icodcl=6 !
! ! ! ! for velocities ( vistl+visct)*gradu !
! ! ! ! for pressure dt*gradp !
! ! ! ! for scalars cp*(viscls+visct/sigmas)*gradt !
! w1,2,3,4,5,6 ! ra ! --- ! work arrays !
! (ncelet) ! ! ! (computation of pressure gradient) !
! coefu ! ra ! --- ! work array !
! (nfabor, 3) ! ! ! (computation of pressure gradient) !
! rdevel(nrdeve) ! ra ! <-> ! real work array for temporary development !
! rtuser(nrtuse) ! ra ! <-> ! user-reserved real work array !
! ra(*) ! ra ! --- ! main real work array !
!__________________!____!_____!________________________________________________!

! 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 "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

integer ifacel(2,nfac) , ifabor(nfabor)


integer ifmfbr(nfabor) , ifmcel(ncelet)
integer iprfml(nfml,nprfml), maxelt, lstelt(maxelt)
integer ipnfac(nfac+1), nodfac(lndfac)
integer ipnfbr(nfabor+1), nodfbr(lndfbr)
integer icodcl(nfabor,nvar)
integer itrifb(nfabor,nphas), itypfb(nfabor,nphas)
integer idevel(nideve), ituser(nituse), ia(*)

double precision xyzcen(ndim,ncelet)


double precision surfac(ndim,nfac), surfbo(ndim,nfabor)
double precision cdgfac(ndim,nfac), cdgfbo(ndim,nfabor)
double precision xyznod(ndim,nnod), volume(ncelet)
double precision dt(ncelet), rtp(ncelet,*), rtpa(ncelet,*)
double precision propce(ncelet,*)
double precision propfa(nfac,*), propfb(nfabor,*)
double precision coefa(nfabor,*), coefb(nfabor,*)
double precision rcodcl(nfabor,nvar,3)
double precision w1(ncelet),w2(ncelet),w3(ncelet)
double precision w4(ncelet),w5(ncelet),w6(ncelet)
double precision coefu(nfabor,ndim)
double precision rdevel(nrdeve), rtuser(nrtuse), ra(*)

! Local variables
integer idebia, idebra

Apéndice F. Códigos Fuente 186


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

integer ifac, iel, ii, ivar, iphas


integer ilelt, nlelt
double precision uref2, d2s3
double precision rhomoy, dh, ustar2
double precision xintur
double precision xkent, xeent

! Local Variables - LFD


double precision alfa, beta
double precision xCentre, yCentre
character*10 sStepNumber
character*10 sProcessorNumber
integer, parameter:: actuatorStartingStep = 7500
real, parameter :: inputVelocity = 1d0
real :: upperActuatorValue, lowerActuatorValue
logical, save:: actuatorValuesInitialized = .false.
!===============================================================================

!===============================================================================
! 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)

call system("./controller "//sProcessorNumber//" act.upper.csv."//sProcessorNumber &


//" act.lower.csv."//sProcessorNumber//" probes_Scalar1.dat < semaphore."//sProcessorNumber//" &")
open(unit=103, file="semaphore."//sProcessorNumber, action="write")
open(unit=104, file="act.upper.csv."//sProcessorNumber, action="read")
open(unit=105, file="act.lower.csv."//sProcessorNumber, action="read")

actuatorValuesInitialized = .true.
endif

idebia = idbia0
idebra = idbra0

d2s3 = 2.d0/3.d0

!===============================================================================
! 2. Assign boundary conditions to boundary faces here

! One may use selection criteria to filter boundary case subsets


! Loop on faces from a subset
! Set the boundary condition for each face
!===============================================================================

! Code | Boundary type


! --------------------------
! ientre | Inlet
! isolib | Free outlet
! isymet | Symmetry
! iparoi | Wall (smooth)
! iparug | Rough wall

!$PhysicalNames
!1 Layer0
!2 entrada
!3 salida
!4 pared
!5 simetria
!6 interna
!7 actuador
!5 simetria
!$EndPhysicalNames

Apéndice F. Códigos Fuente 187


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

!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

!salida -> isolib


call getfbr(’3’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)
iel = ifabor(ifac)
do iphas = 1, nphas
itypfb(ifac,iphas) = isolib

icodcl(ifac,ipr(iphas)) = 1 !dirichlet condition on pressure -> fixed value


icodcl(ifac,iu(iphas)) = 3 !neumann condition on velocity -> fixed gradient
icodcl(ifac,iv(iphas)) = 3
icodcl(ifac,iw(iphas)) = 3

rcodcl(ifac,ipr(iphas),1) = 0.0d0 !dirichlet value fixed to pressure=0


rcodcl(ifac,iu(iphas),3) = 0.0d0 !neumann value fixed to grad(u,normal) = 0
rcodcl(ifac,iv(iphas),3) = 0.0d0
rcodcl(ifac,iw(iphas),3) = 0.0d0
enddo
enddo

!pared -> iparoi


call getfbr(’4’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)

do iphas = 1, nphas
itypfb(ifac,iphas) = iparoi
enddo
enddo

!simetria -> isymet


call getfbr(’5’, nlelt, lstelt)
do ilelt = 1, nlelt
ifac = lstelt(ilelt)

do iphas = 1, nphas
itypfb(ifac,iphas) = isymet
enddo
enddo

if (ntcabs.ge.actuatorStartingStep) then

write(sStepNumber, ’(i0)’ ) ntcabs

Apéndice F. Códigos Fuente 188


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

!actuador -> iparug


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) = 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

F.5. Identificador del Sistema en Matlab


F.5.1. lfd arx.m

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)=

Apéndice F. Códigos Fuente 189


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

% =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

%segón Ljung, se define el vector de regresión en el tiempo k como:


% fi(k)=(-y(k-1), ...,-y(k-na),u(k), u(k-1),...u(k-(nb-1))’
% y el "vector" de parómetros a calcular mp’=(a_1,...,a_na,_1,...b_nb)

[m,N] = size(y);
[r,N] = size(u);

%se construye fi con los valores de regresión, considerando los tiempos de


%na+1 en adelante
fi = zeros(na*m+nb*r,N);
for j=na+1:N
fi(:,j)=[reshape(-y(:, j-1:-1:j-na), na*m, 1); ...
reshape(u(:, j:-1:j-(nb-1)), nb*r, 1)];
end

%se construye la matriz de regresion


fi2 = fi(:, na+1:end);
reg = zeros(m*size(fi2,1), m*(N-na));
for j=1:N-na
reg(:, 1+(j-1)*m:j*m) = kron(fi2(:,j), eye(m));
end

%REVISAR SIG LINEA


yna = y(:, na+1:end);
Y = reshape(yna, m*(N-na), 1);

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);

%se desecha la parte Q de la matriz F y se resuelve por cuad. mónimos


%th: resultante que contiene los valores para armar las matrices A y B
th = pinv(R1) * R2;

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;

Apéndice F. Códigos Fuente 190


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

F.5.2. lfd compare.m

function [ fit ] = lfd_compare(data, max_steps_to_predict, model)


%LFD_COMPARE Compares a given system identification model against the real data
% Returns the Fit information.

y = pvget(data, ’OutputData’);
y = y{1};
ny = size(y , 2);

y_predicted = predict(model, data, max_steps_to_predict, ’e’);


y_predicted = pvget(y_predicted, ’OutputData’);
y_predicted = y_predicted{1};

fit = zeros(ny, 1);


for ky = 1:ny
err = norm(y_predicted(:, ky) - y(:, ky));
meanerr = norm(y(:, ky) - mean(y(:, ky)));
fit(ky) = 100*(1-err/meanerr);
end

% Original code adapted from the compare function in the System


% Identification toolbox:
% ksys = 1;
% th = model;
% z1 = data;
% m = Inf;
% kexp = 1;
%
% y = pvget(data, ’OutputData’);
% y{1} = y{ksys,kexp};
% [nrow, ny] = size(y{1});
% [nrow, nu] = size(u);
%
% sampizf{1} = 1:nrow;
% ksysinit = ’e’;
%
% [yh{ksys}, x01{ksys}] = predict(th, z1, m, ksysinit);
% yhh = pvget(yh{ksys}, ’OutputData’);
%
% for ky = 1:ny
% kyy = ky;
% err = norm(yhh{kexp}(sampizf{kexp}, kyy) - y{kexp}(sampizf{kexp}, ky));
% meanerr = norm(y{kexp}(sampizf{kexp}, ky) - mean(y{kexp}(sampizf{kexp}, ky)));
% fit(kexp, ksys, ky) = 100*(1-err/meanerr);
% end
end

F.5.3. lfd training actuation.m

function act = lfd_training_actuation(totalSteps, freq_range, amplitude)


% Computes the actuation for a training phase for a given amount of totalSteps. It is possible to
% define amount of random phases of actuation and frequency, modulus, etc. per each.
% Params: totalSteps, amountOfPhases, allowable_freq_range, allowable_modulus_range, stepDifference

s = RandStream.create(’mrg32k3a’,’NumStreams’,1);
RandStream.setDefaultStream(s); %to ensure deterministic output
%randseed(45233); %to ensure deterministic output

act = chirp(1:totalSteps, freq_range(1), totalSteps, freq_range(2))*amplitude;


act = repmat(act’, 1, 2);
end

Apéndice F. Códigos Fuente 191


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

F.5.4. lfd training actuation gaussian.m

function act = lfd_training_actuation_gaussian(peakMagnitude, totalSteps, meanStep, sigma)


% Computes the actuation for a training phase for a given amount of totalSteps. It is possible to
% Params: totalSteps, amountOfPhases, allowable_freq_range, allowable_modulus_range, stepDifference
steps = 1:totalSteps;
act = peakMagnitude * exp(-((steps-meanStep).^2)/(2*sigma^2));
act = repmat(act’, 1, 2);
end

F.5.5. lfd training actuation multiple gaussian.m

function act = lfd_training_actuation_multiple_gaussian(peakMagnitude, totalSteps, meanSteps, sigma)


% Computes the actuation for a training phase for a given amount of totalSteps. It is possible to
% Params: totalSteps, amountOfPhases, allowable_freq_range, allowable_modulus_range, stepDifference
steps = 1:totalSteps;
act = zeros(1, totalSteps);
for ii=1:length(meanSteps)
meanStep = meanSteps(ii);
gaussian = peakMagnitude * exp(-((steps-meanStep).^2)/(2*sigma^2));
act = act + gaussian;
end

act = repmat(act’, 1, 2);


end

F.5.6. lfd training actuation pulse.m

function act = lfd_training_actuation_pulse(pulseMagnitude, delayBeforePulseSteps, pulseSteps,


delayAfterPulseSteps)
% Computes the actuation for a training phase for a given amount of totalSteps. It is possible to
% define amount of random phases of actuation and frequency, modulus, etc. per each.
% Params: totalSteps, amountOfPhases, allowable_freq_range, allowable_modulus_range, stepDifference

s = RandStream.create(’mrg32k3a’,’NumStreams’,1);
RandStream.setDefaultStream(s); %to ensure deterministic output
%randseed(45233); %to ensure deterministic output

totalSteps = delayBeforePulseSteps + pulseSteps + delayAfterPulseSteps;


act = zeros(1, totalSteps);
act(delayBeforePulseSteps+1:delayBeforePulseSteps+pulseSteps) = pulseMagnitude;
act = repmat(act’, 1, 2);
end

F.5.7. lfd training actuation ramp.m

function act = lfd_training_actuation_ramp(peakMagnitude, delayBeforeRampSteps, rampUpSteps, rampDownSteps,


delayAfterRampSteps)
% Computes the actuation for a training phase for a given amount of totalSteps. It is possible to
% Params: totalSteps, amountOfPhases, allowable_freq_range, allowable_modulus_range, stepDifference

totalSteps = delayBeforeRampSteps + rampUpSteps + rampDownSteps + delayAfterRampSteps;


act = zeros(1, totalSteps);
deltaRampUp = 1/rampUpSteps;
deltaRampDown = 1/rampDownSteps;
act(delayBeforeRampSteps+1:delayBeforeRampSteps+rampUpSteps) = peakMagnitude*[deltaRampUp:
deltaRampUp:1];

Apéndice F. Códigos Fuente 192


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

act(delayBeforeRampSteps+rampUpSteps+1:delayBeforeRampSteps+rampUpSteps+rampDownSteps) =
peakMagnitude*[1-deltaRampDown:-deltaRampDown:0];
act = repmat(act’, 1, 2);
end

F.6. Controlador en C++


F.6.1. main.cpp

/*
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"

int main(int argc, char* argv[]) {


if (argc != 5) {
std::cerr << "Se esperaban 4 argumentos. Modo de uso: ./controlador <processor-number> <upper-actuator-
output-file> <lower-actuator-output-file> <probes-pressure-input-file> < semaforo." << std::endl;
return 1;
}
else {
std::string logFilepath;
std::string logPrefix;
std::stringstream converter;
converter << "controlador.log." << argv[1];
converter >> logFilepath;

std::stringstream prefixConverter;
prefixConverter << "[CPU." << argv[1] << "]";
prefixConverter >> logPrefix;

Logger logger(logPrefix, logFilepath);


Parser parser(logger, PROBES_COUNT);
MatlabExecutor matlabExecutor(logger);
logger << "Abriendo archivo actuador alto: ’" << argv[2] << "’." << std::endl;
std::ofstream upperActuator(argv[2]);
logger << "Abriendo archivo actuador bajo: ’" << argv[3] << "’." << std::endl;
std::ofstream lowerActuator(argv[3]);
char* probesPressureFilepath = argv[4];

Apéndice F. Códigos Fuente 193


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

logger << "Tomando semaforo de STDIN..."<< std::endl;


std::istream& semaphore = std::cin;

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);

saturneCommunicator.send(upperActuator, logger, act.upper);


saturneCommunicator.send(lowerActuator, logger, act.lower);
}
else {
logger << "Seóal de cierre recibida. Finalizando..." << std::endl;
continueControl = false;
}
}
return 0;
}
catch(const char* message) {
logger << "ERROR DURING SIMULATION: " << message << std::endl;
return 1;
}
catch(...) {
logger << "UNKNOWN ERROR DURING SIMULATION: " << std::endl;
return 1;
}
}
}

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(){
}

void initialize(const std::string& configurationFilepath) {


std::ifstream keyValuesFile(configurationFilepath.c_str());
if (! keyValuesFile)
throw "There was an error trying to read the configuration file.";
else {
while(keyValuesFile.good()) {
std::string line;
getline(keyValuesFile, line);
trim(line);

Apéndice F. Códigos Fuente 194


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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));
}
}
}

}
}

float getFloat(const std::string& key) {


return get< float >(key);
}

bool getBool(const std::string& key) {


return get< bool >(key);
}

int getInt(const std::string& key) {


return get< int >(key);
}

std::string get(const std::string& key) {


t_keyvalues::iterator it = keyValues.find(key);
if (it == keyValues.end()) {
std::stringstream ss;
ss << "The key ’" << key << "’was not found.";
throw ss.str().c_str();
}
else
return it->second;
}

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 );
}

template < typename T >


T get(const std::string& key) {
std::string value = get(key);
std::stringstream ss;
ss << value;
T result;
ss >> result;
return result;
}
};

#endif

F.6.3. configuration control.txt

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

Apéndice F. Códigos Fuente 195


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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

F.6.4. configuration training.txt

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 LINE_PROBES 11.0 //nLineProbes = 11 check values in usini1.f90


#define SAMPLES_PER_LINE 9.0 //nSamplesPerLine = 9 check values in usini1.f90
#define PROBES_COUNT LINE_PROBES*SAMPLES_PER_LINE
#define X_STEP 1.0 //1 diametre in between line probes

Apéndice F. Códigos Fuente 196


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

#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();

Matrix removeUselessProbeValues(const Matrix& values);


Row removeUselessProbeValues(const Row& values);
void checkInitialized();
void restoreTrainingData();
void saveLastStepInformation(int currentStep, const Actuation& input, const Row& output);
};

#endif

Apéndice F. Códigos Fuente 197


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

F.6.7. Controller.cpp

#include <sstream>
#include <set>
#include "Controller.h"

Controller::Controller(char* processorNumber, Logger& logger, MatlabExecutor& matlabExecutor)


: cummulativeOutputsForModel(0,0), cummulativeOutputs(0,0), cummulativeActuationForModel(0,0),
cummulativeActuation(0,0),
initialized(false), modelAlreadyComputed(false), invocationsCount(0), processorNumber(
processorNumber), logger(logger), matlabExecutor(matlabExecutor) {

void Controller::initialize(const std::string& configurationFilepath) {


this->config.initialize(configurationFilepath);
this->previousActuation.upper = 0;
this->previousActuation.lower = 0;
this->initialized = true;

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;

bool trainingFromStoredData = config.getBool("TRAINING_FROM_STORED_DATA_ENABLED");


bool trainingGeneration = config.getBool("TRAINING_GENERATION_ENABLED");
if (trainingFromStoredData && trainingGeneration || !trainingFromStoredData && !trainingGeneration)
throw "It is neccessary to define whether TRAINING_FROM_STORED_DATA or TRAINING_GENERATION will be used
in the configuration file.";
if (trainingFromStoredData) {
//let trainining to be empty
this->itTrainingActuation = this->trainingActuations.begin();
this->restoreTrainingData();
logger << "Before computing model. CummulativeOutputs Rows: " << cummulativeOutputsForModel.getRows()
<< " - Cols: " << cummulativeOutputsForModel.getColumns() << std::endl;
this->computeModel();
}
else { //trainingGeneration
//Create a training function and use it during the first steps
this->trainingActuations = this->getTrainingActuation();
this->itTrainingActuation = this->trainingActuations.begin();
}
}

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());

Matrix yMatrix = matlabExecutor.getMatrix("y");

Apéndice F. Códigos Fuente 198


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

logger << "Received y data values. Rows: " << yMatrix.getRows() << ". Cols: " << yMatrix.getColumns() <<
std::endl;

cummulativeOutputs = yMatrix;
cummulativeOutputsForModel = yMatrix;

Matrix uMatrix = matlabExecutor.getMatrix("u");


logger << "Received u data values. Rows: " << uMatrix.getRows() << ". Cols: " << uMatrix.getColumns()
<< std::endl;

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();
}
}

std::vector < Actuation > Controller::getTrainingActuation() {


std::stringstream expression;
expression << "training_act = " << config.get("TRAINING_GENERATION_FUNCTION_INVOKE") << ";";
matlabExecutor.evaluate(expression.str());
Matrix trainingAct = matlabExecutor.getMatrix("training_act");
matlabExecutor.evaluate("clear training_act;");
logger << "Received training actuation with " << trainingAct.getRows() << " samples." << std::endl;
if (trainingAct.getColumns() != 2 ) {
logger << "Error computing training actuation values. Expected actuation values per sample: 2 " << std
::endl;
throw "Error computing training actuation values.";
}

std::vector < Actuation > result;


for(size_t i = 0; i < trainingAct.getRows(); ++i) {
result.push_back(this->getActuationFromRow(trainingAct[i]));
}
return result;
}

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());

Apéndice F. Códigos Fuente 199


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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;");

Matrix result = matlabExecutor.getMatrix("next_step_act");


if (result.getRows() != 1) {
logger << "Error computing next actuation value. One actuation was expected. Received actuations: "
<< result.getRows() << std::endl;
throw "Error computing next actuation value. One actuation was expected.";
}
else
return this->getActuationFromRow(result[0]);
}

Actuation Controller::getActuationFromRow(const Row& row) {


unsigned int upperActIndex = config.getInt("ACTUATOR_UPPERVALUE_ARRAYINDEX");
unsigned int lowerActIndex = config.getInt("ACTUATOR_LOWERVALUE_ARRAYINDEX");
unsigned int actIndexMax = (lowerActIndex > upperActIndex) ? lowerActIndex: upperActIndex;
if (row.getColumns() < actIndexMax) {
logger << "Error computing actuation values. Received values do not match the configuration indices for
upper and lower actuator. Available indices: " << row.getColumns() << "Upper index:" <<
upperActIndex << ". Lower index:" << lowerActIndex << std::endl;
throw "Error computing next actuation values. Configuration index mismatch";
}
else {
Actuation act;
act.upper = row[upperActIndex];
act.lower = row[lowerActIndex];
return act;
}
}

void Controller::addOutputsForModelComputation(const Row& lastStepOutputs, const Row& actuation) {


if (! modelAlreadyComputed) {
if (cummulativeActuationForModel.getRows() < config.getInt("COMPUTE_MODEL_STEPS")) {
cummulativeActuationForModel.pushRow(actuation);
cummulativeOutputsForModel.pushRow(lastStepOutputs);
}
if (cummulativeActuationForModel.getRows() == config.getInt("COMPUTE_MODEL_STEPS")) {
this->computeModel();
this->modelAlreadyComputed = true;
}
}
}

Matrix Controller::removeUselessProbeValues(const Matrix& values) {


Matrix normalizedMatrix(0, 0);
for(size_t i = 0; i < values.getRows(); ++i) {

Apéndice F. Códigos Fuente 200


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Row normalizedRow = this->removeUselessProbeValues(values[i]);


normalizedMatrix.pushRow(normalizedRow);
}
if (values.getRows() > 0) {
logger << "Normalization finished. Input amount of samples for first line. Original:" << values[0].
getColumns() << " normalized:" << normalizedMatrix[0].getColumns() << std::endl;
}
return normalizedMatrix;
}

Row Controller::removeUselessProbeValues(const Row& values) {


Row normalizedRow(0);
for(size_t i = 0; i < values.getColumns(); ++i) {
if (probesToUse.end() != probesToUse.find(i + 1)) {
normalizedRow.pushCell(values[i]);
}
}
return normalizedRow;
}

void Controller::saveLastStepInformation(int currentStep, const Actuation& input, const Row& output) {


this->inputsLogFile << currentStep << ’,’ << input.upper << ’,’ << input.lower << std::endl;
this->outputsLogFile << currentStep;
for(size_t i = 0; i < output.getColumns(); ++i) {
this->outputsLogFile << ’,’ << output[i];
}
this->outputsLogFile << std::endl;
}

Actuation Controller::getActuationFor(int currentStep, const Row& lastStepOutputs) {


Row lastStepOutputsNormalized = this->removeUselessProbeValues(lastStepOutputs);

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);

if (cummulativeOutputs.getRows() > config.getInt("CONTROL_PREDICTION_MAX_STEPS")) {


size_t indexFrom = cummulativeOutputs.getRows() - config.getInt("CONTROL_PREDICTION_MAX_STEPS");
cummulativeOutputs = cummulativeOutputs.submatrixByRows(indexFrom, cummulativeOutputs.getRows() -1);
cummulativeActuation = cummulativeActuation.submatrixByRows(indexFrom, cummulativeActuation.getRows()
-1);
}
logger << "Finished: Calculating actuation for step: " << currentStep << std::endl;
}
++this->invocationsCount;
this->previousActuation = act;
this->saveLastStepInformation(currentStep, act, lastStepOutputs);
return act;
}

F.6.8. Logger.h

#ifndef LOGGER__

Apéndice F. Códigos Fuente 201


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

#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;
}

template< typename T >


Logger& operator<<(const T& msg){
if (includePrefix) {
this->file << this->prefix;
std::cout << this->prefix;
includePrefix = false;
}
this->file << msg;
this->file.flush();
std::cout << msg;
std::cout.flush();
return *this;
}
Logger& operator<<(ostream_manipulator pf)
{
this->includePrefix = true;
pf(this->file);
pf(std::cout);
return *this;
}

};

#endif

F.6.9. lfd control lagrange init.m

function [ control_state ] = lfd_control_lagrange_init(y, u, p, gamma, A, B, limits, q)


%Parameters:
% y: m*N matrix with the output values
% u: r*N matrix with inputs
% p: orden del modelo ARX
% A: m*m*(p+1). ARX coefficient matrix
% B: m*r*(p+1). ARX coefficient matrix
% q: m*s weights vector. Should have values between 0 and 1. Q=diag(q) will
% gamma: actuation cost
% be used for the control iteration
% where N: observations count
%
% Usage example:
% [A, B] = lfd_arx(y, u, 2);
% limits.min_value = 0;
% limits.max_value = 3;
% control_state = lfd_control_lagrange_init(y, u, 2, 0.99999, 1/625000, A, B, limits, ones(1,sizeof(y,2)))
;
% next_actuation = lfd_control_lagrange(control_state, y, u);

Apéndice F. Códigos Fuente 202


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

%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

%m: y components count


%r: u components count
m = size(y,1);
r = size(u,1);

%s: prediction horizont (should be between 2 and 3 times ’p’)


s=3*p;

% k should match the following rule to allow vp collection: k-p >=1,


k = size(y,2);
if k-p < 1
error(’lfd_control:k_validation’, ’Arguments error. TimeStep and Order should match the following rule:
k-p>=1. k: %d,p: %d’, k, p);
end

%Since Matlab ARX convention includes ’y’ coefficients on the right


%side, starting with the identity matrix, we should re-arrange the info
a = -A(:,:,2:end);
b = B;

% Being y(k) = a_1*y(k-1)+a_2*y(k-2)+...a_p*y(k-p) +


% b_0*u(k)+b_1*u(k-1)+...+b_p*u(k-p)
% The markov parameters can be defined as:
% alpha_1^0 = a_1,..., alpha_1^k = a_1 if k = 0
% ..., alpha_1^k = a_k+1 + sum_1^k(a_i*alpha_1^k-i) if k = 1, 2, .. p-1
% ..., alpha_1^k = sum_1^p(a_i*alpha_1^k-i) if k = p, p+1, ...
% beta_0^0 = b_0,..., beta_0^k = b_0 if k = 0
% ..., beta_0^k = b_k + sum_1^k(a_i*beta_0^k-i) if k = 1, 2, .. p
% ..., beta_0^k = sum_1^p(a_i*beta_0^k-i) if k = p+1,
% p+2, ..
beta00 = b(:,:,1);
beta0 = zeros(m, r, s-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;

Apéndice F. Códigos Fuente 203


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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 y phi se definen a partir de los parómetros de markov que se encuentran en A y B


T=zeros(m*s,r*s);
T_column =zeros(m*s,r);

T_column(1:m,:)=beta00;
for j=2:s;
T_column((j-1)*m+1:j*m,:)=beta0(:,:,j-1);
end;

for column = 1:s


T(m*(column-1)+1:m*s, r*(column-1)+1:r*column) = T_column(1:(m*s - (column-1)*m),:);
end;

% phi: [alpha_1^0 ... alpha_p^0 beta_1^0 ... beta_p^0 ;


% ... ;
% alpha_1^s-1 ... alpha_p^s-1 beta_1^s-1 ... beta_p^s-1]
%
% alpha_k^j = alpha_1^j-1 * a_k + alpha_k+1^j-1 if k= 1, 2, .., p-1
% alpha_1^j-1 * a_k if k= p
% beta_k^j = alpha_1^j-1 * b_k + beta_k+1^j-1 if k= 1, 2, .., p-1
% alpha_1^j-1 * b_k if k= p
phi=zeros(m*s,p*(m+r));

% The variables bellow adopt the following syntax:


% a(:,:,subIndex) -> a_subIndex == alpha_subIndex^0
% b(:,:,subIndex+1) -> b_subIndex == beta_subIndex^0
% alpha(:,:,superIndex,subIndex) -> alpha_subIndex^superIndex
% beta(:,:,superIndex,subIndex) -> beta_subIndex^superIndex
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

Apéndice F. Códigos Fuente 204


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

phi(1:m,:) = [reshape(a, m, m*p) reshape(b(:,:,2:end), m, r*p)];


for j=2:s
phi((j-1)*m+1:j*m,:) = [reshape(alpha(:,:,j-1,:), m, m*p) reshape(beta(:,:,j-1,:), m, r*p)];
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

F.6.10. lfd control lagrange.m

function control_state = lfd_control_lagrange(control_state, y,u)

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;

%Finally: u_s = K*vp


%where u_s:control value from k to k+s-1
%So, lets take the first r values to compute only u_s(k)
u_k = K_r * vp;

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;
end

Apéndice F. Códigos Fuente 205


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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(Logger& logger) : logger(logger) {


logger << "Opening engine..." << std::endl;
if (!(ep = engOpen("\0"))) {
fprintf(stderr, "\nCan’t start MATLAB engine\n");
throw "Unable to start MATLAB engine";
}
}

MatlabExecutor::~MatlabExecutor() {
if (!(ep = engOpen("\0"))) {
logger << "Closing engine..." << std::endl;
engClose(ep);
}
}

void MatlabExecutor::putMatrix(const std::string& matrixVariableName, Matrix& values) {


if (values.getRows() == 0 || values.getColumns() == 0)
throw "Values are required";
mwSignedIndex rows = values.getRows();
mwSignedIndex cols = values.getColumns();
logger << "Calling Matlab for matrix " << rows << "x" << cols << std::endl;

mxArray *matrix = mxCreateDoubleMatrix(rows, cols, mxREAL);


double *ptrMatrix = mxGetPr(matrix);
logger << "Copying matrix..." << std::endl;
for(mwSignedIndex i = 0; i < rows; ++i) {
for(mwSignedIndex j = 0; j < cols; ++j) {
*(ptrMatrix + (j*rows) + i) = values.get(i,j);
}
}

logger << "Putting matrix. Variable: " << matrixVariableName << std::endl;
engPutVariable(ep, matrixVariableName.c_str(), matrix);
mxDestroyArray(matrix);

Apéndice F. Códigos Fuente 206


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Matrix MatlabExecutor::getMatrix(const std::string& matrixVariableName) {


logger << "Getting matrix. Variable: " << matrixVariableName << std::endl;
mxArray *result;
if ((result = engGetVariable(ep,matrixVariableName.c_str())) == NULL) {
logger << "There was an error getting the values from variable ’" << matrixVariableName << "’" << std::
endl;
throw "There was an error getting the values from a variable.";
}
else {
mwSize dimensionsCount = mxGetNumberOfDimensions(result);
if (dimensionsCount > 2) {
logger << "Matrices are prepared to be 2D only. The variable ’" << matrixVariableName << "’ was a ";
logger << dimensionsCount << "D." << std::endl;
throw "Matrices are prepared to be 2D only.";
}
else {
const mwSize* dimensions = mxGetDimensions(result);
mwSize rows = dimensions[0];
mwSize cols = dimensions[1];

Matrix matrix(rows, cols);


double* resultPtr = mxGetPr(result);
for(size_t i = 0; i < rows; ++i) {
for(size_t j = 0; j < cols; ++j) {
double value = *(resultPtr + (j*rows) + i);
matrix.set(i,j, value);
}
}
mxDestroyArray(result);
return matrix;
}
}
}

void MatlabExecutor::evaluate(const std::string& expression) {


#define BUFSIZE 1024
static char buffer[BUFSIZE+1];
memset(buffer, 0, sizeof(buffer));

engOutputBuffer(ep, buffer, sizeof(buffer) - 1);

logger << "Matlab. Evaluating: " << expression << std::endl;


engEvalString(ep, expression.c_str());
logger << "Matlab. Evaluation result: " << buffer << std::endl;
}

double MatlabExecutor::evaluateScalar(const std::string& expression) {


evaluate(expression);
mxArray *ans = NULL;
if ((ans = engGetVariable(ep,"ans")) == NULL) {
logger << "There was an error retrieving the answer of a previusly evaluated command." << std::endl;
throw "Error retrieving the answer of a previosly evaluated command.";
}
else {
double result = mxGetScalar(ans);
mxDestroyArray(ans);
return result;
}
}

F.6.13. Matrix.h

#ifndef MATRIX__

Apéndice F. Códigos Fuente 207


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

#define MATRIX__

typedef double Cell;

class Row {
private:
std::vector< Cell > data;
public:
Row(size_t columns) {
this->data.resize(columns);
}

Row(const std::vector< Cell >& data) : data(data) {


}

void resize(size_t columns) {


data.resize(columns);
}
Cell& operator[](size_t column) {
return data[column];
}
const Cell& operator[](size_t column) const {
return data[column];
}
std::vector< Cell > toCellsVector() {
return this->data;
}
void pushCell(const Cell& value) {
data.push_back(value);
}
size_t getColumns() const {
return data.size();
}
};

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;
}

Row& operator[](size_t row) {


return data[row];
}
const Row& operator[](size_t row) const {

Apéndice F. Códigos Fuente 208


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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"

Parser::Parser(Logger& logger, unsigned int probesCount) : logger(logger), probesCount(probesCount) {


}

void Parser::processLine(const std::string& line, unsigned int& currentStep, Row& probeValues) {


unsigned int aux;
std::istringstream converter(line);
converter >> aux;

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) {

Apéndice F. Códigos Fuente 209


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Cell value;
converter >> value;
probeValues[i] = value;
}
}
}

Row Parser::readValuesForStep(const std::string& probesFilepath, unsigned int stepNumber) {


Row probeValues(this->probesCount);
std::ifstream probes(probesFilepath.c_str());

probes.seekg(0, std::ios::beg);
std::ifstream::pos_type posBegin = probes.tellg();
probes.seekg(-1, std::ios::end);

unsigned int currentStep = std::numeric_limits<unsigned int>::max();


std::string line;
char buffer;
do {
buffer = probes.peek();

if (buffer != ’\n’ || probes.tellg() == posBegin)


line += buffer;
else {
std::reverse(line.begin(), line.end());
processLine(line, currentStep, probeValues);
line.clear();
}

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.";
}

Row Parser::readValuesWithRetry(const std::string& probesFilepath, unsigned int stepNumber, unsigned int


retries) {
#define MAX_RETRIES 4
#define SECS_BETWEEN_RETRIES 5

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;
}
}

Row Parser::readValues(const std::string& probesFilepath, unsigned int stepNumber) {


return readValuesWithRetry(probesFilepath, stepNumber, 0);
}

F.6.16. SaturneCommunicator.h

#ifndef SATURNE_COMMUNICATOR__

Apéndice F. Códigos Fuente 210


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

#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"

int SaturneCommunicator::waitForStep(std::istream& semaphore, Logger& logger) {


unsigned int semaphoreStepNumber;
logger << "Waiting..." << std::endl;
semaphore >> semaphoreStepNumber;
if (semaphore.good()) {
logger << " ...Signal received: ’" << semaphoreStepNumber << "’. Resuming..." << std::endl;
return semaphoreStepNumber;
}
else {
logger << " ...File Closed or damaged. Resuming..." << std::endl;
return -1;
}
}

void SaturneCommunicator::send(std::ofstream& actuatorFile, Logger& logger, double value) {


std::stringstream converter;
converter << value;

std::string strValue;
converter >> strValue;
logger << "Sending ’" << strValue << "’." << std::endl;
actuatorFile << strValue <<std::endl;
}

Apéndice F. Códigos Fuente 211


G Códigos Fuente de Avances Experi-
mentales

G.1. Pruebas de Concepto de Captura de Imágenes


G.1.1. PixelFly qe

#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 main(int argc, char* argv[]) {


int totalSnapshots;

std::cout << "Qty of snapshots to take: ";


std::cin >> totalSnapshots;

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

using namespace std;


int main(int argc, char* argv[])
{
PXD pxd;
FRAMELIB frameLib;
long hFG=0;
FRAME* pFRAME=0;
char arcFileName[20];
static int num=0;
int NO_FRAMES;

cout << "Ingrese el Nro de imagenes a capturar (30 fps)";


cin >> NO_FRAMES;

imagenation_OpenLibrary(".\\PXD_32.DLL", &pxd, sizeof(PXD));


imagenation_OpenLibrary (".\\frame_32.dll", &frameLib, sizeof(FRAMELIB));

CAMERA_TYPE *configInMem;

char configFile[] = {"default.cam"};


printf(" %s\n",configFile);
printf("Incio de Soft %d imagenes \n\n",NO_FRAMES);

hFG= pxd.AllocateFG (-1);

configInMem = pxd.LoadConfig(configFile); // load structure from file


pxd.SetCameraConfig(hFG,configInMem); // use the configuration file here
pxd.FreeConfig(configInMem);

pFRAME = pxd.AllocateBufferList (pxd.GetWidth(hFG), pxd.GetHeight(hFG), pxd.GetPixelType(hFG),NO_FRAMES);

printf("Incio de Captura %d imagenes \n\n",NO_FRAMES);


pxd.Grab (hFG, pFRAME,IMMEDIATE);

for(num= 0; num<NO_FRAMES ; num++) {


sprintf_s(arcFileName,"30fps %.3d.bmp", num);
printf(" %s \n",arcFileName);
frameLib.WriteBMP ( frameLib.ExtractPlane(pFRAME,num), arcFileName,1);
}
frameLib.FreeFrame (pFRAME);

pxd.FreeFG (hFG);
return 0;
}

G.1.3. SpeedCam Mini Vis

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;

class DummyConsumer implements CallbackConsumer {


public void modeChanged(int paramInt){
}

Apéndice G. Códigos Fuente de Avances Experimentales 213


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

public void statusChanged(int paramInt) {


}
public void shutterChanged(boolean paramBoolean, short paramShort) {
}
}

public class Application {


public static void main(String[] arguments) {
System.out.println("Getting MinivisFactory...");
MinivisFactory factory = MinivisFactory.getInstance();
try {
System.out.println("Discovering cameras...");
factory.discover();

System.out.println("Getting known devices...");


TypedNetAddress[] addresses = factory.getKnownDevices();
System.out.println("Found " + addresses.length + " devices.");

System.out.println("Getting camera from MAC...");


DummyConsumer callbackConsumer = new DummyConsumer();
Proxy camera = factory.getCamera("MAC", callbackConsumer);

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. Pruebas de Concepto de Ident. de Sist. en CUDA C/C++


y C++/GSL
Los archivos de código fuente que se adjuntan a continuación, representan una prueba de
concepto sobre la posibilidad de implementar el algoritmo de identificación del sistema en C++.
Para esta nueva versión del sistema se utilizaron 2 librerı́as de álgebra lineal con punto flotante de
doble precisión: GSL y CUDA/CULA. En el último caso se emplean las capacidades de GPGPU
del ordenador. Una comparación de los resultados obtenidos se puede encontrar en el Apéndice
C.2.

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"

void readFromFile(const std::string& filepath, Matrix<t_sample>& target)

Apéndice G. Códigos Fuente de Avances Experimentales 214


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

{
std::ifstream file(filepath.c_str());
if (file)
file >> target;
else
throw Exception("The file could not be opened for reading");
}

void writeToFile(const std::string& filepath, const Matrix<t_sample>& target)


{
std::ofstream file(filepath.c_str());
if (file)
file << target;
else
throw Exception("The file could not be opened for writing");
}

void calculate(int order, Matrix<t_sample>& input, Matrix<t_sample>& output, const std::string&


outputFolder)
{
ArxSystemIdentification arx(order, input, output);
arx.estimateModel();

std::string normalizedOutputFolder = outputFolder;


if (*outputFolder.rbegin() != ’/’ && *outputFolder.rbegin() != ’\\’)
normalizedOutputFolder.append("\\");
for(int i = 0; i < order+1; ++i)
{
std::stringstream aFilepath, bFilepath;
aFilepath << normalizedOutputFolder << "A" << i << ".txt";
bFilepath << normalizedOutputFolder << "B" << i << ".txt";
writeToFile(aFilepath.str(), arx.getAModel(i));
writeToFile(bFilepath.str(), arx.getBModel(i));
}
}

int main(int argc, char* argv[])


{

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)

Apéndice G. Códigos Fuente de Avances Experimentales 215


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

{
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"

ArxSystemIdentification::ArxSystemIdentification(int order, const Matrix<t_sample>& input, const Matrix<


t_sample>& output)
:order(order), input(input), output(output)
{
this->m = output.getColumns();
this->r = input.getColumns();

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

Apéndice G. Códigos Fuente de Avances Experimentales 216


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

y(k) is the output at time k with dimension m x 1.


u(k) is the input at time k with dimension r x 1.
a_1,..a_na matrices of m x m
b_1,...b_nb matrices of m x r

The algorithm will consider na = nb-1 and N=qty of samples.


*/

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]
*/

Matrix<t_sample> fi(na*m+nb*r, N, true);


// fi should take na columns of y and nb columns from u in order to create one single column.
// fi will take N columns as above but slicing the y and u column indexes each.
for(size_t fiColumn = na; fiColumn < N; ++fiColumn) {
size_t fiRow = 0;
int columnOffset = fiColumn - (int)na;
//iterates columns na-1 to 0 for fiColumn=na and N-2 to N-na-1 for fiColumn=N-1
for(int yColumn = na - 1 + columnOffset; yColumn >= 0 + columnOffset; --yColumn) {
for(size_t yRow = 0; yRow < m; ++yRow) {
fi.set(fiRow, fiColumn, -y.get(yRow, yColumn));
++fiRow;
}
}

//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

Y = reshape(y(:, na+1:end), m*(N-na), 1);


*/
Matrix<t_sample> reg(m*(na*m+nb*r), m*(N-na), true);
for(size_t kBlock = 0; kBlock < N-na; ++kBlock) {
//fiColumn from na to N-1
size_t fiColumn = kBlock+na;
for(size_t fiRow = 0; fiRow < (na*m+nb*r); ++fiRow) {
t_sample value = fi.get(fiRow, fiColumn);
for(size_t iBlock = 0; iBlock < m; ++iBlock) {
reg.set(fiRow * m + iBlock, kBlock * m + iBlock, value);
}

Apéndice G. Códigos Fuente de Avances Experimentales 217


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

}
}

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));
}

for(size_t k = 0; k < nb; ++k)


{
//Take the submatrix as per: 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);
Matrix<t_sample> Bk = th.getRow(na*m*m + k*m*r, na*m*m + (k+1)*m*r - 1);
this->estimatedB.push_back(Bk.reshape(m,r));
}
}

const Matrix<t_sample>& ArxSystemIdentification::getAModel(int index) const


{

Apéndice G. Códigos Fuente de Avances Experimentales 218


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

return this->estimatedA.at(index);
}

const Matrix<t_sample>& ArxSystemIdentification::getBModel(int index) const


{
return this->estimatedB.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

%segón Ljung, se define el vector de regresión en el tiempo k como:


% fi(k)=(-y(k-1), ...,-y(k-na),u(k), u(k-1),...u(k-(nb-1))’
% y el "vector" de parómetros a calcular mp’=(a_1,...,a_na,_1,...b_nb)

[m,N] = size(y);
[r,N] = size(u);

%se construye fi con los valores de regresión, considerando los tiempos de


%na+1 en adelante
fi = zeros(na*m+nb*r,N);
for j=na+1:N
fi(:,j)=[reshape(-y(:, j-1:-1:j-na), na*m, 1); ...
reshape(u(:, j:-1:j-(nb-1)), nb*r, 1)];
end

%se construye la matriz de regresion


fi2 = fi(:, na+1:end);
reg = zeros(m*size(fi2,1), m*(N-na));
for j=1:N-na
reg(:, 1+(j-1)*m:j*m) = kron(fi2(:,j), eye(m));
end

%REVISAR SIG LINEA


yna = y(:, na+1:end);
Y = reshape(yna, m*(N-na), 1);

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);

Apéndice G. Códigos Fuente de Avances Experimentales 219


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

%se desecha la parte Q de la matriz F y se resuelve por cuad. mónimos


%th: resultante que contiene los valores para armar las matrices A y B
th = pinv(R1) * R2;

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

template < typename T = float>


class Matrix
{
private:
gsl_matrix* inner;
size_t rows;
size_t columns;
public:
Matrix(size_t rows, size_t columns, bool defaultToZero = false)
:rows(rows), columns(columns)
{
if (defaultToZero)
inner = gsl_matrix_calloc(rows, columns);
else
inner = gsl_matrix_alloc(rows, columns);
}

Matrix(const Matrix<T>& toCopy)


:rows(toCopy.rows), columns(toCopy.columns)
{

Apéndice G. Códigos Fuente de Avances Experimentales 220


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

inner = gsl_matrix_alloc(rows, columns);


gsl_matrix_memcpy(inner, toCopy.inner);
}
Matrix(gsl_matrix* matrix, bool manageMemory)
:rows(matrix->size1), columns(matrix->size2)
{
if (manageMemory) {
inner = matrix;
}
else {
inner = gsl_matrix_alloc(rows, columns);
gsl_matrix_memcpy(inner, matrix);
}
}

Matrix<T>& operator=(const Matrix<T>& toCopy)


{
if (this != &toCopy)
{
gsl_matrix_free(inner);
this->rows = toCopy.rows;
this->columns = toCopy.columns;
inner = gsl_matrix_alloc(rows, columns);
gsl_matrix_memcpy(inner, toCopy.inner);
}
return *this;
}

Matrix<T> reshape(size_t newRows, size_t newColumns) const


{
if (newRows*newColumns != this->rows*this->columns)
{
std::stringstream message;
message << "It is not possible to reshape a " << this->rows << "x" << this->columns << " to a " <<
newRows << "x" << newColumns << " matrix. Amount of elements should match.";
throw Exception(message.str().c_str());
}
Matrix<T> newShape(newRows, newColumns);
size_t iNew = 0;
size_t jNew = 0;
for(size_t j = 0; j < this->columns; ++j)
{
for(size_t i = 0; i < this->rows; ++i)
{
newShape.set(iNew, jNew, this->get(i,j));
if (iNew == newRows - 1)
{
iNew = 0;
++jNew;
}
else
++iNew;

}
}
return newShape;
}

Matrix<T> transpose() const


{
gsl_matrix* transposed = gsl_matrix_alloc(this->columns, this->rows);
gsl_matrix_transpose_memcpy(transposed, inner);
return Matrix<T>(transposed, true);
}

Matrix<T> getTriu() const


{
Matrix<T> triu(this->rows, this->columns, true);
for(size_t i = 0; i < this->rows; ++i)
{

Apéndice G. Códigos Fuente de Avances Experimentales 221


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

for(size_t j = i; j < this->columns; ++j)


{
triu.set(i,j, this->get(i,j));
}
}
return triu;
}
Matrix<T> decomposeQRCULA() const
{
int lda = this->rows;
int matrixRank = this->rows > this->columns? this->columns: this->rows;
Matrix<T> transposed = this->transpose();
T* aCula = transposed.toArrayRowMajor();
T* tauCula = (T*) malloc(matrixRank*sizeof(T));

culaStatus status = culaSgeqrf(this->rows, this->columns, aCula, lda, tauCula);


checkStatus(status);

Matrix<T> resultTransposed(this->columns, this->rows);


resultTransposed.fromArrayRowMajor(aCula);

free(aCula);
free(tauCula);

return resultTransposed.transpose();
}

Matrix<T> decomposeQRGsl() const


{
int matrixRank = this->rows > this->columns? this->columns: this->rows;

gsl_matrix* copy = gsl_matrix_alloc(this->rows, this->columns);


gsl_matrix_memcpy(copy, inner);
gsl_vector* tau = gsl_vector_alloc(matrixRank);
gsl_linalg_QR_decomp (copy, tau);
gsl_vector_free(tau);

return Matrix<T>(copy, true);


}
Matrix<T> pseudoInvertCULA()
{
//A = U S V^T where U:mxm, S:mxn, V:nxn
Matrix<T> transposed = this->transpose();

int lda = this->rows;


int ldu = this->rows;
int ldvt = this->columns;
int matrixRank = this->rows > this->columns? this->columns: this->rows;
T* aCula = transposed.toArrayRowMajor();
T* sCula = (T*) malloc(matrixRank*sizeof(T));
T* uCula = (T*) malloc(ldu*this->rows*sizeof(T)); //[u] = mxm
T* vtCula = (T*) malloc(ldvt*this->columns*sizeof(T)); //[v] = nxn

//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);

Apéndice G. Códigos Fuente de Avances Experimentales 222


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

for (size_t i = 0; i < matrixRank; i++) {


if (*(sCula+i) > MINIMUN_ACCEPTED_EIGENVALUE_ON_SVD)
*(sInvCula+i*this->columns+i) = 1.0 / *(sCula+i);
}

//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

// Computing the SVD of A


// The variable ’U’ should contain A as input and U as output.
gsl_matrix_memcpy(U, this->inner);
gsl_vector * work = gsl_vector_alloc (this->columns);
gsl_linalg_SV_decomp (U, V, S, work);
gsl_vector_free(work);

//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);

for (size_t i = 0; i < this->columns; i++) {


if (gsl_vector_get (S, i) > MINIMUN_ACCEPTED_EIGENVALUE_ON_SVD)
gsl_matrix_set (SI, i, i, 1.0 / gsl_vector_get (S, i));
}

//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.");

Apéndice G. Códigos Fuente de Avances Experimentales 223


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

int matrixRank = this->rows;

gsl_matrix *matrixCopy = gsl_matrix_alloc(matrixRank, matrixRank);


gsl_matrix_memcpy(matrixCopy, inner);

gsl_matrix *inverse = gsl_matrix_alloc(matrixRank, matrixRank);


gsl_permutation* p = gsl_permutation_alloc(matrixRank);
int s=0;
gsl_linalg_LU_decomp (matrixCopy, p, &s);
gsl_linalg_LU_invert(matrixCopy,p,inverse);

gsl_matrix_free(matrixCopy);
gsl_permutation_free(p);

return Matrix<T>(inverse, true);


}

Matrix<T> sum(const Matrix<T>& toSum) const


{
if (toSum.columns != columns) {
std::stringstream message;
message << "Invalid column size for sum operation. Left matrix cols: " << columns << ". right matrix
cols: " << toSum.getColumns();
throw Exception(message.str().c_str());
}
if (toSum.rows != rows) {
std::stringstream message;
message << "Invalid row size for sum operation. Left matrix rows: " << rows<< ". right matrix rows: "
<< toSum.getRows();
throw Exception(message.str().c_str());
}
gsl_matrix* result = gsl_matrix_alloc(this->rows, this->columns);
gsl_matrix_memcpy(result, inner);
gsl_matrix_add(result, toSum.inner);
return Matrix<T>(result, true);
}

Matrix<T> multiply(const Matrix<T>& toMultiply) const


{
if (toMultiply.getRows() != columns) {
std::stringstream message;
message << "Invalid rows size for multiply operation. Left matrix dimension: " << rows << "x" <<
columns << ". Right matrix dimension: " << toMultiply.getRows() << "x" << toMultiply.getColumns()
;
throw Exception(message.str().c_str());
}

Matrix<T> multiplyResult(this->rows, toMultiply.getColumns());


for(size_t i = 0; i < this->rows; ++i)
{
for(size_t j = 0; j < toMultiply.getColumns(); ++j)
{
T cellValue = 0;
for(size_t k = 0; k < this->columns; ++k)
{
cellValue += this->get(i, k) * toMultiply.get(k, j);
}
multiplyResult.set(i, j, cellValue);
}
}
return multiplyResult;
}

Matrix<T> multiplyCULA(const Matrix<T>& toMultiply) const


{
if (this->columns != toMultiply.rows) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << this->columns << ".
right matrix rows: " << this->columns;

Apéndice G. Códigos Fuente de Avances Experimentales 224


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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> multiplyGsl(const Matrix<T>& toMultiply) const


{
if (this->columns != toMultiply.rows) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << this->columns << ".
right matrix rows: " << this->columns;
throw Exception(message.str().c_str());
}
gsl_matrix* result = multiplyGslNoneNone(this->inner, toMultiply.inner);
return Matrix<T>(result, true);
}

Matrix<T> divide(T denominator) const


{
Matrix<T> divisionResult(this->rows, this->columns);
for(size_t i = 0; i < this->rows; ++i)
{
for(size_t j = 0; j < this->columns; ++j)
{
divisionResult.set(i, j, this->get(i, j) / denominator);
}
}
return divisionResult;
}

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<T> submatrix(rowTo - rowFrom + 1, columnTo - columnFrom + 1);


for(size_t column = columnFrom; column <= columnTo; ++column)
{
for(size_t row = rowFrom; row <= rowTo; ++row)
{
submatrix.set(row - rowFrom, column - columnFrom, this->get(row, column));
}
}
return submatrix;
}

Matrix<T> getColumn(size_t columnFrom, size_t columnTo) const


{
return this->getSubmatrix(0, columnFrom, this->rows-1, columnTo);
}

Matrix<T> getColumn(size_t column) const


{
return this->getColumn(column, column);

Apéndice G. Códigos Fuente de Avances Experimentales 225


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

Matrix<T> getRow(size_t rowFrom, size_t rowTo) const


{
return this->getSubmatrix(rowFrom, 0, rowTo, this->columns-1);
}

Matrix<T> getRow(size_t row) const


{
return this->getRow(row, row);
}

~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;
}

void fromArrayRowMajor(const T* array) const


{
for(size_t i = 0; i < this->rows; ++i){
//memcpy(inner->data + i * inner->tda, array + i*this->columns, this->columns*sizeof(T));
for(size_t j = 0; j < this->columns; ++j){
*(inner->data + i * inner->tda + j) = (double)(*(array + i*this->columns + j));
}
}
}
private:
void validateCell(size_t row, size_t column) const
{
this->validateRow(row);
this->validateColumn(column);
}

void validateColumn(size_t column) const


{
if (column < 0 || column >= columns) {
std::stringstream message;
message << "Invalid column index. Total Cols: " << columns << ". Asked: " << column;
throw Exception(message.str());

Apéndice G. Códigos Fuente de Avances Experimentales 226


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

}
}

void validateRow(size_t row) const


{
if (row < 0 || row >= rows) {
std::stringstream message;
message << "Invalid row index. Total Rows: " << rows << ". Asked: " << row;
throw Exception(message.str());
}
}

void checkStatus(culaStatus status) const


{
if(status)
{
char buf[256];
culaGetErrorInfoString(status, culaGetErrorInfo(), buf, sizeof(buf));
throw Exception(buf);
}
}
T* multiplyCULATransposedNone(T* aCula, T* bCula, int mA, int nA, int mB, int nB) const
{
if (mA != mB) {
std::stringstream message;
message << "Invalid row size for multiply operation. Left matrix columns: " << mA << ". right matrix
rows: " << mB;
throw Exception(message.str().c_str());
}

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) {

Apéndice G. Códigos Fuente de Avances Experimentales 227


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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);
}

gsl_matrix* blasMultiplyGsl(gsl_matrix* a, gsl_matrix* b, CBLAS_TRANSPOSE_t opA, CBLAS_TRANSPOSE_t opB,


size_t responseRows, size_t responseCols) const
{
gsl_matrix * r = gsl_matrix_alloc (responseRows, responseCols);
gsl_blas_dgemm (opA, opB,
1.0, a, b,
0.0, r);
return r;
}

/**
* 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;
}
};

template <typename T>


std::istream& operator>>(std::ifstream& input, Matrix<T>& matrix)
{
for(size_t j = 0; j < matrix.getColumns(); ++j)
{
for(size_t i = 0; i < matrix.getRows(); ++i)
{
T cellValue;
input >> std::setiosflags(std::ios::fixed) >> std::setprecision(PRINT_MATRIX_CELL_VALUE_PRECISION) >>
cellValue;
matrix.set(i, j, cellValue);
if (! input.good())
throw Exception("Error writing the matrix file");
}
}

Apéndice G. Códigos Fuente de Avances Experimentales 228


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

return input;
}

template <typename T>


std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix)
{
for(size_t j = 0; j < matrix.getColumns(); ++j)
{
for(size_t i = 0; i < matrix.getRows(); ++i)
{
T cellValue = matrix.get(i, j);
output << std::setiosflags(std::ios::fixed) << std::setprecision(PRINT_MATRIX_CELL_VALUE_PRECISION)
<< cellValue << " ";
if (! output.good())
throw Exception("Error writing the matrix file");
}
output << std::endl;
}
return output;
}

#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;

Apéndice G. Códigos Fuente de Avances Experimentales 229


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

int cudaMinimumVersion = culaGetCudaMinimumVersion();


int cudaRuntimeVersion = culaGetCudaRuntimeVersion();
int cudaDriverVersion = culaGetCudaDriverVersion();
int cublasMinimumVersion = culaGetCublasMinimumVersion();
int cublasRuntimeVersion = culaGetCublasRuntimeVersion();
int errors = 0;
if(cudaRuntimeVersion < cudaMinimumVersion)
{
errorMessage << "CUDA runtime version is insufficient; version " << cudaMinimumVersion << " or greater
is required" << std::endl;
++errors;
}
if(cudaDriverVersion < cudaMinimumVersion)
{
errorMessage << "CUDA driver version is insufficient; version " << cudaMinimumVersion << " or greater
is required" << std::endl;
++errors;
}
if(cublasRuntimeVersion < cublasMinimumVersion)
{
errorMessage << "CUBLAS runtime version is insufficient; version " << cublasMinimumVersion << " or
greater is required" << std::endl;
++errors;
}
if (errors)
throw Exception(errorMessage.str());
}

void CULAContext::checkStatus(culaStatus status)


{
char buf[256];
if(status){
culaGetErrorInfoString(status, culaGetErrorInfo(), buf, sizeof(buf));
throw Exception(buf);
}
}

G.2.7. common/Exception.h

#ifndef EXCEPTION_H_
#define EXCEPTION_H_

#include <string>
#include <exception>

class Exception : public std::exception {


private:
std::string message;
public:
Exception(const std::string& message);
virtual ~Exception() throw() {}
virtual const char* what() const throw();
};

#endif /* EXCEPTION_H_ */

G.2.8. common/Exception.cpp

#include "Exception.h"

Exception::Exception(const std::string& message) : message(message) {


}

Apéndice G. Códigos Fuente de Avances Experimentales 230


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

const char* Exception::what() const throw() {


return this->message.c_str();
}

G.3. Pruebas de Concepto de Controlador Adaptativo


G.3.1. lfd control init.m

function [ control_state ] = lfd_control_init(y, u, p, alpha, mu, A, B, limits, q)


% usage example:
%
% [A, B] = lfd_arx(y, u, 2);
% limits.min_value = 0;
% limits.max_value = 3;
% control_state = lfd_control_init(y, u, 2, 0.99999, 1/625000, A, B, limits, ones(1,sizeof(y,2)));
% next_actuation = lfd_control(control_state, y, u);

y = y’;
u = u’;

%y de m*N datos de las salidas


%u de r*N datos de entradas, N=cantidad de observaciones
%p=orden del modelo ARX

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);

%alfa=0.999999, mu, parametros de Kegerise


g=(1-alpha)/mu; %g=gamma otro de los parametros de Kegerise
%alfa=0.999999=1-2*g*mu

%s=horizonte de prediccion (valores recomendados entre 2 y 3 veces ’p’)


s=2*p;

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

%segun la idea de Kegerise se busca min y_s’Qy_s+g tr(H’H)


%Q es diagonal en bloques, de msxms, con bloques diagonales
%Q_1,..Q_s de tamanios mxm, con numeros entre 0 y 1 en la diagonal
%Cada Q_i=diag(q_1(i),..q_m(i))

Apéndice G. Códigos Fuente de Avances Experimentales 231


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

%el termino y_s’Qy_s se puede leeer:


%y(k)’Q_1y(k)+y(k+1)’Q_2y(k+1)+...y(k+s-1)’Q_sy(k+s-1)

%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;

%TTQr=r primeras filas de T’Q


TTQr(:,1:m)=beta00’*diag(q);
for j=1:s-1;TTQr(:,m*j+1:(j+1)*m)=beta0(:,:,j)’*diag(q);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

G.3.2. lfd control.m

function [ control_state ] = lfd_control(control_state, y, u)


% example:
% [A, B] = arx_ljung(y, u, 2);
% u_next_step = lfd_control(y, u, 2, 0.99999, 1/625000, ones (1,2*4), A, B)

y = y’;
u = u’;

%y de m*N datos de las salidas


%u de r*N datos de entradas, N=cantidad de observaciones
%p=orden del modelo ARX

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);

Apéndice G. Códigos Fuente de Avances Experimentales 232


Sistema de Control de Flujos a Lazo Cerrado Pablo D. Roca

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).

%ys_k_1_s = ys(k-1-s) = [y(k-1-s);y(k-1-s+1);...;y(k-2)]


ys_k_1_s = reshape(y(:,(k-1-s):(k-2)), m*s, 1);
%vp_k_1_p_s = vp(k-1-p-s) = [u(k-1-p-s);...;u(k-2-s);y(k-1-p-s);...;y(k-2-s)]
up_k_1_p_s = reshape(u(:,(k-1-p-s):(k-2-s)), r*p, 1);
yp_k_1_p_s = reshape(y(:,(k-1-p-s):(k-2-s)), m*p, 1);
vp_k_1_p_s = [up_k_1_p_s;yp_k_1_p_s];

%vp_k_p = vp(k-p) = [u(k-p);...;u(k-1);y(k-p);...;y(k-1)]


up_k_p = reshape(u(:,(k-p):(k-1)), r*p, 1);
yp_k_p = reshape(y(:,(k-p):(k-1)), m*p, 1);
vp_k_p = [up_k_p;yp_k_p];

%according to eq. 16 h(k) = alpha*h(k-1) - 2*mu*tqr*ys(k-1-s)*vp(k-1-p-s)’


h_k = alpha * h_k_1 - 2 * mu * TTQr * ys_k_1_s * vp_k_1_p_s’;
u_k = h_k * vp_k_p;

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;
u_k = u_k’;

control_state.u_k = u_k;
control_state.h_k = h_k;

end

Apéndice G. Códigos Fuente de Avances Experimentales 233


Bibliografı́a

[1] Neculai Andrei. Modern control theory - a historical perspective, 2005.

[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.

[10] A. Cammilleri, F. Gueniat, J. Carlier, L. Pastur, E. Memin, F. Lusseyran, and G. Artana.


Pod-spectral decomposition for fluid flow analysis and model reduction. Theoretical and
Computational Fluid Dynamics, pages 1–29, 2013.

[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.

[19] E. Detemple-Laake and H. Eckelmann. Phenomenology of kármán vortex streets in oscilla-


tory flow. Experiments in Fluids, 7(4):217–227, 1989.

[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.

[21] E. Fernández-Cara and E. Zuazua. Control theory: History, mathematical achievements


and perspectives. Bol. Soc. Esp. Mat. Apl., 26:79–140, 2003.

[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.

[24] B. Friedland. Control System Design: An Introduction To State-Space Methods. Dover


Books on Electrical Engineering Series. Dover Publications, Incorporated, 2005.

[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.

[39] Petros Koumoutsakos. Active control of vortex–wall interactions. Physics of Fluids,


9(12):3808–3816, 1997.

[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.

[43] D. J. Mavriplis. Unstructured grid techniques. Annual Review of Fluid Mechanics,


29(1):473–514, 1997.

[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.

[70] M. M. Zdravkovich. Flow Around Circular Cylinders: Volume I: Fundamentals. Flow


Around Circular Cylinders: A Comprehensive Guide Through Flow Phenomena, Experi-
ments, Applications, Mathematical Models, and Computer Simulations. OUP Oxford, 1997.

[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

También podría gustarte