root/applications/doprava/texty/delka_cyklu/05_AlgorithmDescription/AlgorithmDescription.tex @ 1150

Revision 1150, 18.7 kB (checked in by jabu, 14 years ago)
Line 
1\def \obr {05_AlgorithmDescription/fig/}
2\lstset{language=[Visual]C++,showstringspaces=false,numbers=left, numbersep=0pt, tabsize=4, breaklines, breakautoindent=false, captionpos=b}
3\chapter{Popis implementace}
4
5
6
7\section{Použité knihovny}
8
9\subsection{IT++}
10IT++ je knihovna jazyka C++ zahrnující třídy pro matematické výpočty a komunikaci.
11Umožňuje práci s vektory a maticemi podobným způsobem jako v nástroji MATLAB.
12Použity jsou třídy \texttt{vec} a \texttt{Array}.
13
14
15\subsubsection{Třída vec}
16Třída \texttt{vec} reprezentuje vektor hodnot číselného typu \texttt{double}.
17Přetížením operátorů kulatých a hranatých závorek a operátoru \texttt{=} umožňuje jednoduchou inicializaci
18vektoru pomocí textového řetězce a zjednodušuje přístup k jednotlivým hodnotám.
19Kód
20\begin{lstlisting}
21  vec a = "0.1 0.2 0.3";
22  cout << a(0) << endl;
23  cout << a[1] << endl;
24\end{lstlisting}
25inicializuje vektor o dimenzi 3 s hodnotami 0,1, 0,2 a 0,3 a poté
26vypíše první a druhý prvek vektoru.
27
28\subsubsection{Třída Array}
29Tato šablonová třída umožňuje pracovat s polem o proměnných předem daného libovolného typu.
30Rozměr pole se může v průběhu programu měnit.
31
32
33\subsection{BDM}
34Knihovna BDM (Bayesian Decision Making) je navržena pro programy používající
35Bayesovu statistiku. Zde jsou použity hlavně třídy \texttt{Datalink}, \texttt{RV}, \texttt{UI} a \texttt{Setting}
36sloužící pro komunikaci s mikrosimulátorem AIMSUN, načítání hodnot z konfiguračních souborů a komunikaci mezi agenty.
37\\
38\\
39V knihovně BDM je také definována třída \texttt{Participant}, implementující metody pro komunikaci
40, od které je odvozena třída našeho agenta.
41
42
43\subsubsection{Třída RV}
44Třída \texttt{RV} implementuje pole popisků k vektorům třídy IT++.
45K přístupu k jednotlivým slouží přetížený operátor závorky \texttt{(int index)}.
46K určení veličiny uložené ve vektoru se používají metody
47\begin{description}
48 \item [name] jméno veličiny uložené v příslušném vektoru
49 \item [length] rozměr RV vektoru
50 \item [size(i)] rozměr veličiny, kterou značí popisek na pozici \texttt{i}
51\end{description}
52
53\subsubsection{Třídy UI a Setting}
54UI a Setting slouží mimo jiné k načtení vybraných dat z konfiguračních souborů.
55Kód
56\begin{lstlisting}
57    UI::get(inputs,set,"inputs",UI::compulsory);
58\end{lstlisting}
59zapíše na adresu proměnné \texttt{inputs} hodnotu v objektu \texttt{set} třídy \texttt{Setting},
60označenou jako \texttt{\"inputs\"}. Objekt \texttt{set} reprezentuje načtený konfigurační soubor.
61\texttt{UI::compulsory} značí, že daná hodnota musí být zadána.
62
63
64
65\subsubsection{Třída Datalink}
66Tato třída definuje spojení mezi dvěma vektory, mezi kterými zprostředkovává spojení
67pomocí metody \texttt{filldown}.
68\\
69\\
70Následující kód popisuje vytvoření dvou vektorů \texttt{from} a \texttt{to},
71popsaných \texttt{RV} vektory \texttt{rv\_from} a \texttt{rv\_to}, a zkopání odpovídajících
72údajů z \texttt{from} do \texttt{to} pomocí třídy \texttt{Datalink}. Výsledkem je, že vektor
73\texttt{to} bude obsahovat hodnoty 1 a 2.
74
75\begin{lstlisting}
76  RV a = RV ( "{ a }");
77  RV b = RV ( "{ b }" );
78  RV c = RV ( "{ c }" );
79
80  RV rv_to = a;
81  rv_to.add ( b );
82
83  RV rv_from = rv_to;
84  rv_from.to ( c );
85
86  datalink dl ( rv_to, rv_from );
87  vec from ( "1 2 3" );
88  vec to = dl.pushdown ( total );
89\end{lstlisting}
90
91
92
93
94
95\section{Třída Lane}
96Každá instance třídy Lane reprezentuje jeden dopravní pruh.
97Po inicializaci se do příslušných proměnných uloží textové
98řetězce, podle kterých se přiřazují k pruhu data z detektorů
99a AIMSUNu, jako je na příklad maximální délka
100fronty na dopravním pruhu za jednu simulační periodu.
101
102
103\section{Třída LaneHandler}
104Tato třída zprostředkovává přístup agentovi k údajům z jednotlivých pruhů.
105Stará se o zaznamenávání a statistické zpracování dat z AIMSUNu.
106Také je zde implementován odhad čekací doby automobilu do průjezdu křižovatkou,
107což je údaj používaný v hodnotící délky cyklu funkci agenta.
108
109\subsection{Fronta}
110Agent předává třídě LaneHandler údaj o maximální délce fronty za vzorkovací periodu.
111Jedná se o největší počet automobilů v příslušném jízdním pruhu, jejichž rychlost nepřesahuje
112určitou hodnotu. V našem konkrétním případě je tato mezní rychlost nastavena na 3,6 km/h.
113Tento údaj je však pro naše potřeby zkreslený, a to hlavně tím, že ve většině případů se délka cyklu neshoduje
114se vzorkovací periodou. Uvažujme jízdní pruh s poměrem délky zelené 0,5.
115Pokud bude například délka cyklu 180 sekund, a budeme li předpokládat, že začátek jedné periody se bude shodovat s časem,
116kdy na příslušném semaforu naskočí zelená, bude v první vzorkovací periodě pruh průjezdný po dobu 45 sekund, ale
117v další nebude průjezdný vůbec a fronta se za stejné hustoty provozu zvětší.
118
119\subsection{Odhad fronty}\label{ss:odhad_fronty}
120K odhadu fronty je použito metody tzv. exponenciálního zapomínání. Metoda vychází z plovoucího průměru
121Který je vhodný pro odhad nekonstantní hodnoty. Označíme si veličinu $\overline{q_i}$  jako plovoucí průměr
122fronty v kroku $i$, kam budeme ukládat posledních $n$ měření. Označme si velikost fronty naměřenou v $i$-tém kroku jako$q_i$.
123V kroku $i+1$ je hodnota hodnota plovoucího průměru před přičtením poslední naměřené hodnoty rovna
124$$
125\overline{q_i} = \frac{1}{n} \sum_{j=0}^{n-1} q_{i-j} .
126$$
127
128Obsahuje tedy všech posledních $n$ naměřených hodnot. $\overline{q_{i+1}}$ se tedy rovná
129$$
130\overline{q_{i+1}} = \frac{1}{n} ( n \overline{q_i} - q_{i-n+1} + q_{i+1} ) = \overline{q_i} - \frac{1}{n} q_{i-n+1} +\frac{1}{n} q_{i+1}.
131$$
132Abychom nemuseli ukládat posledních $n$ měření. Zjednodušíme algoritmus tím, že místo kroku $i-n+1$ odečteme od průměru
133jeho hodnotu podělenou délkou průměrovacího okna $n$. Výpočet přejde na tvar
134$$
135\overline{q_{i+1}} = \frac{1}{n} ( n \overline{q_i} - \overline{q_i} + q_{i+1} ) = \overline{q_i} + \frac{1}{n} (q_{i+1} - \overline{q_i}).
136$$
137$\frac{1}{n} (q_{i+1} - \overline{q_i}$ je vlastně přírůstek v kroku $i+1$, označme si ho jako $\Delta q_{i+1}$,
138a faktor $1/n$ můžeme chápat jako jeho váhu $w$. Po dosazení dostáváme jednoduchý tvar
139$$
140\overline{q_{i+1}} = \overline{q_i} + w \Delta q_{i+1}.
141$$
142Průměr s exponenciálním zapomínáním se nazývá proto, že je v něm v $i$-tém kroku uložena i první hodnota,
143má však zanedbatelnou váhu $\left(\frac{n-1}{n}\right)^i$. Jedná se o jaksi zjednodušenou verzi Kalmanova filtru.
144Grafy \ref{fig:q1} a \ref{fig:q2} znázorňují rozdíl mezi okamžitou a filtrovanou délkou fronty při váze $w = 0.2$.
145Graf \ref{fig:q1} pro konstantní délku cyklu 80 sekund, graf \ref{fig:q2} pro délku cyklu periodicky se měnící od 40
146do 120 sekund.
147
148\begin{figure}[H]
149\begin{center}
150    {\includegraphics[width=10cm]{\obr q_scen_01_1h_tc80.eps}}
151    \caption{Porovnání okamžité a filtrované délky fronty \newline délka cyklu 80 s}\label{fig:q1}
152\end{center}
153\end{figure}
154
155\begin{figure}[H]
156\begin{center}
157    {\includegraphics[width=10cm]{\obr q_scen_01_1h_tc40-120.eps}}
158    \caption{Porovnání okamžité a filtrované délky fronty \newline délka cyklu 40-120 s}\label{fig:q2}
159\end{center}
160\end{figure}
161
162
163V reálném případě je potřeba vypočítat délku fronty podle záznamů z detektorů.
164Prostý výpočet délky fronty například jako rozdíl počtu vozidel, která odjela a která přijela však není možný.
165V důsledku problémů popsaných v \ref{sss:zpracovani_dat}. Výpočet délky fronty není předmětem zkoumání této práce.
166Podrobnější pojednání o tomto problému lze najít například v \cite{pecherkova}.
167\\
168\\
169Protože časté přenastavování délky cyklu působí řadičům problémy, přenastavuje se tento parametr jednou za časový
170úsek, ktrý je několikanásobně delší než 90 sekund. Je tedy nutné modelovat časový průběh fronty. Při rozšiřování testovacího
171prostředí tento model ovlivní i údaj o počtu vozidel, které přijedou ze sousední křižovatky. Tento údaj závisí na délce cyklu
172a není agentovy dostupný přímo. Bude tedy nutné rozšířit komunikaci agentů, popsanou v \ref{ss:komunikace}, o tento údaj.
173
174
175\subsection{Odhad čekací doby}\label{ss:odhad_cekaci_doby}
176Jednou z nejdůležitějších částí logiky, implementovaná v třídě \texttt{LaneHandler} je
177odhad čekací doby vozidel stojících v, nebo přijíždějících do příslušného jízdního pruhu.
178Tento odhad se používá při výběru a ohodnocení délky cyklu.
179\\
180\\
181Odahad se provádí zjednodušenou mikrosimulací po čas \texttt{T}.
182Do proměnné \texttt{q} se uloží aktuální hodnota fronty.
183Simulace začíná v čase \texttt{t = 0}. V každém kroku simulace
184se zvětší fronta o hustotu provozu (počt aut za sekundu), odhadovanou z údajů z detektorů, a pokud se čas nachází
185ve průjezdné fázi, zmenší se o konstantu, nazývanou saturovaný tok, která udává maximální počet aut, které projedou
186křižovatkou. K čekací době vozidel, uložené v proměnné \texttt{wt}, se potom přičte délka zbývající fronty a čas
187\texttt{t} se zvětší o jednu sekundu.
188\\
189\\
190Odhad probíhá ve dvou fázích, realizovaných cykly typu \texttt{for}. V první běží čas do největší části \texttt{T},
191soudělné s \texttt{tc}, v druhé po zbytek \texttt{T}. níže uvádím popis všech proměnných.
192\begin{description}
193 \item[tc] délka cyklu, pro kterou je odhad prováděn (parametr funkce)
194 \item[T] doba odhadu
195 \item[ro] hustota provozu odhadovaná z dat z detektorů
196 \item[cars\_in\_avg] filtrovaná data z detektorů (atribut třídy)
197 \item[queue\_avg] filtrovaná naměřená délka fronty (atribut třídy)
198 \item[q] délka fronty v průběhu odhadu
199 \item[wt] součet čekacích časů
200 \item[green\_time\_ratio] poměr délky zelené k délce cyklu (atribut třídy)
201 \item[gt] doba, kdy je křižovatka pro pruh průjezdná
202 \item[tc\_rest] čas v daném cyklu
203 \item[tc\_last] zbytek odhadovací periody
204 \item[gt\_last] délka zelené ve zbytku odhadovací periody
205 \item[delta] korekční parametr vyjadřuje zkrácení doby průjezdnosti vlivem pomalých rozjezdů a podpbně
206\end{description}
207Odhad je implementován v metodě \texttt{getWT}:
208
209\begin{lstlisting}
210        double getWT ( int tc ) {
211                const int T = 450; // 5 scyklů
212                double ro = cars_in_avg/90;
213                double q = queue_avg;
214                double wt = 0;
215                double gt = tc*green_time_ratio - delta;
216                int t_rest;
217                int tc_last = T % tc;
218                double gt_last = tc_last*green_time_ratio;
219                for ( int t = 0; t < (T-tc_last); t++ ) {
220                        t_rest = t%tc;
221                        // zelena
222                        if ((tc-gt)/2<=t_rest&&t_rest<(tc+gt)/2)
223                                q -= saturated_stream;
224                        if ( q < 0)
225                                q = 0;
226                        wt += q;                       
227                        q += ro;                               
228                }               
229                // zbytek
230                for ( int t = 0; t < tc_last; t++ ) {
231                        // zelena
232                        if ((tc_last-gt_last)/2<=t&&t<(tc_last+gt_last)/2 )
233                                q -= saturated_stream;
234                        if ( q < 0)
235                                q = 0;
236                        wt += q;                       
237                        q += ro;
238                }
239                return wt;
240        }
241\end{lstlisting}
242
243
244
245\section{Hlavní smyčka}
246Hlavní smyčka programu se stará o synchronizaci všech potřebných parametrů a provádění iterací.
247Před započetím opakování kroku simulace nastaví podle konfiguračního souboru počáteční parametry mikrosimulátoru dopravy AIMSUN,
248jako jsou délka cyklu a fáze řadičů, inicializuje jednotlivé agenty a zavolá jejich metody \texttt{fromSettings} a \texttt{Validate}.
249
250\subsection{Krok simulace}
251Délka kroku simulace je pevně nastavena na 90 sekund shodně s periodou sběru dat z AIMSUNu.
252V jednom kroku se nejprve načtou data z AIMSUNu do vektoru \texttt{glob\_dt}, který se následně předá
253každému z agentů jako parametr jejich metody \texttt{adapt}. Následně se zprostředkuje komunikace mezi
254agenty tak, že se naplní fronta zpráv voláním metody \texttt{broadcast} jednotlivých agentů. Z této fronty
255se postupně odebírají zprávy, které se předávají agentům parametrem jejich metody \texttt{receive}
256Po ukončení komunikace naplní vektor výstupů \texttt{glob\_ut} voláním metod \texttt{act} hodotami parametrů
257pro AIMSUN, předá se mu a vyčká se do dalšího kroku.
258
259\section{Třída agenta}
260Třída \texttt{TrafficAgentCycleTime} je odvozena od obecného návrhu agenta \texttt{BaseTrafficAgent}.
261Jsou v ní implementovány metody pro načtení dat, komunikaci a nastavení délky cyklu za účelem řízení
262jedné konkrétní křižovatky.
263
264\subsection{Stručný popis algoritmu}
265Cíl algoritmu je zlepšit dopravní situaci nastavením délky cyklu řadiče na takovou
266hodnotu, při níž bude celková čekací doba všech vozidel minimální.
267Nejprve agent odhadne délku cyklu, která je ideální pro něj, poté vyšle zprávu, zda je tato hodnota
268vyšší nebo nižší než aktuální. Pokud je nadpoloviční většina agentů pro změnu stejným směrem,
269pokouší se najít hodnotu ideální pro všechny.
270
271\subsection{Výpočetní metody}
272
273\subsubsection{Metoda getWT}
274
275Tato metoda vrací součet čekacích dob, sečtený přes všechny dopravní pruhy pro danou délku cyklu předanou parametrem \texttt{tc}.
276V cyklu projde instance tříd \texttt{LAneHandler}, na které má uloženy ukazatele v proměnné \texttt{lanehs} typu
277\texttt{Array<LaneHandler*>}. Pole se inicializuje v metodě \texttt{validate} předka \texttt{BaseTrafficAgent}.
278
279\subsubsection{Metoda findIdealTc}\label{sss:ideal_tc}
280Pro určení, zda vznést návrh na zvýšení či snížení délky cyklu, slouží metoda \texttt{findIdealTc}.
281Ta zjišťuje čekací doby pro všechny možnosti rozsahu od minimální do maximální hodnoty, určené atributy
282\texttt{minTc} a \texttt{maxTc}. Vrátí takovou délku cyklu, pro kterou je čekací doba nejmenší.
283\\
284\\
285Princip použití součtu čekacích dob automaticky upřednostňuje dopravní pruhy s větší
286vytížeností, což je žádoucí. Ostatní pruhy však zcela nepotlačuje. Tímto způsobem by se mělo
287dosáhnout optimální hodnoty pro celou křižovatku.
288
289\subsection{Přepsané metody předka}
290Hlavní smyčka programu automaticky volá v každém cyklu metody určené
291k načtení dat, komunikaci a nastavení dalšího řízení.
292
293
294
295\subsubsection{Metoda validate}
296K předání požadovaných hodnot parametrů v průběhu simulace slouží vektor \texttt{actions}.
297Významy těchto hodnot vysvětluje \texttt{rv\_actions} třídy \texttt{RV}. V metodě \texttt{validate},
298která se volá na začátku simulace, přidáme do \texttt{rv\_actions} hodnotu \texttt{Tc}. Tím
299vlastně sdělíme AIMSUNu, že budeme přenastavovat délku cyklu. Protože délka jednotlivých fází se nepřenastavuje automaticky,
300přidáme do \texttt{rv\_actions} také označení těchto fází. V praxi je tento postup realizován kódem
301\begin{lstlisting}
302  rv_action = RV("Tc",1);
303  rv_action.add( RV(stage_names, ones_i(stage_names.length())));
304\end{lstlisting}
305kde je v proměnné \texttt{stage\_names} uložen seznam fází.
306\\
307\\
308Následující metody se volají v každém cyklu simulace.
309
310
311
312\subsubsection{Metoda adapt}
313Na začátku každého simulačního cyklu se jako první volá u všech agentů metoda \texttt{adapt}.
314V parametru se jí předá adresa vektoru výstupních údajů simulace \texttt{glob\_dt}, k jejichž zpracování je metoda určena.
315Zde se předávají údaje z detektorů a délky front instancím třídy \texttt{LaneHandler} a poté se volá jejich metoda
316\texttt{countAvgs}, která počítá filtrované hodnoty způsobem popsaným v sekci \ref{ss:odhad_fronty}.
317
318
319\subsubsection{Metoda receive a broadcast} \label{ss:komunikace}
320Po načtení a zpracování dat začíná komunikace. Ta je realizována metodami
321\texttt{broadcas} a \texttt{receive}, které se volají střídavě. Přesněji řečeno,
322hlavni smyčka nejprve volá metody \texttt{receive} každého agenta tak dlouho, dokud nevyprázdní frontu zpráv.
323Ta je reprezentována polem proměnných typu \texttt{Setting}, které mají nastaveny čtyři parametry:
324
325\begin{description}
326 \item [from] určuje od koho zpráva přichází
327 \item [to] má hodnotu jména agenta, pro kterého je zpráva určena
328 \item [what] obsahuje co posíláme
329 \item [value] obsahuje hodnotu spojenou s tím co posíláme
330\end{description}
331
332Každý agent má v atributu \texttt{name} uloženo jméno křižovatky, kterou ovládá.
333Toto jméno je uloženo v konfiguračním souboru a odpovídá označením ze sekce \ref{ss:oblast_simulace}.
334Pokud je jméno agenta stejné jako parametr zprávy \texttt{to}, vyjme se zpráva z fronty a předá se
335metodě \texttt{receive}.V momentě, kdy je fronta prázdná, zavolají se metody \texttt{broadcast} všech agentů.
336Metoda \texttt{broadcast} opět plní frontu zprávami, které chce agent vyslat. Po jejím ukončení se opět volá \texttt{receive}.
337Střídavé volání těchto dvou metod probíhá, dokud \texttt{broadcast} produkuje nějaké zprávy.
338\\
339\\
340V našem případě probíhá odesílání ve dvou krocích. V obou se posílají zprávy všem ostatním agentům.
341Nejprve agent sdělí, jestli chce délku cyklu zvýšit, snížit, nebo ponechat stejnou.
342Pokud je pro zvýšení více než polovina agentů, začíná druhá fáze.
343V té každý agent pošle všechny délky cyklu v předem daném rozsahu a k nim očekávané zisky.
344Rozsah je od minimální do stávající při odhlasování snížení a od stávající do maximální při zvýšení.
345Zisk se počítá jako rozdíl čekací doby při navrhované a stávající délce cyklu pomocí metody popsané v \ref{ss:odhad_cekaci_doby}.
346Odeslání těchto zpráv je realizováno kódem
347\begin{lstlisting}
348  int broadcast_width = (max_tc - min_tc) + 1;
349
350  for ( int i = 0; i < broadcast_width; i++ ) {
351    int time_cycle = min_tc + i*stepTc;
352    double profit = getProfit(time_cycle);
353   
354    // send tc
355    stringstream time_cycle_stream;
356    time_cycle_stream << "tc_" << (i);
357    send2allNeighbours( set, time_cycle_stream.str(), time_cycle);
358
359    // send profit
360    stringstream profit_stream;
361    profit_stream << "profit_" << (i);
362    send2allNeighbours( set, profit_stream.str(), profit );
363  }
364\end{lstlisting}
365
366Agent tedy vygeneruje pro každou hodnotu délky cyklu index, podle kterého se k ní dá přiřadit hodnota zisku.
367V metodě \texttt{receive} se podle tohoto indexu sčítají zisky do pole \texttt{received\_profit\_sum}.
368
369
370
371\subsubsection{Metoda act}\label{sss:metoda_act}
372Pokud se agenti dohodly na změně délky cyklu, probíhá její přenastavení v metodě \texttt{act}.
373Nejprve se projde pole \texttt{received\_profit\_sum} a vybere se z něj maximum.
374Poté se podle indexu maximálního zisku určí ideální délka fronty.
375\\
376\\
377Měření ukázala, že časté změny cyklu působí emulátorům řadičů problémy.
378Proto se ideální hodnota průměruje plovoucím průměrem a nastavuje se jednou za 5 cyklů.
379
380
381
382
Note: See TracBrowser for help on using the browser.