102
POLITECHNIKA WARSZAWSKA WYDZIAŁ MECHANICZNY ENERGETYKI I LOTNICTWA ZAKŁAD MECHANIKI PRACA DYPLOMOWA INŻYNIERSKA MAREK CEL OPROGRAMOWANIE DO WYZNACZANIA PODSTAWOWYCH CHARAKTERYSTYK AERODYNAMICZNYCH PŁATA NOŚNEGO SOFTWARE FOR ESTIMATING BASIC AERODYNAMIC CHARACTERISTICS OF AN AIRCRAFT WING 191184 Lotnictwo i Kosmonautyka Promotor: dr inż Zbigniew Paturski Warszawa, marzec 2009

Cel M - Oprogramowanie do wyznaczania podstawowych charakterystyk aerodynamicznych plata nosnego.pdf

Embed Size (px)

Citation preview

POLITECHNIKA WARSZAWSKA

WYDZIAŁMECHANICZNY ENERGETYKI I LOTNICTWA

ZAKŁAD MECHANIKI

PRACA DYPLOMOWAINŻYNIERSKA

MAREK CEL

OPROGRAMOWANIE DO WYZNACZANIA PODSTAWOWYCHCHARAKTERYSTYK AERODYNAMICZNYCH PŁATA NOŚNEGO

SOFTWARE FOR ESTIMATING BASIC AERODYNAMICCHARACTERISTICS OF AN AIRCRAFT WING

191184

Lotnictwo i Kosmonautyka

Promotor: dr inż Zbigniew Paturski

Warszawa, marzec 2009

Oświadczenie autora (autorów) pracy

Świadom odpowiedzialności prawnej oświadczam, że przedstawiona praca dyplomowa:

- została napisana przeze mnie samodzielnie i nie zawiera treści uzyskanych w sposób niezgodny z obowiązującymi przepisami,

- nie była wcześniej przedmiotem procedur związanych z uzyskaniem tytułu zawodowego lub stopnia naukowego w wyższej uczelni.

Oświadczam ponadto, że niniejsza wersja pracy jest identyczna z załączoną wersją elektroniczną.

............................................. .............................................. data podpis autora (autorów) pracy

SŁOWA KLUCZOWE: aerodynamika samolotu, numeryczna implementacja teorii linii nośnej Prandtla

- 2 -

Spis treści

1. Wykaz ważniejszych oznaczeń..........................................................................................4

2. Wprowadzanie....................................................................................................................5

3. Teoretyczne podstawy programu.......................................................................................7

3.1. Teoria profilu cienkiego.............................................................................................7

3.2. Opływ płata o skończonym wydłużeniu – model wirowy.......................................10

3.3. Teoria linii nośnej Prandtla.......................................................................................11

3.4. Metoda Glauerta.......................................................................................................15

4. Ogólne informacje o programie.......................................................................................18

4.1. Platforma sprzętowa i rodzina systemów operacyjnych...........................................18

4.2. Wykorzystane narzędzia...........................................................................................18

4.2.1. Język C++.........................................................................................................18

4.2.2. Qt Toolkit..........................................................................................................19

5. Opis programu..................................................................................................................21

5.1. klasa Wing................................................................................................................21

5.1.1. Zarządzanie danymi..........................................................................................21

5.1.2. Algorytm obliczeniowy i jego implementacja..................................................25

5.1.3. Format pliku wynikowego................................................................................31

5.2. Graficzny interfejs użytkownika – GUI...................................................................33

5.2.1. Wprowadzanie danych geometrycznych skrzydła............................................33

5.2.2. Wprowadzanie parametrów obliczeń................................................................37

5.2.3. Prezentacja wyników........................................................................................38

6. Analiza uzyskanych wyników..........................................................................................40

7. Wnioski, możliwe zastosowania oraz możliwości rozwoju.............................................45

Załączniki.............................................................................................................................47

A – Listingi ważniejszych kodów źródłowych................................................................47

B – Streszczenie.............................................................................................................101

C – Bibliografia.............................................................................................................102

- 3 -

1. Wykaz ważniejszych oznaczeń

1. Wykaz ważniejszych oznaczeń

c – długość cięciwy

cZ – współczynnik siły nośnej

cXi – współczynnik oporu indukowanego

d cZ

d α– pochodna aerodynamiczna

dR, dXi, dZ – elementarne siły

aerodynamiczne (wypadkowa, oporu

i nośna) działające na wycinek płata

l – elementarna siła nośna profilu

L – rozpiętość

R – wypadkowa siła aerodynamiczna

V∞ – prędkość strumienia niezaburzonego

Vi – prędkość indukowana

x – współrzędna mierzona równolegle

do cięciwy

X – opór aerodynamiczny

Xi – opór indukowany

y – współrzędna mierzona wzdłuż

rozpiętości (w teorii linii nośnej)

y – współrzędna mierzona prostopadle do

cięciwy (w teorii profilu cienkiego)

Z – siła nośna

α∞ – kąt natarcia mierzony pomiędzy

cięciwą, a kierunkiem prędkości

strumienia niezaburzonego

α0 – kąt zerowej siły nośnej

αi – indukowany kąt natarcia

αrz – rzeczywisty kąt natarcia

γ – rozkład cyrkulacji wzdłuż cięciwy

Γ – cyrkulacja

ξ, ψ – zmienne niezależne równania

różniczkowo-całkowego

Λ – wydłużenie geometryczne płata

µ – wartość pomocnicza

η – współrzędna mierzona wzdłuż

rozpiętości

ρ – gęstość powietrza

- 4 -

2. Wprowadzanie

2. Wprowadzanie

Celem niniejszym pracy było opracowanie kodu źródłowego i jego implementacji

na komputerze klasy IBM/PC, którego zadaniem było wyznaczanie podstawowych

charakterystyk aerodynamicznych płata nośnego, to jest:

▪ współczynnika siły nośnej,

▪ współczynnika oporu aerodynamicznego,

▪ rozkładu współczynnika siły nośnej wzdłuż rozpiętości,

▪ rozkładu współczynnika oporu indukowanego wzdłuż rozpiętości,

▪ rozkładu prędkości indukowane wzdłuż rozpiętości.

Do realizacji tego celu opracowany został algorytm obliczeniowy oparty

o opracowaną na początku XX wieku przez Ludwika Prandtla teorię linii nośnej

i jej rozwiązanie z pomocą metody Glauerta. Teoria linii nośnej znajduje zastosowanie do

wyznaczania wyżej wymienionych charakterystyk dla płatów nośnych cechujących się

dużym wydłużeniem (rzędu 5 i większym) oraz niewielkim kątem skosu (do ok. 15 stopni)

w liniowym zakresie siły nośnej [1]. Przeprowadzenie obliczeń dla szeregu kątów natarcia

umożliwia wyznaczenie charakterystyk od niego zależnych, a więc: pochodnej

aerodynamicznej i współczynników siły nośnej oraz oporu indukowanego w funkcji kata

natarcia.

Do implementacji opracowanego algorytmu posłużono się językiem programowania

C++. Z wykorzystaniem owego języka utworzony został kod źródłowy realizujący

powyższe zadanie. Za przechowywanie danych, zarówno wejściowych jak i wynikowych,

oraz prowadzenie obliczeń odpowiada utworzona klasa Wing.

- 5 -

2. Wprowadzanie

W programie zastosowano także graficzny interfejs użytkownika, ułatwiający

posługiwanie się programem, wprowadzanie danych i umożliwiającym prezentację

wyników (także w formie graficznej). Do zaprojektowania interfejsu wykorzystany została

aplikacja Qt Designer wchodząca w skład zestawu Qt Toolkit.

- 6 -

3. Teoretyczne podstawy programu

3. Teoretyczne podstawy programu

3.1. Teoria profilu cienkiego

Dla profilu o maksymalnej grubości nie przekraczającej w przybliżeniu

12% długości cięciwy opływanego płynem nielepkim pod niewielkim kątem natarcia

można przyjąć, że wypadkowa siła aerodynamiczna i moment działające na profil zależą

wyłącznie od kąta natarcia i kształtu szkieletowej, a grubość profilu wzdłuż całej cięciwy

przyjąć można za zerową [2].

Rysunek 3.1.1 [3]

Opływ takiego profilu opisany jest poprzez superpozycję przepływu jednorodnego

oraz rozkładu cyrkulacji wzdłuż szkieletowej.

- 7 -

3. Teoretyczne podstawy programu

Całkowita cyrkulacja wokół profilu wyrażona jest następującym wzorem:

Γ=∫0

c

γds≈∫0

c

γ dx (3.1.1)

Z prawa Kutty-Żukowskiego elementarna siła nośna profilu o cyrkulacji

Γ i rozkładzie cyrkulacji γ równa jest:

l=ρV ∞Γ=ρV ∞∫0

c

γdx (3.1.2)

Podstawiając 3.1.9 do 3.1.2:

l=∫0

c

ρV ∞ γ dx=∫0

c

p dx (3.1.3)

Różnicę ciśnień pomiędzy górna, a dolną powierzchnią szkieletowej można pokazać

stosując równanie Bernoulliego. Dla dowolnie wybranego punktu wzdłuż cięciwy

o współrzędnej x1 równanie Bernoulliego, dla górnej powierzchni ma postać:

p1+12ρ(V ∞+v1)

2=p0+12ρV ∞

2 (3.1.4)

a dla dolnej powierzchni:

p2+12ρ (V ∞+v2)

2= p0+12ρV ∞

2 (3.1.5)

Różnica ciśnień pomiędzy górna, a dolną powierzchnią szkieletowej wyrażona

jest zatem następującym wzorem:

p2− p1=12

ρV ∞2 [2( v1

V ∞−

v2

V ∞)+( v1

V ∞)

2

−( v2

V ∞)

2] (3.1.6)

Zakładając, że ( v1

V ∞)

2

≈0 oraz ( v2

V ∞)

2

≈0 :

p= p2−p1=ρV ∞ (v1−v2) (3.1.7)

Cyrkulacja wokół elementarnego odcinka cięciwy opisana jest zależnością:

γdx=(V ∞+v1)dx−(V ∞+v2)dx=(v1−v2)dx (3.1.8)

Podstawiając 3.1.8 do 3.1.7:

p=ρV ∞(v1−v2)=ρV ∞ γ (3.1.9)

- 8 -

3. Teoretyczne podstawy programu

Zakładając, że sinα≈α mierzony w radianach:

sin(dydx)≈ dy

dx= v+V ∞sinα

V ∞+v1(3.1.10)

(V ∞+v1)dydx

=v+V ∞α (3.1.11)

Rysunek 3.1.2 [4]

Składnik v1dydx można pominąć [5], a prędkość v jest prędkością indukowaną

w punkcie x1 przez wszystkie wiry związane z rozkładem cyrkulacji γ i wyrażona

jest następującą zależnością:

v= 12π∫0

c γx−x1

dx (3.1.12)

Podstawiając 3.1.12 do 3.1.11:

V ∞(dydx

−α)= 12π∫0

c γx− x1

dx (3.1.13)

Równanie 3.1.13 jest podstawowym równaniem teorii profilu cienkiego [6].

Jego rozwiązanie sprowadza się do wyznaczania rozkładu cyrkulacji γ odpowiadającej

rozpatrywanemu profilowi.

- 9 -

3. Teoretyczne podstawy programu

3.2. Opływ płata o skończonym wydłużeniu – model wirowy

Bryła geometryczna opływana stacjonarnym strumieniem płynu, potencjalnym na

zewnątrz tej bryły, nie może być modelem płata nośnego [7]. Do opisu płata użyty zatem

został model wirowy.

Cechy charakterystyczne wynikające z właściwości ruchu wirowego cieczy

doskonałej jakie musi posiadać model wirowy płata to [8]:

▪ linie wirowe muszą pokrywać się z liniami prądu;

▪ linia wirowa musi zaczynać się w punkcie na ściance płata i rozciągać

się do nieskończoności;

▪ linia wirowa musi zaczynać się w osobliwym punkcie pola prędkości

(w tym przypadku – punkt na krawędzi spływu).

Dodatkowymi założeniami, upraszczającymi model, dla płata o stosunkowo dużym

wydłużeniu i niewielkim skosie są [9]:

▪ płat nośny można zastąpić linią osobliwą, nazywaną linią nośną, będącą

początkiem powierzchni wirowej reprezentującej cienki obszar za płatem

wypełniony silnie zawirowanym płynem;

▪ linia nośna jest odcinkiem prostej;

▪ powierzchnia wirowa jest płaskim pasem o szerokości równej rozpiętości

płata nośnego (Rysunek 3.2.1), równoległym do prędkości strumienia

niezaburzonego.

Rysunek 3.2.1 [10]

- 10 -

3. Teoretyczne podstawy programu

Każda z linii wirowych, które tworzą powierzchnię wirową, wspomnianą powyżej,

może być traktowana jak wir podkowiasty, składający się z wiru związanego

(pokrywającego się z linią osobliwą zastępującą płat nośny) oraz dwu wirów swobodnych

(rozciągających się do nieskończoności za płatem).

W takim ujęciu linia nośna jest superpozycją nieskończonej ilości wirów związanych

odpowiadających profilom przekrojów poprzecznych płata nośnego.

3.3. Teoria linii nośnej Prandtla

Teoria linii nośnej Prandtla (zwana czasem, zwłaszcza w anglojęzycznej literaturze,

teorią Prandtla-Lanchestera, lub nawet teorią Lanchestera [11]) została opublikowana

w języku niemieckim w latach 1918-1919 przez Ludwika Prandtla, a w 1921 roku National

Advisory Committee for Aeronautics wydała angielskojęzyczny dokument (NACA Report

No. 116) przygotowany przez Prandtla na temat m.in. teorii linii nośnej.

Rysunek 3.3.1 [12]

Na Rysunku 3.3.1 przedstawiony jest układ współrzędnych xyz, w którym

oś x jest równoległa to kierunku prędkości strumienia niezaburzonego, oś y pokrywa

się z linią osobliwą zastępująca w modelu wirowym płat nośny, a oś z jest ortogonalna

do płaszczyzny utworzonej przez osie x i y. W takim układzie składowe siły

aerodynamicznej, działającej na płat, równoległe do osi x i z są równe odpowiednio sile

oporu aerodynamicznego i sile nośnej płata [13].

- 11 -

3. Teoretyczne podstawy programu

Każdy z wirów swobodnych („spływających” z końców płata) indukuje pole

prędkości. Suma prędkości, wytworzona przez te wiry, na linii osobliwej zastępującej płat

nośny nazywana jest prędkością indukowaną i w przyjętym układzie współrzędnych

ma kierunek osi z (jest normalna do płaszczyzny wirowej). Zgodnie z przyjętymi

w Rozdziale 1 konwencjami prędkość indukowana oznaczana jest symbolem Vi, natomiast

kąt zawarty pomiędzy prędkością strumienia niezaburzonego, a prędkością indukowaną

nazywany jest indukowanym kątem natarcia [14] i oznaczany symbolem αi, kąt ten

mierzony zgodnie z obrotem osi z do osi x. Wypadkowa prędkości indukowanej

i prędkości strumienia niezaburzonego w funkcji współrzędnej rozpiętości oznaczona jest

V(y), gdzie:

V ( y )=V i( y)+V ∞ (3.3.1)

oraz:

αi=arctan(− V i

V ∞)≈−

V i

V ∞(3.3.2)

Na Rysunku 3.3.2 przedstawiony jest trójkąt prędkości oraz kąta natarcia

indukowany kąt natarcia.

Rysunek 3.3.2 [15]

Wartość modułu prędkości dVi, indukowanej w dowolnym punkcie linii nośnej

nie będącym jej punktem końcowym poprzez elementarny wir swobodny wyraża

się na mocy prawa Biota i Savarta [16] następującą zależnością:

dV i=−(d Γd η ) d η

4π ( y−η) (3.3.3)

- 12 -

3. Teoretyczne podstawy programu

Natomiast moduł prędkości indukowanej przez wszystkie wiry swobodne

w rozpatrywanym punkcie:

V i( y)=−∫−L

2

L2 (d Γ

d η)d η

4 π ( y−η)(3.3.4)

Podstawiając 3.3.4 do 3.3.2:

αi ( y)=−V i ( y )V ∞

= 14πV ∞

∫−L

2

L2 ( d Γ

d η)d η

y−η(3.3.5)

Przyjmując, zgodnie z podstawowym założeniem teorii linii nośnej, że opływ

dowolnego elementu płata nośnego, wyciętego dwoma płaszczyznami oddalonymi

od siebie o odległość elementarną dy i normalnymi do linii osobliwej, zwanej linią nośną,

jest opływem płaskim odpowiedniego profilu, przy czym prędkość w nieskończoności

jest równa wypadkowej V(y) określonej zależnością 3.3.1 [17].

Rzeczywisty kąt natarcia profilu od współrzędnej mierzonej wzdłuż rozpiętości

określony jest następującym wzorem:

αrz( y)=α∞ ( y)−αi( y ) (3.3.6)

gdzie, zgodnie z konwencjami przyjętymi w Rozdziale 1:

α∞ – kąt natarcia mierzony między cięciwą, a prędkością strumienia niezaburzonego;

αi – indukowany kąt natarcia;

αrz – rzeczywisty kąt natarcia profilu;

Podstawiając 3.3.5 do 3.3.6:

αrz( y)=α∞−1

4πV ∞∫−L

2

L2 (d Γ

d η )d η

y−η(3.3.7)

Siła aerodynamiczna dR działająca na elementarny wycinek płata nośnego

jest normalna do prędkości wypadkowej V(y). W związku z tym można siłę dR rozłożyć

na składowe dX i dZ równoległe do osi x i z w przyjętym układzie współrzędnych, a więc

na elementarną siłę nośną i oporu aerodynamicznego wycinka płata.

- 13 -

3. Teoretyczne podstawy programu

Moduł wypadkowej siły elementarnej dR wynosi:

dR=ρV ( y)Γ( y )dy [18] (3.3.8)

Stąd wynika:

dZ=dR cosαi=dR( V ∞

V ( y ))=ρV ∞Γ( y )dy (3.3.9)

dX i=dR sin αi=dR(−V ∞

V ( y))=−ρV i Γ( y)dy (3.3.10)

Z=ρV ∞∫−L

2

L2

Γ( y )dy (3.3.11)

X i=−ρ∫−L

2

L2

V i( y )Γ( y )dy=ρ∫−L

2

L2 [∫−L

2

L2 (d Γ

d η )d η

4π( y−η)]Γ( y )dy (3.3.12)

Elementarna siła nośna działająca na wycinek płata nośnego wyrażone jest także

następującą zależnością:

dZ=C ZρV ∞

2

2c( y)dy [19] (3.3.13)

W liniowym zakresie CZ(α) współczynnik siły nośnej można opisać wzorem:

cZ=(d cZ

d α )(αrz−α0) (3.3.14)

Podstawiając 3.3.9 i 3.3.14 do 3.3.13:

Γ( y)dy=V ∞

2 (d cZ

d α )(αrz−α0)c ( y)dy (3.3.15)

Podstawiając αrz z 3.3.7 do 3.3.15:

Γ( y)=V ∞

2 (d cZ

d α )[α∞( y)−α0( y)−∫−L

2

L2 ( d Γ

d η )d η

y−η]c ( y ) (3.3.16)

Otrzymane równanie różniczkowo-całkowe (3.3.16) zwane jest podstawowym

równaniem teorii linii nośnej [20].

- 14 -

3. Teoretyczne podstawy programu

3.4. Metoda Glauerta

Rozwiązanie równania 3.3.16 sprowadza się do wyznaczenia rozkładu cyrkulacji

Γ(y) wzdłuż rozpiętości płata nośnego. Metodę rozwiązanie tego równania zaproponował

Glauert. Opiera się ona na wprowadzeniu dwu zmiennych niezależnych:

y=− L2

cos ξ ; η=−L2

cos ψ (3.4.1)

Rozwiązanie poszukiwane jest pod postacią szeregu:

Γ(ξ)=2LV∞∑n=1

An sin nξ (3.4.2)

Podstawiając 3.4.1 i 3.4.2 do 3.3.16:

∑n=1

Ansin nξ=14

c (ξ)L

dc Z

d α[α∞( y )−α0( y)−1

π∫0

π ∑n=1

An ncos n ψd ψ

cos ψ−cos ξ] (3.4.3)

Korzystając ze wzoru:

∫0

π cosn ψd ψcos ψ−cos ξ

=π sin n ξsin ξ [21] (3.4.4)

i wprowadzając oznaczenie:

μ(ξ)=14

c(ξ)L

d cZ

d α(3.4.5)

ostatecznie:

∑n=1

[sin ξ+nμ(ξ)] Ansin nξ=μ(ξ)[α∞ (ξ)−α0(ξ)]sin ξ (3.4.6)

Dla symetrycznego rozkładu cyrkulacji (lot prostoliniowy ustalony bez ślizgu)

znikają we wzorze 3.4.2 na cyrkulację Γ(y) współczynniki o indeksach parzystych.

Nieskończony szereg 3.4.2 można przybliżyć szeregiem skończonym

o m elementach. Aby wyznaczyć współczynniki An takiego szeregu posłużyć należy

się układem równań dla m przekrojów poprzecznych płata. Otrzymany w ten sposób układ

m równań z m niewiadomymi.

- 15 -

3. Teoretyczne podstawy programu

Na Rysunku 3.4.1 przedstawione są wyniki obliczeń rozkładu cyrkulacji dla czterech

płatów o różnych obrysach, stałym wzdłuż rozpiętości profilu i niezwichrzonych.

Rysunek 3.4.1 [22]

Podstawiając 3.4.2 do 3.3.4, 3.3.11 i 3.3.12:

V i(ξ)V ∞

=− 1sin ξ∑n=1

nAn sin nξ (3.4.7)

Z=ρV ∞2

2π L2 A1 (3.4.8)

X i=ρV ∞

2

2π L2∑

n=1

nAn2 (3.4.9)

Współczynnik oporu indukowanego wyrażony jest następującym wzorem:

c Xi=πΛ∑n=1

nAn2

(3.4.10)

Porównując prawe strony 3.3.9 oraz 3.3.13:

ρV ∞ Γ( y )dy=12ρV ∞

2 cZ( y)c ( y)dy (3.4.11)

Stąd:

cZ ( y)= 2Γ( y )V ∞ c( y) (3.4.12)

- 16 -

3. Teoretyczne podstawy programu

Podstawiając 3.4.1 oraz 3.4.2 do 3.4.12 oraz uwzględniając ξ= f ( y) :

cZ ( y)=4L∑

n=1

An sin [nξ( y )]

c( y )(3.4.13)

Natomiast z zależności 3.3.10 i 3.4.2:

c Xi( y )=−V i ( y)2L∑

n=1

Ansin [nξ( y)]

V ∞c( y)(3.4.14)

- 17 -

4. Ogólne informacje o programie

4. Ogólne informacje o programie

4.1. Platforma sprzętowa i rodzina systemów operacyjnych

Program został napisany na komputery w architekturze kompatybilnej

z komputerami klasy IBM/PC z procesorami należącym do rodziny x86 i dedykowane

jest dla systemów operacyjnych GNU/Linux, chociaż możliwe skompilowanie portu także

dla systemów operacyjnych rodziny MS Windows oraz Mac OS X, a także innych

systemów UNIX-like.

Program skompilowany został z wykorzystaniem kompilatora GCC – G++ 4.3.1

w środowisku openSUSE Linux 11.0 x86-32 z jądrem Linux 2.6.25.18-0.2-default

na komputerze klasy IBM/PC.

4.2. Wykorzystane narzędzia

4.2.1. Język C++

Język C++ powstał w 1983 roku i jest bezpośrednim następcą języka wysokiego

poziomu – C, stworzonego w 1972 roku w laboratoriach firmy Bell, jego nazwa nawiązuje

do tego faktu wykorzystując operator inkrementacji i nazwę swojego poprzednika.

C++ jest językiem wieloparadygmatowym co znaczy, że umożliwia podobnie

jak C programowanie strukturalne i proceduralne, a ponadto został rozszerzony względem

swojego poprzednika o mechanizmy umożliwiające programowanie zorientowane

obiektowo. Najważniejszą nowością względem C to m.in. : mechanizmy enkapsulacji,

klasy, obiekty oraz dziedziczenie.- 18 -

4. Ogólne informacje o programie

od pierwowzoru, będącego jedynie kompilatorem C, rozwijany jest jako GNU Compiler

Collection.

4.2.2. Qt Toolkit

Qt jest zestawem narzędzi programistycznych przenośnych pomiędzy trzema

najbardziej popularnymi platformami systemowymi na rynku komputerów osobistych [23],

to jest: MS Windows, Mac OS X oraz Linux. Qt rozwijane jest przez firmę Qt Software,

od 2008 roku należącą do fińskiego koncernu Nokia [24].

W skład zestawu wchodzi:

moc (ang. Meta Object Compiler) – preprocesor, który na podstawie plików

nagłówkowych generuje pliki źródłowe;

uic (ang. User Interface Compiler) – kompilator definicji interfejsów generowanych

za pośrednictwem programu Qt Designer;

qmake – program do zarządzania procesem kompilacji;

Qt Designer – środowisko typu RAD (ang. Rapid Application Development) służące

do szybkiego projektowania oraz prototypowania graficznych interfejsów

użytkownika;

Oprogramowanie zawarte w zestawie Qt jest otwarte i dostępne na zasadach wolnej

licencji GNU General Public License. Od wersji 4.5 planowane jest udostępnienie zestawu

na zasadach licencji GNU Lesser General Public License co umożliwi jego darmowe

wykorzystanie w oprogramowaniu własnościowym.

Biblioteka Qt dostarcza komponentów (w oryginalnym nazewnictwie

anglojęzycznym – widget) do budowania graficznego interfejsu aplikacji, będących

klasami potomnymi od klasy QWidget. Biblioteka zawiera także inne moduły,

nie związane z GUI, a umożliwiające na przykład korzystanie z baz danych, renderowanie

grafiki 3D, czy też obsługę formatu XML.

Z biblioteki Qt korzysta wiele aplikacji, m. in: środowisko graficzne dla systemów

rodziny UNIX-like – KDE, przeglądarka internetowa Opera, czy komunikator internetowy

Gadu-Gadu.

- 19 -

4. Ogólne informacje o programie

Qt zapewnia obsługę zdarzeń w oparciu o mechanizm sygnałów emitowanych

przez poszczególne elementy interfejsu i slotów – funkcji składowych wywoływanych

po emisji sygnału połączonego z zadanym slotem.

Qt Toolkit może być alternatywą dla porównywalnego środowiska typu RAD jakim

jest C++ Builder, produkowany przez firmę Borland, jednak jego darmowa wersja

jest znacznie uboższa, a licencja ogranicza użytkowanie jedynie do zastosowań osobistych.

Innym podobnym zestawem jest GTK+ czyli The GIMP Toolkit, który pierwotnie

przeznaczony był dla programu do edycji grafiki – GNU Image Manipulation Program.

Odpowiednikiem Qt Designer dla GTK+ jest aplikacja Glade Interface Designer. Jednak

w niniejszym przypadku wykorzystany został zestaw Qt.

- 20 -

5. Opis programu

5. Opis programu

5.1. klasa Wing

Klasa Wing odpowiada za przechowywanie, zarządzanie dostępem

oraz wykonywanie obliczeń na danych bezpośrednio związanych z płatem nośnym,

czyli: wejściowych danych geometrycznych, parametrów obliczeń, danych pośrednich

oraz wyników w postaci charakterystyk aerodynamicznych. Rozwiązanie

takie, umożliwiające w jednej spójnej formie umieszczenie danych i narzędzi

do posługiwania się nimi, jest jednym z najważniejszych atrybutów programowania

zorientowanego obiektowo i nosi nazwę enkapsulacji [25]. Definicja klasy Wing

przedstawiona jest na Listingu A-4, natomiast jej plik nagłówkowy na Listingu A-3.

5.1.1. Zarządzanie danymi

Klasa Wing odpowiada za kontrolę poprawności wprowadzanych

przez jej użytkownika (programistę) danych, dzięki wykorzystaniu wbudowanego w C++

mechanizmu określania dostępu do danych składowych klasy jako private, public

lub protected. Wszystkie dane składowe klasy Wing mają status dostępu do nich określony

jako private, co oznacza ze dostęp do nich możliwy jest jedynie z wnętrza klasy.

Aby umożliwić użytkownikowi klasy dostęp do wybranych danych, a jednocześnie

zapewnić poprawność ich wprowadzania klasa Wing zawiera zestaw odpowiednich funkcji

składowych służących do przypisywania oraz odczytywania wartości danych składowych.

Dzięki temu możliwa jest jeszcze ściślejsza kontrola nad dostępem do danych.

Dla przykładu aspect_ratio jest zmienną przechowującą wydłużenie geometryczne płata

- 21 -

5. Opis programu

nośnego obliczone z danych geometrycznych poszczególnych przekrojów skrzydła

wprowadzonych przez użytkownika aplikacji lub wczytanych z pliku. Wartość

tej zmiennej jest przeliczana za każdym razem gdy te dane zostaną zmienione, a więc

nie ma żadnej uzasadnionej potrzeby dostępu do niej w celu przypisania jej nowej

wartości, brak więc jest funkcji składowej temu służącej. Odczyt wartości zmiennej

składowej aspect_ratio jest natomiast całkowicie uzasadniony, służy do tego celu funkcja

składowa o dostępie public getAspectRatio, której definicja przedstawiona

jest na Listingu 5.1.1.

1 double Wing::getAspectRatio() {2 return aspect_ratio ;3 }

Listing 5.1.1

W przypadku danych składowych, do których przypisanie wartości

przez użytkownika klasy jest pożądane, funkcja realizująca takie zadania powinna

najpierw zweryfikować poprawność przekazanych wartości. Na Listingu 5.1.2

przedstawiona jest definicja funkcji setParameters realizującej zapis parametrów obliczeń

taki jak: kąty natarcia, prędkość i gęstość powietrza, liczbę sekcji płata nośnego osiąganą

podczas interpolacji oraz dokładność przybliżenia szeregu Fouriera.

1 bool Wing::setParameters( double a_start, double a_finish, int a_iterations, double f_velocity, double f_density, int s_iterations, int f_accuracy ) {

2 bool input_valid = true ;34 if ( a_start == a_finish ) {5 if ( ! a_iterations == 1 ) input_valid = false ;6 } else if ( a_start < a_finish ) {7 if ( ! a_iterations > 1 ) input_valid = false ;8 } else9 input_valid = false ;1011 if ( ! f_velocity > 0.0 ) input_valid = false ;12 if ( ! f_density > 0.0 ) input_valid = false ;13 if ( ! s_iterations >= sections ) input_valid = false ;14 if ( ! s_iterations > f_accuracy ) input_valid = false ;15 if ( input_valid ) {16 aoa_start = a_start ;

- 22 -

5. Opis programu

17 aoa_finish = a_finish ;18 aoa_iterations = a_iterations ;19 fluid_velocity = f_velocity ;20 fluid_density = f_density ;21 sections_iterations = s_iterations ;22 fourier_accuracy = 2 * f_accuracy - 1 ;23 parameters_saved = true ;24 }2526 return input_valid ;2728 }

Listing 5.1.2

Funkcja setParameters w pierwszej kolejności sprawdza warunki poprawności

wprowadzonych wartości. Wartość początkowa iteracji po kącie natarcia nie może

być większa od wartości końcowej, w przypadku gdy są sobie równe ilości iteracji musi

być równa 1, w innym przypadku musi być większa od 1. Prędkość i gęstość powietrza

muszą być liczbami dodatnimi, ilość sekcji po interpolacji powinna być co najmniej równa

ilości sekcji wprowadzonych przez użytkownika, a dokładność przybliżenie szeregu

Fouriera nie może być większa niż ilość sekcji osiąganych podczas interpolacji. Dopiero

po sprawdzeniu wszystkich warunków następuje przypisanie wartości. Funkcja

setParameters jest typu bool co oznacza, że zwraca jedną z dwóch wartości true albo false.

Wartość true zwracana jest gdy wszystkie wartości spełniają warunki i nastąpiło

przypisanie, natomiast false gdy choć jedna z podanych wartości jest niepoprawna.

Analogiczne mechanizmy stosowane są w stosunku do wszystkich danych

składowych, do których dostęp, czy to zapis czy odczyt, jest niezbędny.

Rozmiar wielu zmiennych składowych uzależniony jest od wartości innych, tak jest

na przykład w przypadku zmiennej lift_coefficient, w której przechowywane są wartości

współczynnika siły nośnej płata nośnego, dla każdej iteracji kąta natarcia. Z tego powodu

wykorzystywany jest mechanizm wskaźników do dynamicznego tworzenia tablic,

w których przechowywane są tego typu wartości. Przy wielokrotnym przeliczaniu

wyników, podczas pracy na tej samej instancji klasy Wing, dochodzi wielokrotnie

do takiego tworzenia tablic. O ile zajęta wcześniej pamięć nie zostanie zwolniona

to przy każdym kolejnym przeliczeniu zmniejszać się będą jej zasoby. Takie zjawisko

- 23 -

5. Opis programu

nazywane jest wyciekaniem pamięci [26]. Zwalnianiem pamięci zajmuje się funkcja

releaseResults, która przed każdym nowym przeliczeniem usuwa wyniki poprzedniego

i zwalnia pamięć zarezerwowaną na ich przechowywanie. Definicja funkcji releaseResults

przedstawiona jest na Listingu 5.1.3.

1 void Wing::releaseResults () {2 int i ;3 for ( i = 0; i < old_accuracy; i++ ) {4 delete [] equations_lhs[i] ;5 equations_lhs[i] = 0 ;6 }78 for ( i = 0; i < old_aoa_iterations; i++ ) {9 delete [] equations_rhs[i] ;10 delete [] fourier_terms[i] ;11 delete [] gamma[i] ;12 delete [] lift_coefficient_distribution[i] ;13 delete [] induced_velocity_distribution[i] ;14 delete [] induced_drag_coefficient_distribution[i] ;15 equations_rhs[i] = 0 ;16 fourier_terms[i] = 0 ;17 gamma[i] = 0 ;18 lift_coefficient_distribution[i] = 0 ;19 induced_velocity_distribution[i] = 0 ;20 induced_drag_coefficient_distribution[i] = 0 ;21 }2223 delete [] equations_lhs ;24 delete [] equations_rhs ;25 delete [] equations_span ;26 delete [] fourier_terms ;27 delete [] gamma ;28 delete [] lift_coefficient_distribution ;29 delete [] induced_velocity_distribution ;30 delete [] induced_drag_coefficient_distribution ;31 delete [] lift_coefficient ; 32 delete [] induced_drag_coefficient ;33 equations_lhs = 0 ;

- 24 -

5. Opis programu

34 equations_rhs = 0 ;35 equations_span = 0 ;36 fourier_terms = 0 ;37 gamma = 0 ;38 lift_coefficient_distribution = 0 ;39 induced_velocity_distribution = 0 ;40 induced_drag_coefficient_distribution = 0 ;41 lift_coefficient = 0 ; 42 induced_drag_coefficient = 0 ;4344 delete [] wingspan ;45 delete [] chord_length ;46 delete [] lift_curve_slope ;47 delete [] angle_of_0_lift_deg ;48 delete [] angle_of_0_lift_rad ;49 delete [] fi ;50 delete [] mi ;5152 wingspan = 0 ;53 chord_length = 0;54 lift_curve_slope = 0 ;55 angle_of_0_lift_deg = 0 ;56 angle_of_0_lift_rad = 0 ;57 fi = 0 ;58 mi = 0 ;5960 old_accuracy = fourier_accuracy ;61 old_aoa_iterations = aoa_iterations ;62 }

Listing 5.1.3

5.1.2. Algorytm obliczeniowy i jego implementacja

Przeprowadzeniem obliczeń na podstawie wprowadzonych danych zajmuje

się, przedstawiona na Listingu 5.1.4, funkcja składowa compute oraz szereg funkcji przez

nią wywoływanych. Funkcja compute ma typ bool i zwraca wartość true jeżeli obliczenia

powiodły się oraz false jeżeli wystąpił jakikolwiek błąd.

- 25 -

5. Opis programu

Ponadto jeżeli zmienna składowa debug_mode ma przypisaną wartość true funkcja

drukuje do plików tymczasowych wartości wprowadzonych przez użytkownika danych

geometrycznych skrzydła, parametrów obliczeń oraz danych pośrednich

wykorzystywanych podczas obliczeń.

Funkcja compute wywołuje także funkcję releaseResults przedstawioną

na Listingu 5.1.3, służącą do zwalniana pamięci zarezerwowanej podczas wcześniejszych

obliczeń.

1 bool Wing::compute() {2 bool ret = true ;3 if ( sections < 2 )4 return false ;5 if ( ! parameters_saved )6 return false ;7 releaseResults() ;8 if ( debug_mode ) writeParametersToFile() ;9 iterateAoA() ;10 if ( debug_mode ) writeAoAToFile() ;11 interpolateSections() ;12 if ( debug_mode ) writeInterpolatedToFile() ;13 rewriteSectionsForFullSpan() ;14 sortFullSpanSections() ;15 if ( debug_mode ) writeFullspanToFile() ;16 createEquations() ;17 if ( debug_mode ) writeEquationsToFile() ;18 if ( ! solveEquations() ) ret = false ;19 if ( debug_mode && ret ) writeFourierToFile() ;20 if ( ret ) calculateCharacteristics() ;21 if ( ret )22 results_uptodate = true ;23 else24 results_uptodate = false ;2526 return ret ;27 }

Listing 5.1.4

- 26 -

5. Opis programu

Kolejne kroki obliczeń realizowane są przez następujące funkcje składowe klasy

Wing: iterateAoA, interpolateSections, rewriteSectionsForFullSpan, sortFullSpanSections,

createEquations, solveEquations i calculateCharacteristics.

W pierwszej kolejności, na podstawie danych podanych przez użytkownika,

tworzone są zestawy danych wejściowych dla obliczeń, to jest: wartości kątów natarcia,

dla których będą wyznaczane charakterystyki aerodynamiczne oraz dane kolejnych

przekrojów poprzecznych płata (geometria, kąt zerowej siły nośnej, pochodna

aerodynamiczna) uzyskanych na drodze interpolacji liniowej.

Wartości kolejnych kątów natarcia, dla których prowadzone są obliczenia

przechowywane są w tablicach, na które wskazują wskaźniki angle_of_attack_deg

(wartości wyrażone w stopniach – służące do prezentacji wyników)

oraz angle_of_attack_rad (wartości wyrażane w radianach – służące do obliczeń).

Obie tablice są typu double i tworzone są dynamicznie przez funkcję składową iterateAoA

przedstawioną na Listingu 5.1.5, która też oblicza i przypisuje wartości kolejnych iteracji

kąta natarcia.

1 void Wing::iterateAoA() {2 int i ;34 if ( aoa_iterations > 1 )5 aoa_step = (aoa_finish – aoa_start) / ( (double)aoa_iterations - 1 );6 else7 aoa_step = 0.0 ;89 angle_of_attack_deg = new double[aoa_iterations] ;10 angle_of_attack_rad = new double[aoa_iterations] ;1112 for ( i = 0; i < aoa_iterations; i++ ) {13 angle_of_attack_deg[i] = aoa_start + aoa_step * (double)i ;14 angle_of_attack_rad[i] = 2 * pi() * angle_of_attack_deg[i] / 360 ;15 }16 }

Listing 5.1.5

Interpolacją danych dla kolejnych przekrojów płata zajmuje się funkcja

interpolateSections, uzyskana współrzędna po rozpiętości, długość cięciwy, pochodna

- 27 -

5. Opis programu

aerodynamiczna oraz kąt zerowej siły nośnej mierzony w stopniach i radianach

zapisywane są odpowiednio w tablicach, na które wskazują wskaźniki: wingspan,

chord_length, lift_curve_slope, angle_of_0_lift_deg oraz angle_of_0_lift_rad.

Dane te odpowiadają przekrojom jednej połówki płata (prawego – zgodnie

z przyjętym w Rozdziale 3.3 układem współrzędnych), gdzie elementy o indeksie 0 tablic

wymienionych w powyższym akapicie odpowiadają przekrojowi w płaszczyźnie symetrii,

natomiast ostatnie elementy przekrojowi na końcówce płata nośnego. Zbudowaniem tablic

danych dla pełnej rozpiętości zajmuje się funkcja rewriteSectionsForFullSpan. Funkcja

ta tworzy także dwie tablice, wskazywane przez fi i mi, w których przechowywane

są wartości ξ (3.4.1) i µ (3.4.5).

W kolejny kroku, na podstawie opisanej w Rozdziale 3 metody Glauerta, tworzona

jest dwuwymiarowa tablica, na która wskazuje wskaźnik equations_lhs, która odpowiada

macierzy głównej układu równań wykorzystywanego w metodzie Glauerta. Zadanie

to realizowane jest przez funkcję składową klasy Wing – createEquations. Funkcja

ta tworzy także drugą tablicę dwuwymiarową (equations_rhs), w której przechowywane

są wartości wyrazów wolnych równań dla poszczególnych kątów natarcia

odpowiadającym kątom natarcia przechowywanym w tablicach angle_of_attack_deg

oraz angle_of_attack_rad.

Ponieważ elementy lewych stron równań należących do wspomnianego układu

nie zależą od kąta natarcia, nie ma potrzeby tworzenia macierzy głównej owego układu

dla poszczególnych kątów natarcia.

Po utworzeniu tablic wskazywanych przez equations_lhs i equations_rhs

wywoływana jest funkcja składowa solveEquations, która z wykorzystaniem procedury

GEN_SOLV, której definicja znajduje się na Listingu A-2, wyznacza wartości

m pierwszych współczynników An szeregu 3.4.2 dla wszystkich kątów natarcia

przechowywanych w tablicach wskazywanych przez angle_of_attack_deg

i angle_of_attack_rad. Przy czym m ma wartość odpowiadającą wartości przechowywanej

przez zmienna składową klasy Wing – fourier_accuracy. W ten sposób otrzymane wyniki

zapisywane są do dwuwymiarowej tablicy, której pierwszy indeks odpowiada indeksowi

tablic przechowujących kąty natarcia, natomiast drugi oznacza kolejne współczynniki

szeregu 3.4.2.

- 28 -

5. Opis programu

Ostatnim etapem obliczeń jest wyznaczenie charakterystyk aerodynamicznych płata

dla kolejnych kątów natarcia na podstawie uzyskanych wartości współczynników An.

Realizowane jest to przez funkcję calculateCharacteristics przedstawioną

na Listingu 5.1.6.

1 void Wing::calculateCharacteristics() {2 int a, i, n ;3 double sum_nAn2, sum_nAnsin, tmp_gamma ;45 gamma = new double* [aoa_iterations] ;6 lift_coefficient_distribution = new double* [aoa_iterations] ;7 induced_velocity_distribution = new double* [aoa_iterations] ;8 induced_drag_coefficient_distribution = new double* [aoa_iterations] ;9 lift_coefficient = new double [aoa_iterations] ;10 induced_drag_coefficient = new double [aoa_iterations] ;1112 for ( a = 0; a < aoa_iterations; a++ ) {13 gamma[a] = new double [sections_fullspan ] ;14 lift_coefficient_distribution[a] = new double [ sections_fullspan ] ;15 induced_velocity_distribution[a] = new double [ sections_fullspan ] ;16 induced_drag_coefficient_distribution[a] = new double [ sections_fullspan

] ;17 }1819 for ( a = 0; a < aoa_iterations; a++ ) {20 lift_coefficient[a] = 0.0 ;21 for ( i = 0; i < sections_fullspan; i++ ) {22 tmp_gamma = 0.0 ;23 sum_nAn2 = 0.0 ;24 sum_nAnsin = 0.0 ;25 for ( n = 0; n < fourier_accuracy; n++ ) {26 tmp_gamma = tmp_gamma + sin( ( (double)n + 1 ) * fi[i] ) *

fourier_terms[a][n] ;27 sum_nAnsin += ( (double)n + 1 ) * sin( ( (double)n + 1 ) *

fi[i] ) * fourier_terms[a][n] ;28 sum_nAn2 += ( (double)n + 1 ) * pow( fourier_terms[a][n], 2 ) ;29 }30 tmp_gamma = tmp_gamma * ( 2 * wing_span * fluid_velocity ) ;31 gamma[a][i] = tmp_gamma ;

- 29 -

5. Opis programu

32 lift_coefficient_distribution[a][i] = 2 * gamma[a][i] / ( fluid_velocity * chord_length[i] ) ;

33 induced_velocity_distribution[a][i] = ( i != 0 && i != sections_fullspan - 1 ) ? ( ( -1 ) / sin( fi[i] ) * sum_nAnsin ) : ( 0 ) ;

34 induced_drag_coefficient_distribution[a][i] = ( -induced_velocity_distribution[a][i] ) * gamma[a][i] / ( fluid_velocity * fluid_velocity * chord_length[i] ) ;

35 if ( i > 0 )36 lift_coefficient[a] += ( wingspan[i] - wingspan[i-1] ) *

( lift_coefficient_distribution[a][i] + lift_coefficient_distribution[a][i - 1] ) / 2 ;

37 }38 lift_coefficient[a] /= wing_span ;39 induced_drag_coefficient[a] = pi() * aspect_ratio * sum_nAn2 ;40 }41 }

Listing 5.1.6

Poniżej opisane zostały wielkości przechowywane przez odpowiadające poniższym

wskaźnikom tablice, oraz zależności matematyczne, na podstawie których są wyznaczane.

gamma – elementarna cyrkulacja w danym przekroju płata, z 3.4.2;

lift_coefficient_distribution – elementarny współczynnik siły nośnej, z 3.4.12;

induced_velocity_distribution – prędkość indukowana odniesiona do prędkości

strumienia niezaburzonego w danym przekroju płata, z 3.4.7;

induced_drag_coefficient_distribution – elementarny współczynnik oporu

indukowanego, z 3.3.10 oraz 3.4.2;

lift_coefficient – współczynnik siły nośnej płata, uzyskiwany poprzez całkowanie

metodą trapezów rozkładu współczynnika siły nośnej wzdłuż rozpiętości;

induced_drag_coefficient – współczynnik oporu indukowanego płata, z 3.4.10.

Pierwsze indeksy tablic wskazywanych przez gamma, lift_coefficient_ditribution,

induced_velocity_distribution oraz induced_drag_coefficient_distribution oraz indeksy

tablic lift_coefficient i induced_drag_coefficient odpowiadają indeksom kolejnych kątów

natarcia, natomiast drugie indeksy tablic dwuwymiarowych indeksom kolejnych

przekrojów płata wzdłuż rozpiętości.

Obliczenia wykonywane są w dwu pętlach, pierwszej iterującej po kolejnych kątach

natarcia oraz drugiej iterującej po kolejnych przekrojach poprzecznych płata nośnego.

- 30 -

5. Opis programu

Wykorzystaną do wyznaczenia współczynnika siły nośnej metodę trapezów można

opisać w następujący sposób:

∫x1

x2

f (x )dx≈∑i=1

n h2[ f ( x1+(i−1)h)+ f ( x1+ih)] (5.1.1)

gdzie:

h=x2− x1

n(5.1.2)

h – krok całkowania;

n – ilość kroków całkowania.

5.1.3. Format pliku wynikowego

Na Rysunku 5.1.1 przedstawiono schematycznie strukturę pliku wynikowego.

Dane zapisywane są w postaci liczb oddzielonych znakami spacji lub końca wiersza, dane

będące w tej samej linii oddzielone spacjami traktować należy jak kolumny.

Ciemnoszare pola na Rysunku 5.1.1 służą jedynie opisowi tabel lub kolumn

i nie występują w pliku wynikowym, dane reprezentowane przez pola jasnoszare.

Pola sąsiadujące ze sobą w tej samej linii symbolizują dane będące w tej samej linii

i oddzielone znakiem spacji. Pola sąsiadujące ze sobą jeden nad drugim symbolizują dane

oddzielone znakiem końca linii. Pionowe strzałki umieszczone wewnątrz pól symbolizują

kolejne wiersze danego zestawu danych, oddzielone znakiem końca wiersza. Natomiast

strzałki poziome kolejne kolumny, oddzielone znakiem spacji.

Na Listingu 5.1.7 przedstawiony jest fragment funkcji składowej klasy Wing –

writeToFile realizujący zapis do pliku rozkładu cyrkulacji dla szeregu kątów natarcia.

1 for ( i = 0; i < sections_fullspan; i++ ) {2 for ( a = 0; a < aoa_iterations; a++ ) {3 if ( a == aoa_iterations -1 )4 fprintf( fl, "%f", lift_coefficient_distribution[a][i] ) ;5 else { fprintf( fl, "%f ", lift_coefficient_distribution[a][i] ) ; }6 }7 fprintf( fl, "\n" ) ;8 }

Listing 5.1.7

- 31 -

5. Opis programu

Rysunek 5.1.1

- 32 -

5. Opis programu

5.2. Graficzny interfejs użytkownika – GUI

Interfejs użytkownika w całości jest opisany w języku angielskim

i z wykorzystaniem oznaczeń stosowanych w literaturze anglojęzycznej.

Do zaprojektowania GUI wykorzystana została aplikacji Qt Designer należącej do zestawu

Qt Toolkit, z wykorzystaniem biblioteki komponentów Qt w wersji 3.3.

Główne okno aplikacji zawiera pasek menu i komponent zakładek umożliwiających

poruszanie się pomiędzy formularzami do wprowadzania danych geometrycznych

przekrojów płata, parametrów obliczeń oraz prezentacji wyników obliczeń.

W programie wykorzystano oraz wkompilowano bibliotekę widgetów do zastosowań

technicznych o nazwie Qwt – Qt Widget for Technical Applications w wersji 4.4.2.

Biblioteka ta dostarcza widget klasy QwtPlot, służący do prezentacji wykresów.

W podstawowym zestawie Qt brak jest podobnego widgetu, a jest on wielokrotnie

stosowany w opisywanym oprogramowaniu, m.in. do prezentacji otrzymanych wyników.

Biblioteka Qwt dostępna jest na zasadach licencji GNU Lesser General Public License,

co oznacza, że może być za darmo stosowana w oprogramowaniu własnościowym.

5.2.1. Wprowadzanie danych geometrycznych skrzydła

Tuż po włączeniu programu widoczna jest zawartość pierwszej zakładki – Wing

Data, na Rysunku 5.2.1 przedstawiony jest widok pierwszej zakładki przed

wprowadzeniem danych, natomiast na Rysunku 5.2.2 z wprowadzonymi danymi dla dwu

przekrojów płata – w osi symetrii oraz na końcówce.

Ramka kontrolek – Cross Section Editor umożliwia wprowadzanie, edycję

i usuwanie zestawów danych związanych z kolejnymi przekrojami poprzecznymi płata

nośnego. Tabela Cross Section Data służy prezentacji wartości owych danych oraz

wyborowi przekroju do edycji lub usunięcia. W ramce Wing Data zgrupowane są pola

wyświetlające globalne dane geometryczne płata, takie jak na przykład wydłużenie

geometryczne – Aspect Ratio. Ramka Planform Preview zawiera wykres prezentujący

w sposób graficzny geometrię obrysu płata na podstawie wprowadzonych danych

przekrojów.

- 33 -

5. Opis programu

Rysunek 5.2.1

Rysunek 5.2.2

- 34 -

5. Opis programu

Elementy zawarte w ramkach Planform Preview oraz Wing Data oraz przycisk Next

oraz zakładka Parameters pozostają nieaktywne do czasu aż ilość ilości wprowadzonych

zestawów danych przekroju jest równa co najmniej dwu.

W programie przyjęty został układ współrzędnych xy, w którym oś y jest równoległa

do osi samolotu w locie i leży w płaszczyźnie symetrii płata nośnego. Oś x natomiast jest

normalna do płaszczyzny symetrii i skierowana w prawą stronę.

W programie zaimplementowane zostały mechanizmy foolproof mające na celu

weryfikację poprawności wprowadzanych danych. Przykładem takiego mechanizmu

jest funkcja forceDouble, przedstawiona na Listingu 5.2.2, która uniemożliwia

wprowadzenie w pole tekstowe innych wartości niż liczba zmiennoprzecinkowa

(uniemożliwia wprowadzenie znaków nie wykorzystywanych do zapisu takich liczb,

np. liter), dodatkowo funkcja ta może także wymusić aby wprowadzane wartości były

nieujemne oraz ograniczyć ilość cyfr znaczących.

1 void MainWindow::lineWingSpan_textChanged( const QString & ) {2 forceDouble( lineWingSpan, 3, false, 2 ) ;3 }

Listing 5.2.1

Funkcja fourceDouble weryfikuje m.in. poprawność danych wprowadzanych do pola

lineWingSpan uniemożliwiając wprowadzenie liczby ujemnej oraz ograniczając ilość cyfr

znaczących do pięciu (dwie cyfry do zapisu części całkowitej i 3 cyfry do zapisu części

ułamkowej). Sygnał textChnaged emitowany przez pole lineWingSpan wywołuje,

przedstawiony na Listingu 5.2.1, slot lineWingSpan_tectChanged, natomiast slot

ten wywołuje funkcję forceDouble na polu lineWingSpan.

1 void MainWindow::forceDouble( QLineEdit* q_line_edit, int round, bool allow_neg, int max_before_point ) {

2 q_line_edit->setReadOnly( true ) ;34 int i, point_pos, pos ;5 char c = '\0' ;6 bool is_double = true ;7 bool point_used = false ;8 bool coma_used = false ;9 bool minus_used = false ;10 char* old_text ;

- 35 -

5. Opis programu

11 char* tmp_text ;12 const char* new_text = q_line_edit->text() ;1314 tmp_text = new char[q_line_edit->text().length() + 1] ;15 point_pos = -1 ;1617 for ( i = 0; new_text[i] != '\0'; i++ ) {18 c = new_text[i] ;19 if ( c == ',' ) {20 tmp_text[i] = '.' ;21 coma_used = true ;22 } else23 tmp_text[i] = new_text[i] ;24 }2526 for ( pos = 0; new_text[pos] != '\0'; pos++ ) {27 c = tmp_text[pos] ;2829 if ( c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5'

|| c == '6' || c == '7' || c == '8' || c == '9' ) {30 if ( ( (point_pos + round) < pos ) && point_used ) {31 is_double = false ;32 break ;33 } else if ( pos >= max_before_point && !point_used && !minus_used ) {34 is_double = false ;35 break ;36 } else if ( pos > max_before_point && !point_used && minus_used ) {37 is_double = false ;38 break ;39 } else40 continue ;41 } else if ( ( !point_used ) && c == '.' ) {42 point_used = true ;43 point_pos = pos ;44 continue ;45 } else if ( pos == 0 && c == '-' ) {46 if ( allow_neg ) {47 minus_used = true ;48 continue ;

- 36 -

5. Opis programu

49 }else {50 is_double = false ;51 break ;52 }53 } else {54 is_double = false ;55 break ;56 }57 }5859 if ( ! is_double ) {60 old_text = new char[q_line_edit->text().length()] ;61 for ( i = 0; ; i++ ) {62 if ( i < pos ) {63 old_text[i] = tmp_text[i] ;64 if ( tmp_text[i] == '\0') break ;65 } else {66 old_text[i] = new_text[i+1] ;67 if ( tmp_text[i+1] == '\0') break ;68 }69 }70 q_line_edit->setText( old_text ) ;71 } else if ( coma_used )72 q_line_edit->setText( tmp_text ) ;7374 q_line_edit->setReadOnly( false ) ;75 }

Listing 5.2.2

5.2.2. Wprowadzanie parametrów obliczeń

Na Rysunku 5.2.3 przedstawiony jest widok zakładki Parameters, służącej

do wprowadzania parametrów obliczeń takich jak: zakres i ilość iteracji kąta natarcia,

prędkość i gęstość powietrza, ilość przekrojów płata do zinterpolowania, dokładność

przybliżenia szeregu 3.4.2.

- 37 -

5. Opis programu

Przycisk Compute pozostaje nieaktywne do czasu poprawnego zapisania wartości

wszystkich parametrów. Przycisk Next oraz zakładka Results pozostają nieaktywne do

czasu zakończenia obliczeń charakterystyk aerodynamicznych.

Rysunek 5.2.3

5.2.3. Prezentacja wyników

W zakładce Results prezentowane są wyniki obliczeń w formie wykresów oraz

zestawień tabelarycznych, do przełączania widoku pomiędzy różne charakterystyki służy

dodatkowy zestaw zakładek, w skład którego wchodzą następujące pozycje:

▪ Lift Coef. - współczynnik siły nośnej od kąta natarcia;

▪ Induced Drag Coef. - współczynnik oporu indukowanego od kąta natarcia;

▪ Circulation Distribution – rozkład cyrkulacji;

▪ Lift Coef. Distribution – rozkład współczynnika siły nośnej;

▪ Induced Velocity Distribution – rozkład prędkości indukowanej;

▪ Induced Drag Coef. Distribution – rozkład współczynnika oporu

indukowanego;

- 38 -

5. Opis programu

Dwie pierwsze charakterystyki są prezentowane w funkcji kąta natarcia, natomiast

do przełączania pomiędzy wynikami pozostałych charakterystyk dla wszystkich iteracji

kąta natarcia służy pole Angle of Attack znajdujące się na górze widoku zakładki Results.

Na Rysunku 5.2.4 przedstawiony jest widok zakładki Results i prezentacje różnych

charakterystyk płata nośnego.

Rysunek 5.2.4

- 39 -

6. Analiza uzyskanych wyników

6. Analiza uzyskanych wyników

W celu podstawowej weryfikacji uzyskanych wyników sporządzone zostało

zestawienia rozkładu cyrkulacji Γ(y) dla czterech płatów o różnym obrysie. Obliczenia

zostały wykonane dla następujących parametrów: α∞ =5 deg., V∞ =60 m/s, ρ =1,225 kg/m3.

Wszystkie rozważane skrzydła mają stały wzdłuż rozpiętości profil NACA 642-212,

dane profilu [27] niezbędne do przeprowadzenia obliczeń:

pochodna aerodynamiczna – a = 6,303 1/rad;

kąt zerowej siły nośnej – α0 = -1,5 deg.

Ponadto wszystkie wykorzystane w obliczeniach płaty nośne są niezwichrzone,

a także wszystkie mają rozpiętość 12 metrów i zerowy kąt zaklinowania. Dane

geometryczne przekrojów poprzecznych skrzydeł, wprowadzone do programu celem

wykonania obliczeń zaprezentowane są w Tabelach 6.1 do 6.4.

Skrzydło o obrysie rombowym

Rozpiętość [m] Krawędź natarcia [m] Krawędź spływu [m]

0,000 0,000 2,200

6,000 0,750 0,751

Tabela 6.1

Skrzydło o obrysie trapezowym

Rozpiętość [m] Krawędź natarcia [m] Krawędź spływu [m]

0,000 0,000 1,550

6,000 0,200 1,000

Tabela 6.2

- 40 -

6. Analiza uzyskanych wyników

Skrzydło o obrysie prostokątnym

Rozpiętość [m] Krawędź natarcia [m] Krawędź spływu [m]

0,000 0,000 1,150

6,000 0,000 1,150

Tabela 6.3

Skrzydło o obrysie eliptycznym

Rozpiętość [m] Krawędź natarcia [m] Krawędź spływu [m]

0,000 0,000 1,500

0,300 0,007 1,486

0,600 0,029 1,443

0,900 0,045 1,409

1,200 0,067 1,366

1,500 0,082 1,335

1,800 0,100 1,300

2,100 0,120 1,260

2,400 0,143 1,214

2,700 0,160 1,180

3,000 0,179 1,142

3,300 0,200 1,100

3,600 0,224 1,053

3,900 0,266 0,969

4,200 0,282 0,936

4,500 0,300 0,900

4,800 0,320 0,859

5,100 0,344 0,812

5,400 0,372 0,756

5,700 0,409 0,682

6,000 0,500 0,500

Tabela 6.4

Wyniki obliczeń rozkładu cyrkulacji przedstawione są za pomocą Rysunku 6.1

oraz Tabeli 6.5.

Wstępna ocena uzyskanych wyników dokonana została na podstawie porównania

obliczonych rozkładów cyrkulacji z oczekiwanymi wynikami – Rysunek 3.4.1.

Na tej podstawie można stwierdzić, że program poprawnie wyznacza rozkład

cyrkulacji dla płatów o różnym obrysie.

- 41 -

6. Analiza uzyskanych wyników

Rysunek 6.1

Obrys płata

rombowy eliptyczny trapezowy prostokątny

2y/L Γ(y) Γ(y) Γ(y) Γ(y)

0,00 32,186 26,426 26,894 22,117

0,05 32,005 26,367 26,812 22,109

0,10 31,475 26,197 26,574 22,087

0,15 30,639 25,923 26,202 22,052

0,20 29,556 25,563 25,724 22,005

0,25 28,291 25,133 25,172 21,944

0,30 26,904 24,655 24,576 21,869

0,35 25,436 24,142 23,954 21,774

0,40 23,911 23,604 23,316 21,656

0,45 22,334 23,040 22,660 21,509

0,50 20,698 22,433 21,979 21,328

0,55 18,996 21,747 21,265 21,104

0,60 17,224 20,928 20,511 20,825

0,65 15,386 19,900 19,708 20,474

0,70 13,487 18,569 18,845 20,025

0,75 11,520 16,828 17,896 19,435

0,80 9,471 14,573 16,810 18,636

0,85 7,333 11,727 15,503 17,496

0,90 5,165 8,286 13,793 15,741

0,95 3,110 4,400 11,073 12,600

1,00 0,000 0,000 0,000 0,000

Tabela 6.5

- 42 -

0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90 1,000,000

5,000

10,000

15,000

20,000

25,000

30,000

35,000

rombowyeliptycznytrapezowyprostokątny

2y/L

Γ

6. Analiza uzyskanych wyników

W celu dalszej weryfikacji porównane zostały wyniki współczynnika siły nośnej

płata otrzymane za pomocą stworzonego oprogramowania z wynikami otrzymanymi

za pomocą symulacji numerycznej z wykorzystaniem programu FLUENT. Obliczenia

przeprowadzona dla płata o obrysie trapezowym, którego dane geometryczne przedstawia

Tabela 6.2, dla trzech różnych kątów natarcia i prędkości przepływu 60 m/s.

Uzyskane wyniki oraz wartości procentowe błędu względnego przedstawione

zostały w Tabeli 6.6.

Opracowany Program FLUENT Błąd Względny

α [deg] CZ [-] CZ [-] δ [%]

1,00 0,22 0,20213493 8,12

3,00 0,40 0,37158938 7,10

5,00 0,58 0,53382475 7,96

Tabela 6.6

Jak widać na przedstawionej tabeli są pewne rozbieżności wyników pomiędzy

uzyskanymi za pomocą opracowanego w ramach tej pracy kodu, a za pomocą symulacji

numerycznej. Jednak część z tych rozbieżności wynikać może z dokładności odczytu

charakterystyk (pochodna aerodynamiczna i kąt zerowej siły nośnej) profilu NACA 642-

212 z wykresu [27].

Wiedząc, że współczynnik siły nośnej płata obliczany jest za pomocą całkowania

rozkładu współczynnika siły nośnej wzdłuż cięciwy, założyć można, że także rozkład

współczynnika siły nośnej obliczany z wykorzystaniem stworzonego oprogramowania

nie jest obarczony dużym błędem.

Na Rysunkach 6.2 i 6.3 zamieszczono w celach informacyjnych wizualizację

rozkładu współczynnika ciśnienia odpowiednio na górnej i dolnej powierzchni płata przy

kącie natarcia 5 stopni i prędkości przepływu 60 m/s, uzyskane z wykorzystaniem

symulacji numerycznej w programie FLUENT.

- 43 -

6. Analiza uzyskanych wyników

Rysunek 6.2

Rysunek 6.3

- 44 -

7. Wnioski, możliwe zastosowania oraz możliwości rozwoju

7. Wnioski, możliwe zastosowania oraz możliwości rozwoju

Opracowany program znajduje zastosowanie przede wszystkim do wyznaczania

współczynnika siły nośnej płata nośnego, jego rozkładu wzdłuż rozpiętości

oraz współczynnika oporu indukowanego płata na podstawie zadanego obrysu i jego

rozkładu wzdłuż rozpiętości.

Program wykorzystać można podczas optymalizacji obrysu płata nośnego lub jego

końcówki pod względem minimalizacji oporu indukowanego. Innym zastosowaniem może

być pomoc w wyznaczaniu rozkładu momentu zginającego skrzydła na podstawie rozkładu

współczynnika siły nośnej wzdłuż rozpiętości.

Uwolnienie kodu źródłowego i udostępnienie go na zasadach wolnej licencji,

na przykład GNU Public General License niesie za sobą duże możliwości rozwoju

i popularyzacji stworzonego oprogramowania. Wiele istotnych projektów open-source

miało swój początek właśnie w uczelniach wyższych. Doskonałym tego przykładem jest

Licencja X11 wywodząca się z Massachusetts Institute of Technology. Ponieważ na rynku

brak jest podobnego wolnego oprogramowania może ono zyskać popularność w pewnych

kręgach związanych na przykład z modelarstwem i lotnictwem amatorskim.

Samo oprogramowanie jest we wczesnym stadium i wymaga szczegółowego

testowania i wniesienia poprawek zarówno w sferze interfejsu użytkownika

jak i algorytmu obliczeniowego.

Wykorzystana metoda Glauerta nie jest precyzyjna i może dawać niepoprawne

wyniki, dlatego należy rozważyć inny sposób rozwiązywania równania 3.3.16 na przykład

- 45 -

7. Wnioski, możliwe zastosowania oraz możliwości rozwoju

z wykorzystaniem numerycznych procedur rozwiązywania równań różniczkowo-

całkowych.

Kolejną funkcją oprogramowania wymagającą usprawnienia są formularze służące

zapisowi i odczytowi wyników do i z plików. Należałoby rozszerzyć je o pewne

funkcjonalności potwierdzenia nadpisania pliku wynikowego, pewne błędy występują

także podczas porzucania zmian względem wczytanego pliku.

- 46 -

Załączniki

Załączniki

A – Listingi ważniejszych kodów źródłowych

1 #ifndef LINEAR_SOLVER_H2 #define LINEAR_SOLVER_H34 /**5 * System of linear equations solver6 * Thanks to Franciszek Dul, Ph.D. - Warsaw University of Technology7 */89 inline void SWAP( double &a , double &b ) ;1011 int GEN_SOLV( double* x, double* A, int n, int m=1, double a_tol=1.e-12 ) ;1213 #endif

Listing A-1 – linear_solver.h

1 #include "../include/linear_solver.h"2 #include <cmath>3 #include <iostream>45 /**6 * System of linear equations solver7 * Thanks to Franciszek Dul, Ph.D. - Warsaw University of Technology

- 47 -

Załączniki

8 */910 inline void SWAP( double &a , double &b ){ double tmp = a; a = b; b = tmp; }111213 int GEN_SOLV( double* x , double* A , int n , int m , double a_tol ) {14 // n - dimension , m - number of RHS (if m = 1 Ax=b is solved) 15 // A(i,j) = A[n*j+i], i=1...n, j=1...n, 16 // x(i,j) = x[n*k+i], i=1...n, k=1...m, input: RHS; output x 1718 int i, j, jn, k, kn, ir, jx;19 double a_max , hr , d;2021 for( j = 0 , jn = 0; j < n; ++j , jn += n ) {22 a_max = fabs( A[j+jn] );23 ir = j;24 for( i = j+1; i < n; ++i ) {25 if ( ( d = fabs( A[i+jn] ) ) > a_max ) {26 a_max = d;27 ir = i;28 }29 }30 if ( a_max < a_tol ) {31 std::cerr << "ERR: GEN_SOLV , ierr = " << j << std::endl;32 return j;33 }34 if ( ir > j ) {35 for( k = 0 , kn = 0; k < n; ++k , kn += n )36 SWAP( A[j+kn] , A[ir+kn] );37 for( jx = 0 ; jx < m; ++jx )38 SWAP( x[n*jx+j] , x[n*jx+ir] );39 }40 hr = 1.0 / A[j+jn];41 for( jx = 0 ; jx < m; ++jx )42 x[n*jx+j] *= hr;43 for( i = j+1; i < n; ++i )44 A[j+i*n] *= hr;45 for( i = j+1; i < n; ++i ) {

- 48 -

Załączniki

46 hr = A[i+jn];47 for( k = j+1 , kn = k*n ; k < n; ++k , kn += n )48 A[i+kn] -= hr * A[j+kn];49 for( jx = 0 ; jx < m; ++jx )50 x[n*jx+i] -= hr * x[n*jx+j];51 }52 }53 for( i = n - 1; i >= 0; --i )54 for( j = i+1; j < n; ++j )55 for( jx = 0 ; jx < m; ++jx )56 x[n*jx+i] -= A[i+j*n] * x[n*jx+j];5758 return -1;59 }

Listing A-2 – linear_solver.cpp

1 #ifndef WING_H2 #define WING_H34 class Wing {5 private:6 /****************************************************************************7 ** PRIVATE MEMBER VARIABLES8 ****************************************************************************/9 char file_name[400] ;10 bool debug_mode ;11 // VARIABLES TO SET BEFORE COMPUTATIONS12 /*13 double* Wing::wing_cs_data[5] - Wing Cross Section Data14 [0] Wing Span Y Coordinate,15 [1] Leading Edge X Coordinate,16 [2] Trailing Edge X Coordinate,17 [3] Airfoil Lift Curve Slope,18 [4] Angle of Zero Lift19 */20 double* sections_data[5] ; 21 double wing_span, wing_area, aspect_ratio, taper_ratio ;

- 49 -

Załączniki

22 double aoa_start, aoa_finish, aoa_step ;23 int aoa_iterations ;24 double fluid_velocity, fluid_density ;25 int sections_iterations ;26 int sections_fullspan ;27 int fourier_accuracy ;28 int old_accuracy ;29 int old_aoa_iterations ;30 int sections ;31 bool results_uptodate ;32 bool parameters_saved ;33 // COMPUTATIONS RESULTS34 double* angle_of_attack_deg ;35 double* angle_of_attack_rad ;36 double* wingspan ;37 double* chord_length ;38 double* lift_curve_slope ;39 double* angle_of_0_lift_deg ; // angle of zero lift40 double* angle_of_0_lift_rad ; // angle of zero lift41 double* fi ;42 double* mi ;43 double** equations_lhs ;44 double** equations_rhs ;45 double* equations_span ;46 double** fourier_terms ;47 double** gamma ;48 double** lift_coefficient_distribution ;49 double** induced_velocity_distribution ;50 double** induced_drag_coefficient_distribution ;51 double* lift_coefficient ; 52 double* induced_drag_coefficient ;53 /****************************************************************************54 ** PRIVATE MEMBER FUNCTIONS55 ****************************************************************************/56 void calculateCharacteristics() ;57 void calculateGeometry() ;58 bool checkIfSectionExists( double span_y ) ;59 void createEquations() ;

- 50 -

Załączniki

60 void interpolateSections() ;61 void iterateAoA() ;62 double pi() ;63 void releaseResults() ;64 void rewriteSectionsForFullSpan() ;65 bool solveEquations() ;66 void sortFullSpanSections() ;67 void sortSectionsData() ;68 bool writeAoAToFile() ;69 bool writeEquationsToFile() ;70 bool writeFourierToFile() ;71 bool writeFullspanToFile() ;72 bool writeInterpolatedToFile() ;73 bool writeParametersToFile() ;74 bool writeWingInputToFile() ;75 76 public:77 /****************************************************************************78 ** PUBLIC MEMBER FUNCTIONS79 ****************************************************************************/80 Wing() ;81 ~Wing() ;82 bool addSectionData( double span_y, double le_x, double te_x, double

slope, double angle ) ;83 bool compute() ;84 bool deleteSectionData( int row ) ;85 bool editSectionData( double span_y, double le_x, double te_x, double

slope, double angle, int row ) ;86 double getAspectRatio() ;87 double getAoADeg( int aoa ) ;88 double getAoA_Finish() ;89 int getAoA_Iterations() ;90 double getAoA_Start() ;91 double getAoA_Step() ;92 double getDragCoef( int aoa ) ;93 double getDragCoefDist( int aoa, int section ) ;94 double getGamma( int aoa, int section ) ;95 double getFluidDensity() ;96 double getFluidVelocity() ;

- 51 -

Załączniki

97 int getFourierAccuracy() ;98 double getLiftCoef( int aoa ) ;99 double getLiftCoefDist( int aoa, int section ) ;100 int getSections() ;101 int getSectionsFullspan() ;102 int getSectionsIterations() ;103 double getSectionAngle( int i ) ;104 double getSectionLEX( int i ) ;105 double getSectionSlope( int i ) ;106 double getSectionTEX( int i ) ;107 double getSectionY(int i) ;108 double getTaperRatio() ;109 double getVelocityDist( int aoa, int section ) ;110 double getWingArea() ;111 double getWingSpan() ;112 double getWingSpanCoef( int section ) ;113 bool isParametersSaved() ;114 bool isResultsUpToDate() ;115 bool readFromFile( const char* file ) ;116 bool setParameters( double a_start, double a_finish, int a_iterations,

double f_velocity, double f_density, int s_iterations, int f_accuracy ) ;117 bool writeToDefaultFile() ;118 bool writeToFile( const char* file ) ;119} ;120121#endif

Listing A-3 Wing.class.h

1 #include "../include/Wing.class.h"2 #include "../include/linear_solver.h"3 #include <math.h>4 #include <cstring>5 #include <stdio.h>6 #include <iostream>789

- 52 -

Załączniki

10 /****************************************************************************11 ** PRIVATE MEMBER FUNCTIONS12 ****************************************************************************/1314 /**15 * void Wing::calculateCharacteristics()16 * calculates aerodynamic charasteristics of the wing17 */18 void Wing::calculateCharacteristics() {19 int a, i, n ;20 double sum_nAn2, sum_nAnsin, tmp_gamma ;21 22 // creating arrays for every Angle of Attack23 gamma = new double* [aoa_iterations] ;24 lift_coefficient_distribution = new double* [aoa_iterations] ;25 induced_velocity_distribution = new double* [aoa_iterations] ;26 induced_drag_coefficient_distribution = new double* [aoa_iterations] ;27 28 lift_coefficient = new double [aoa_iterations] ;29 induced_drag_coefficient = new double [aoa_iterations] ;30 31 // creating wing span distributions arrays second dimension32 for ( a = 0; a < aoa_iterations; a++ ) {33 // creating arrays for every Cross Section34 gamma[a] = new double [sections_fullspan ] ;35 lift_coefficient_distribution[a] = new double [ sections_fullspan ] ;36 induced_velocity_distribution[a] = new double [ sections_fullspan ] ;37 induced_drag_coefficient_distribution[a] = new double

[ sections_fullspan ] ;38 }39 40 // calculating characteristics for every angle of attack41 for ( a = 0; a < aoa_iterations; a++ ) {42 43 // start value of temporary coefficients44 lift_coefficient[a] = 0.0 ;45 46 for ( i = 0; i < sections_fullspan; i++ ) {47

- 53 -

Załączniki

48 // start values49 tmp_gamma = 0.0 ;50 sum_nAn2 = 0.0 ;51 sum_nAnsin = 0.0 ;52 53 // for every Fourier series term54 for ( n = 0; n < fourier_accuracy; n++ ) {55 // calculating gamma (circulation) for single Cross Section and

Angle of Attack56 tmp_gamma = tmp_gamma + sin( ( (double)n + 1 ) * fi[i] ) *

fourier_terms[a][n] ;57 // calculating temporary coefficients58 sum_nAnsin += ( (double)n + 1 ) * sin( ( (double)n + 1 ) * fi[i] ) *

fourier_terms[a][n] ;59 sum_nAn2 += ( (double)n + 1 ) * pow( fourier_terms[a][n], 2 ) ;60 }61 62 // finishing calculating gamma (circulation)63 tmp_gamma = tmp_gamma * ( 2 * wing_span * fluid_velocity ) ;64 gamma[a][i] = tmp_gamma ;65 // calculating lift coef. distribution for single Cross Section and

Angle of Attack66 lift_coefficient_distribution[a][i] = 2 * gamma[a][i] / ( fluid_velocity

* chord_length[i] ) ;67 // calculating induced valocity distribution distribution for single

Cross Section and Angle of Attack68 induced_velocity_distribution[a][i] = ( i != 0 && i != sections_fullspan

- 1 ) ? ( ( -1 ) / sin( fi[i] ) * sum_nAnsin ) : ( 0 ) ;69 // calculating induced drag coef. distribution for single Cross Section

and Angle of Attack70 induced_drag_coefficient_distribution[a][i] = (

-induced_velocity_distribution[a][i] ) * gamma[a][i] / ( fluid_velocity * fluid_velocity * chord_length[i] ) ;

71 72 // calculating lift coef. for single Angle of Attack and whole wing73 if ( i > 0 ) lift_coefficient[a] += ( wingspan[i] - wingspan[i-1] ) *

( lift_coefficient_distribution[a][i] + lift_coefficient_distribution[a][i - 1] ) / 2 ;

74 //lift_coefficient[a] = sum_nAnsin75 76 }77 78 lift_coefficient[a] /= wing_span ;

- 54 -

Załączniki

79 80 // calcualting induced drag coef. for single Angle of Attack and whole

wing81 induced_drag_coefficient[a] = pi() * aspect_ratio * sum_nAn2 ;82 83 }84 85 }8687 /**88 * void Wing::calculateGeometry() 89 */90 void Wing::calculateGeometry() {91 int i ;92 // geometric data93 wing_span = .0 ;94 wing_area = .0 ;95 aspect_ratio = .0 ;96 taper_ratio = .0 ;97 98 // If at least 2 sections coduct calculations99 if ( sections > 1 ) {100 // Calculating Wing Span (Wing::wing_span)101 wing_span = 2 * ( sections_data[0][sections - 1] - sections_data[0][0] ) ;102103 // Calculating Wing Area (Wing::wing_area)104 for ( i = 0; i < ( sections - 1 ); i++ ) {105 wing_area += ( ( sections_data[2][i] - sections_data[1][i] ) +

( sections_data[2][i + 1] - sections_data[1][i + 1] ) ) / 2 * ( sections_data[0][i + 1] - sections_data[0][i] ) ;

106 }107 wing_area *= 2 ;108109 // Calculating Aspect Ratio (Wing::aspect_ratio)110 aspect_ratio = wing_span * wing_span / wing_area ;111112 // Calculating Taper Ratio (Wing::taper_ratio)113 taper_ratio = ( sections_data[2][sections - 1] - sections_data[1][sections

- 1] ) / ( sections_data[2][0] - sections_data[1][0] ) ;114 }

- 55 -

Załączniki

115 116}117118/**119* bool Wing::checkIfSectionExists( double ) 120* checks if given Wing Span Y Coordinate already exists in

Wing::sections_data121* returns TRUE if exists122* returns FALSE if does NOT123*/124bool Wing::checkIfSectionExists( double span_y ) {125 int i ;126 bool cs_exists = false ;127 double* haystack_span ;128 haystack_span = sections_data[0];129 130 for ( i = 0; i < sections; i++ ) {131 if ( span_y == *haystack_span ) {132 cs_exists = true ;133 break ;134 } else {135 haystack_span++ ;136 continue ;137 }138 }139 140 return cs_exists ;141}142143/**144* void Wing::createEquations()145* creates square matrix Wing::equations_lhs of Fourier series terms'

coefficients of order 146* Wing::fourier_accuracy147* sin( n * fi ) * ( sin( fi ) + n * mi( fi ) ) * An, where An is uknown

variable148* and matrix of equations' right hand side mi( fi ) * alpha_0 * sin( fi ),

Wing::equations_rhs149*/150void Wing::createEquations() {

- 56 -

Załączniki

151 int i, a, n, cur_section ;152 double sin_fi, rhs ;153 int step = (int)floor( ( sections_iterations - 2 ) / ( ( fourier_accuracy

+ 1) / 2 ) ) ;154 155 if ( step < 1 )156 step = 1 ;157 158 // creating first dimension159 equations_lhs = new double* [fourier_accuracy] ;160 equations_rhs = new double* [aoa_iterations] ;161 162 equations_span = new double [fourier_accuracy] ;163 164 // creating second dimension165 for ( i = 0; i < fourier_accuracy; i++ ) {166 equations_lhs[i] = new double [fourier_accuracy] ;167 }168 169 // creating second dimension170 for ( a = 0; a < aoa_iterations; a++ ) {171 equations_rhs[a] = new double [fourier_accuracy] ;172 }173 174 cur_section = step ;175 176 // calculating linear equations system's matrices for left wing177 //for ( i = 1; i < ( ( fourier_accuracy + 1) / 2 ) - 1; i++ ) {178 for ( i = 0; i < ( ( fourier_accuracy + 1) / 2 ) - 1; i++ ) {179 for ( n = 1; n <= fourier_accuracy; n++ ) {180 equations_lhs[i][ n - 1 ] = ( sin( fi[cur_section] ) + ( (double)n ) *

mi[cur_section] ) * sin( ( (double)n ) * fi[cur_section] ) ;181 }182183 for ( a = 0; a < aoa_iterations; a++ ) {184 sin_fi = sin( fi[cur_section] ) ;185 rhs = sin_fi * mi[cur_section] * ( angle_of_attack_rad[a] -

angle_of_0_lift_rad[cur_section] );186 equations_rhs[a][i] = rhs ;

- 57 -

Załączniki

187 }188189 equations_span[i] = wingspan[cur_section] ;190191 cur_section += step ;192 }193 194 // calculating linear equations system's matrices for plane of

simetricity195 for ( n = 1; n <= fourier_accuracy; n++ ) {196 equations_lhs[( ( fourier_accuracy + 1) / 2 ) - 1][ n-1 ] =

( sin( fi[sections_iterations - 1] ) + ( (double)n ) * mi[sections_iterations - 1] ) * sin( ( (double)n ) * fi[sections_iterations - 1] ) ;

197 }198 199 for ( a = 0; a < aoa_iterations; a++ ) {200 sin_fi = sin( fi[sections_iterations-1] ) ;201 rhs = sin_fi * mi[sections_iterations - 1] * ( angle_of_attack_rad[a] -

angle_of_0_lift_rad[sections_iterations - 1] );202 equations_rhs[a][( ( fourier_accuracy + 1) / 2 ) - 1] = rhs ;203 }204 205 //equations_span[( ( fourier_accuracy + 1) / 2 ) - 1] =

wingspan[sections_iterations - 1] ;206 equations_span[( ( fourier_accuracy + 1) / 2 ) - 1] =

wingspan[sections_iterations - 1] ;207 208 cur_section = sections_fullspan - step - 1 ;209 210 // calculating linear equations system's matrices for right wing211 for ( i = fourier_accuracy - 1; i > ( ( fourier_accuracy + 1) / 2 ) - 1;

i-- ) {212 for ( n = 1; n <= fourier_accuracy; n++ ) {213 equations_lhs[i][ n-1 ] = ( sin( fi[cur_section] ) + ( (double)n ) *

mi[cur_section] ) * sin( ( (double)n ) * fi[cur_section] ) ;214 }215216 for ( a = 0; a < aoa_iterations; a++ ) {217 sin_fi = sin( fi[cur_section] ) ;218 rhs = sin_fi * mi[cur_section] * ( angle_of_attack_rad[a] -

angle_of_0_lift_rad[cur_section] ) ;219 equations_rhs[a][i] = rhs ;

- 58 -

Załączniki

220 }221222 equations_span[i] = wingspan[cur_section] ;223224 cur_section = cur_section - step ;225 }226 227}228229/**230* void Wing::interpolateCrossSections()231* creates arrays of Cross Sections data using linear interpolations of all

data:232* Leading Edge X Coordinate233* Trailing Edge X Coordinate234* Airfoil Lift Curve Slope235* and Airfoil Angle of 0 Lift236*/237void Wing::interpolateSections() {238 int i ;239 240 // creating arrays of interpolating data241 wingspan = new double[sections_iterations] ;242 chord_length = new double[sections_iterations] ;243 lift_curve_slope = new double[sections_iterations] ;244 angle_of_0_lift_deg = new double[sections_iterations] ;245 angle_of_0_lift_rad = new double[sections_iterations] ;246 247 // calculating winspan_step248 double wingspan_step = ( wing_span / 2 ) / ( sections_iterations - 1 ) ;249 250 // setting start current section251 int current_section = 0 ;252 253 // setting start leading edge x coordinate, trailing edge x coordinate

values,254 // airfoil lift curve slope and angle of 0 lift 'previous' value255 double i_wingspan = 0.0 ;256 double i_leading_edge = sections_data[1][0] ;

- 59 -

Załączniki

257 double i_trailing_edge = sections_data[2][0] ;258 double i_lift_curve_slope = sections_data[3][0] ;259 double i_angle_of_0_lift = sections_data[4][0] ;260 261 // setting start 'per_step_' values262 double per_step_leading_edge = ( sections_data[1][current_section + 1] -

sections_data[1][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

263 double per_step_trailing_edge = ( sections_data[2][current_section + 1] - sections_data[2][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

264 double per_step_lift_curve_slope = ( sections_data[3][current_section + 1] - sections_data[3][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

265 double per_step_angle_of_0_lift = ( sections_data[4][current_section + 1] - sections_data[4][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

266 267 // setting values of the root section268 chord_length[0] = sections_data[2][0] - sections_data[1][0] ;269 lift_curve_slope[0] = sections_data[3][0] ;270 angle_of_0_lift_deg[0] = sections_data[4][0] ;271 angle_of_0_lift_rad[0] = ( 2 * pi() * angle_of_0_lift_deg[0] ) / 360 ;272 273 // interpolating loop274 for ( i = 1; i < sections_iterations - 1; i++ ) {275 // root span allready known... so first interpolation made for greater by

one276 i_wingspan += wingspan_step ;277 wingspan[i] = i_wingspan ;278 // checking if values 'per_step_' are 'up to date'279 if ( wingspan[i] < sections_data[0][current_section + 1] + 0.0001 ) {280 // calculating chord_length281 i_leading_edge += per_step_leading_edge ;282 i_trailing_edge += per_step_trailing_edge ;283 chord_length[i] = i_trailing_edge - i_leading_edge ;284 // calculating lift_curve_slope285 lift_curve_slope[i] = i_lift_curve_slope + per_step_lift_curve_slope ;286 i_lift_curve_slope = lift_curve_slope[i] ;287 // calculating angle_of_0_lift_deg and angle_of_0_lift_rad288 angle_of_0_lift_deg[i] = i_angle_of_0_lift + per_step_angle_of_0_lift ;289 angle_of_0_lift_rad[i] = ( 2 * pi() * angle_of_0_lift_deg[i] ) / 360 ;

- 60 -

Załączniki

290 i_angle_of_0_lift = angle_of_0_lift_deg[i] ;291 } else {292 std::cerr << "span= " << wingspan[i] ;293 // updating 'per_step_' values294 // looking for new gradients 'per_step_'295 while ( current_section < sections - 1 ) {296 current_section++ ;297 // when find recalculate 'per_step_' values298 if ( wingspan[i] + 0.0001 > sections_data[0][current_section] &&

wingspan[i] < sections_data[0][current_section + 1] + 0.0001 ) {299 per_step_leading_edge = ( sections_data[1][current_section + 1] -

sections_data[1][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

300 per_step_trailing_edge = ( sections_data[2][current_section + 1] - sections_data[2][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

301 per_step_lift_curve_slope = ( sections_data[3][current_section + 1] - sections_data[3][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

302 per_step_angle_of_0_lift = ( sections_data[4][current_section + 1] - sections_data[4][current_section] ) / ( sections_data[0][current_section + 1] - sections_data[0][current_section] ) * wingspan_step ;

303 break ;304 } else305 continue ;306 }307 std::cerr << "\tLE_perstep= " << per_step_leading_edge ;308 std::cerr << "\tcur_sec= " << current_section << std::endl ;309 // calculating chord_length310 i_leading_edge = sections_data[1][current_section] +

per_step_leading_edge / ( wingspan[i] - sections_data[0][current_section] ) * wingspan_step ;

311 i_trailing_edge = sections_data[2][current_section] + per_step_trailing_edge / ( wingspan[i] - sections_data[0][current_section] ) * wingspan_step ;

312 chord_length[i] = i_trailing_edge - i_leading_edge ;313 // calculating lift_curve_slope314 lift_curve_slope[i] = sections_data[3][current_section] +

per_step_lift_curve_slope / ( wingspan[i] - sections_data[0][current_section] ) * wingspan_step ;

315 // calculating angle_of_0_lift_deg and angle_of_0_lift_rad316 angle_of_0_lift_deg[i] = sections_data[4][current_section] +

per_step_angle_of_0_lift / ( wingspan[i] - sections_data[0][current_section] ) * wingspan_step ;

317 angle_of_0_lift_rad[i] = 2 * pi() * angle_of_0_lift_deg[i] / 360 ;

- 61 -

Załączniki

318 319 // setting current leading edge x coordinate, trailing edge x

coordinate values,320 // airfoil lift curve slope and angle of 0 lift interpolation

'previous' value321 i_lift_curve_slope = lift_curve_slope[i] ;322 i_angle_of_0_lift = angle_of_0_lift_deg[i] ;323 }324 }325 326 // setting values of the tip section327 wingspan[sections_iterations - 1] = sections_data[0][sections - 1] ;328 chord_length[sections_iterations - 1] = sections_data[2][sections - 1] -

sections_data[1][sections - 1] ;329 lift_curve_slope[sections_iterations - 1] = sections_data[3][sections -

1] ;330 angle_of_0_lift_deg[sections_iterations - 1] = sections_data[4][sections

- 1] ;331 angle_of_0_lift_rad[sections_iterations - 1] = ( 2 * pi() *

angle_of_0_lift_deg[sections_iterations - 1] ) / 360 ;332333334}335336/**337* void Wing::iterateAoA()338* creates array of Angle of Attack339*/340void Wing::iterateAoA() {341 int i ;342 343 // calculating angle of attack iteration step344 if ( aoa_iterations > 1 )345 aoa_step = ( aoa_finish - aoa_start ) / ( (double)aoa_iterations - 1 );346 else347 aoa_step = 0.0 ;348 349 // creating AoA deg and rad arrays350 angle_of_attack_deg = new double[aoa_iterations] ;351 angle_of_attack_rad = new double[aoa_iterations] ;352

- 62 -

Załączniki

353 // calculating AoAs arrays354 for ( i = 0; i < aoa_iterations; i++ ) {355 angle_of_attack_deg[i] = aoa_start + aoa_step * (double)i ;356 angle_of_attack_rad[i] = 2 * pi() * angle_of_attack_deg[i] / 360 ;357 }358}359360/**361* double Wing::pi()362* returns 4 * atan( 1 ) 363* pi = 3.1415....364*/365double Wing::pi() {366 return ( 4 * atan( 1 ) ) ;367}368369/**370* void Wing::releaseResults()371* releases memmory containing computation results372* this function is called before every new results computations373*/374void Wing::releaseResults () {375 int i ;376 // releasing memory377 for ( i = 0; i < old_accuracy; i++ ) {378 delete [] equations_lhs[i] ;379 // and setting null address380 equations_lhs[i] = 0 ;381 }382 383 for ( i = 0; i < old_aoa_iterations; i++ ) {384 delete [] equations_rhs[i] ;385 delete [] fourier_terms[i] ;386 delete [] gamma[i] ;387 delete [] lift_coefficient_distribution[i] ;388 delete [] induced_velocity_distribution[i] ;389 delete [] induced_drag_coefficient_distribution[i] ;390 equations_rhs[i] = 0 ;

- 63 -

Załączniki

391 fourier_terms[i] = 0 ;392 gamma[i] = 0 ;393 lift_coefficient_distribution[i] = 0 ;394 induced_velocity_distribution[i] = 0 ;395 induced_drag_coefficient_distribution[i] = 0 ;396 }397 398 delete [] equations_lhs ;399 delete [] equations_rhs ;400 delete [] equations_span ;401 delete [] fourier_terms ;402 delete [] gamma ;403 delete [] lift_coefficient_distribution ;404 delete [] induced_velocity_distribution ;405 delete [] induced_drag_coefficient_distribution ;406 delete [] lift_coefficient ; 407 delete [] induced_drag_coefficient ;408 equations_lhs = 0 ;409 equations_rhs = 0 ;410 equations_span = 0 ;411 fourier_terms = 0 ;412 gamma = 0 ;413 lift_coefficient_distribution = 0 ;414 induced_velocity_distribution = 0 ;415 induced_drag_coefficient_distribution = 0 ;416 lift_coefficient = 0 ; 417 induced_drag_coefficient = 0 ;418 419 // releasing interpolated sections data420 delete [] wingspan ;421 delete [] chord_length ;422 delete [] lift_curve_slope ;423 delete [] angle_of_0_lift_deg ;424 delete [] angle_of_0_lift_rad ;425 delete [] fi ;426 delete [] mi ;427 428 // setting null address

- 64 -

Załączniki

429 wingspan = 0 ;430 chord_length = 0;431 lift_curve_slope = 0 ;432 angle_of_0_lift_deg = 0 ;433 angle_of_0_lift_rad = 0 ;434 fi = 0 ;435 mi = 0 ;436 437 // setting new Wing::old_accuracy and Wing::old_aoa_iterations438 old_accuracy = fourier_accuracy ;439 old_aoa_iterations = aoa_iterations ;440}441442/**443* void Wing::rewriteSectionsForFullSpan()444* rewrties Wing::wingspan, Wing:chord_leng_of_0_liftope,

Wing::angle_of_0_lift_deg445* and Wing::angle_of_0_lift_rad for full ( NOT semi ) wingspana and creates

fi (Wing::fi) array446*/447void Wing::rewriteSectionsForFullSpan() {448 double* f_wingspan ;449 double* f_chord_length ;450 double* f_lift_curve_slope ;451 double* f_angle_of_0_lift_deg ;452 double* f_angle_of_0_lift_rad ;453 int f_iterations = 2 * sections_iterations - 1 ;454 int i ;455 456 // creating full span arrays457 f_wingspan = new double[f_iterations] ;458 f_chord_length = new double[f_iterations] ;459 f_lift_curve_slope = new double[f_iterations] ;460 f_angle_of_0_lift_deg = new double[f_iterations] ;461 f_angle_of_0_lift_rad = new double[f_iterations] ;462 fi = new double[f_iterations] ;463 mi = new double[f_iterations] ;464 465 // left wing tip to wing root (excluded)

- 65 -

Załączniki

466 for ( i = 0; i < sections_iterations; i++ ) {467 f_wingspan[i] = wingspan[i] ;468 f_chord_length[i] = chord_length[i] ;469 f_lift_curve_slope[i] = lift_curve_slope[i] ;470 f_angle_of_0_lift_deg[i] = angle_of_0_lift_deg[i] ;471 f_angle_of_0_lift_rad[i] = angle_of_0_lift_rad[i] ;472 // calulating fi & mi473 fi[i] = acos( ( -2 ) * f_wingspan[i] / wing_span ) ;474 mi[i] = ( 0.25 * f_chord_length[i] * f_lift_curve_slope[i] ) /

wing_span ;475 }476 477 // wing root (included) to right wing tip478 for ( i = 1; i < sections_iterations; i++ ) {479 f_wingspan[ i + sections_iterations - 1 ] = - wingspan[i] ;480 f_chord_length[ i + sections_iterations - 1 ] = chord_length[i] ;481 f_lift_curve_slope[ i + sections_iterations - 1 ] =

lift_curve_slope[i] ;482 f_angle_of_0_lift_deg[ i + sections_iterations - 1 ] =

angle_of_0_lift_deg[i] ;483 f_angle_of_0_lift_rad[ i + sections_iterations - 1 ] =

angle_of_0_lift_rad[i] ;484 // calulating fi & mi485 fi[ i + sections_iterations - 1 ] = acos( ( -2 ) * f_wingspan[ i +

sections_iterations - 1 ] / wing_span ) ;486 mi[ i + sections_iterations - 1 ] = ( 0.25 * f_chord_length[ i +

sections_iterations - 1 ] * f_lift_curve_slope[ i + sections_iterations - 1 ] ) / wing_span ;

487 }488 489 // setting number of sections in full span Wing::sections_fullspan490 sections_fullspan = f_iterations ;491 492 // deleting semi span arrays493 delete [] wingspan ;494 delete [] chord_length ;495 delete [] lift_curve_slope ;496 delete [] angle_of_0_lift_deg ;497 delete [] angle_of_0_lift_rad ;498 499 // pointing sections arrays to full span arrays

- 66 -

Załączniki

500 wingspan = f_wingspan ;501 chord_length = f_chord_length ;502 lift_curve_slope = f_lift_curve_slope ;503 angle_of_0_lift_deg = f_angle_of_0_lift_deg ;504 angle_of_0_lift_rad = f_angle_of_0_lift_rad ;505 506}507508/**509* bool Wing::solveEquations()510* solves system of linear equation due to assign values to equations

variables511* which are coefficients of Fourier series terms and calculate aerodynamic

characteristics512* returns TRUE on success513* returns FALSE on failure514*/515bool Wing::solveEquations() {516 bool success = true ;517 int a, i, n = 0 ;518 double* lhs ;519 double* rhs ;520 521 // creating Wing::fourier_terms array's first dimension522 fourier_terms = new double* [aoa_iterations] ;523 // and second dimension524 for ( a = 0; a < aoa_iterations; a++ ) {525 fourier_terms[a] = new double [fourier_accuracy] ;526 }527 528 // creating temporary arrays529 lhs = new double [ fourier_accuracy * fourier_accuracy + fourier_accuracy

] ;530 rhs = new double [ fourier_accuracy ] ;531 532 // iterating over Angle of Attack533 for ( a = 0; a < aoa_iterations; a++ ) {534 // copying equations Right-Hand-Side to temporary array535 for ( i = 0; i < fourier_accuracy; i++ ) {

- 67 -

Załączniki

536 rhs[i] = equations_rhs[a][i] ;537 // copying equations Left-Hand-Side to temporary array538 for ( n = 0; n < fourier_accuracy; n++ ) {539 lhs[fourier_accuracy*n+i] = equations_lhs[i][n] ;540 }541 }542 // solving system of linear equations for single Angle of Attack543 if ( GEN_SOLV( rhs, lhs, fourier_accuracy ) != -1 ) {544 success = false ;545 }546 // copying equation's result547 for ( i = 0; i < fourier_accuracy; i++ ) {548 fourier_terms[a][i] = rhs[i] ;549 } 550551 }552 553 delete [] lhs ;554 delete [] rhs ;555 lhs = 0 ;556 rhs = 0 ;557 558 return success ;559}560561/**562* void Wing::sortFullSpanSections() 563*wingspan, Wing::chord_length, Wing::lift_curve_sl_of_0_liftand

Wing::angle_of_0_lift_deg564 * and Wing::angle_of_0_lift_rad using bubble sort algorithm565*/566void Wing::sortFullSpanSections() {567 bool sorted ;568 int i, j ;569 double temp ;570 571 for ( i = 1; i < sections_fullspan; i++ ) {572 sorted = true ;573

- 68 -

Załączniki

574 for ( j = 0; j < sections_fullspan - i; j++ ) {575 if ( wingspan[j] > wingspan[j+1] ) {576 // wing span577 temp = wingspan[j] ;578 wingspan[j] = wingspan[j+1] ;579 wingspan[j+1] = temp ;580 // chord581 temp = chord_length[j] ;582 chord_length[j] = chord_length[j+1] ;583 chord_length[j+1] = temp ;584 // lift curve slop585 temp = lift_curve_slope[j] ;586 lift_curve_slope[j] = lift_curve_slope[j+1] ;587 lift_curve_slope[j+1] = temp ;588 // angle of _of_0_lift0 lift589 temp = angle_of_0_lift_deg[j] ;590 angle_of_0_lift_deg[j] = angle_of_0_lift_deg[j+1] ;591 angle_of_0_lift_deg[j+1] = temp ;592 temp = angle_of_0_lift_rad[j] ;593 angle_of_0_lift_rad[j] = angle_of_0_lift_rad[j+1] ;594 angle_of_0_lift_rad[j+1] = temp ;595 // fi596 temp = fi[j] ;597 fi[j] = fi[j+1] ;598 fi[j+1] = temp ;599 // mi600 temp = mi[j] ;601 mi[j] = mi[j+1] ;602 mi[j+1] = temp ;603 // keep sorting604 sorted = false ;605 }606 }607 if ( sorted ) {608 break ;609 }610 }611

- 69 -

Załączniki

612}613614/**615* void Wing::sortSectionsData() 616* sorts unsorted Wing::sections_data[ ] array using bubble sort algorithm617*/618void Wing::sortSectionsData() {619 bool sorted ;620 int i, j, k ;621 double temp ;622 623 for ( i = 1; i < sections; i++ ) {624 sorted = true ;625626 for ( j = 0; j < sections - i; j++ ) {627 if ( sections_data[0][j] > sections_data[0][j+1] ) {628 for (k=0;k<5;k++) {629 temp = sections_data[k][j] ;630 sections_data[k][j] = sections_data[k][j+1] ;631 sections_data[k][j+1] = temp ;632 }633 sorted = false ;634 }635 }636 if ( sorted ) {637 break ;638 }639 }640}641642/**643* bool Wing::writeAoAToFile()644* writes full span sections arrays to file645*/646bool Wing::writeAoAToFile() {647 int a ;648 FILE* file ;649

- 70 -

Załączniki

650 if ((file=fopen("../tmp/tmp.aoa", "w"))!=NULL) {651 for ( a = 0; a < aoa_iterations; a++ ) {652 fprintf( file, "%f\t%f\n", angle_of_attack_deg[a],

angle_of_attack_rad[a] ) ;653 }654 fclose( file) ;655 return true ;656 } else {657 return false ;658 }659}660661/**662* bool Wing::writeEquationsToFile()663* writes Wing::equations_lhs and Wing::equations_rhs to file664*/665bool Wing::writeEquationsToFile() {666 int a, i, n ;667 bool ret = true ;668 FILE* file ;669 670 if ((file=fopen("../tmp/tmp.lhs", "w"))!=NULL) {671 for ( i = 0; i < fourier_accuracy; i++ ) {672 fprintf( file, "%f\t\t", equations_span[i] ) ;673 for ( n = 0; n < fourier_accuracy; n++ ) {674 fprintf( file, "%f\t", equations_lhs[i][n] ) ;675 }676 fprintf( file, "\n" ) ;677 }678 fclose( file ) ;679 } else {680 fclose( file ) ;681 ret = false ;682 }683 684 if ((file=fopen("../tmp/tmp.rhs", "w"))!=NULL && ret) {685 for ( i = 0; i < fourier_accuracy; i++ ) {686 fprintf( file, "%f\t\t", equations_span[i] ) ;687 for ( a = 0; a < aoa_iterations; a++ ) {

- 71 -

Załączniki

688 fprintf( file, "%f\t", equations_rhs[a][i] ) ;689 }690 fprintf( file, "\n" ) ;691 }692 fclose( file ) ;693 } else {694 fclose( file ) ;695 ret = false ;696 }697 698 return ret ;699}700701/**702* bool Wing::writeFourierToFile()703* writes Wing::fourier_terms to file704*/705bool Wing::writeFourierToFile() {706 int a, n ;707 FILE* file ;708 709 if ((file=fopen("../tmp/tmp.terms", "w"))!=NULL) {710 for ( n = 0; n < fourier_accuracy; n++ ) {711 for ( a = 0; a < aoa_iterations; a++ ) {712 fprintf( file, "%f\t", fourier_terms[a][n] ) ;713 }714 fprintf( file, "\n" ) ;715 }716 fclose( file) ;717 return true ;718 } else {719 return false ;720 }721}722723/**724* bool Wing::writeFullspanToFile()725* writes full span sections arrays to file

- 72 -

Załączniki

726*/727bool Wing::writeFullspanToFile() {728 int i ;729 FILE* file ;730 731 if ((file=fopen("../tmp/tmp.fullspan", "w"))!=NULL) {732 for ( i = 0; i < sections_fullspan; i++ ) {733 fprintf( file, "%f\t%f\t%f\t%f\t%f\t%f\t%f\n", wingspan[i],

chord_length[i], lift_curve_slope[i], angle_of_0_lift_deg[i], angle_of_0_lift_rad[i], fi[i], mi[i] ) ;

734 }735 fclose( file) ;736 return true ;737 } else {738 return false ;739 }740}741742/**743* bool Wing::writeInterpolatedToFile()744* writes interpolated sections arrays to file745*/746bool Wing::writeInterpolatedToFile() {747 int i ;748 FILE* file ;749 750 if ((file=fopen("../tmp/tmp.interpolated", "w"))!=NULL) {751 for ( i = 0; i < sections_iterations; i++ ) {752 fprintf( file, "%f\t%f\t%f\t%f\t%f\n", wingspan[i], chord_length[i],

lift_curve_slope[i], angle_of_0_lift_deg[i], angle_of_0_lift_rad[i] ) ;753 }754 fclose( file) ;755 return true ;756 } else {757 return false ;758 }759}760761/**

- 73 -

Załączniki

762* bool Wing::writeParametersToFile()763* writes parametres to file764*/765bool Wing::writeParametersToFile() {766 FILE* file ;767 768 if ((file=fopen("../tmp/tmp.parameters", "w"))!=NULL) {769 fprintf( file, "#Angle of Attack Iteration Start Value [deg]\n" );770 fprintf( file, "aoa_start = %f\n", aoa_start ) ;771 fprintf( file, "\n#Angle of Attack Iteration Finish Value [deg]\n" );772 fprintf( file, "aoa_finish = %f\n", aoa_finish ) ;773 fprintf( file, "\n#Angle of Attack Number of Iterations [-]\n" );774 fprintf( file, "aoa_iterations = %d\n", aoa_iterations ) ;775 fprintf( file, "\n#Angle of Attack Step [deg]\n" );776 fprintf( file, "aoa_step = %f\n", aoa_step ) ;777 fprintf( file, "\n#Fluid Velocity [m/s]\n" );778 fprintf( file, "fluid_velocity = %f\n", fluid_velocity ) ;779 fprintf( file, "\n#Fluid Density [kg/cu m]\n" );780 fprintf( file, "fluid_density = %f\n", fluid_density ) ;781 fprintf( file, "\n#Number of Cross Sections [-]\n" );782 fprintf( file, "sections_iterations = %d\n", sections_iterations ) ;783 fprintf( file, "\n#Fourier Series Accuracy [-]\n" );784 fprintf( file, "fourier_accuracy = %d\n", ( ( fourier_accuracy + 1 ) /

2 ) ) ;785 fclose( file) ;786 return true ;787 } else {788 return false ;789 }790}791792/**793* bool Wing::writeWingInputToFile()794* writes Wing::sections_data array to file795*/796bool Wing::writeWingInputToFile() {797 int i ;798 FILE* file ;799

- 74 -

Załączniki

800 if ((file=fopen("../tmp/tmp.winginput", "w"))!=NULL) {801 for ( i = 0; i < sections; i++ ) {802 fprintf( file, "%f\t%f\t%f\t%f\t%f\n", sections_data[0][i],

sections_data[1][i], sections_data[2][i], sections_data[3][i], sections_data[4][i] ) ;

803 }804 fclose( file) ;805 return true ;806 } else {807 return false ;808 }809}810811812/****************************************************************************813** PUBLIC MEMBER FUNCTIONS814****************************************************************************/815816/**817* Wing::Wing()818* Wing class constructor819*/820Wing::Wing() {821 int i ;822 823 // set true if debug mode on824 debug_mode = true ;825 826 // setting file_name827 file_name[0] = '\0' ;828 829 // angle of attack iteration data830 aoa_start = .0 ;831 aoa_finish = .0 ;832 aoa_step = .0 ;833 aoa_iterations = 1 ;834 835 // fluid data836 fluid_velocity = .0 ;

- 75 -

Załączniki

837 fluid_density = 1.225 ; // density of the air at 0 Celsius and 1013.25 hPa

838 839 // sections data840 sections = 0 ;841 sections_iterations = 2 ;842 843 // Fourier series data844 fourier_accuracy = 1 ;845 old_accuracy = 0 ;846 old_aoa_iterations = 0 ;847 848 // setting pointers at null address849 wingspan = 0 ;850 chord_length = 0 ;851 lift_curve_slope = 0 ;852 angle_of_0_lift_deg = 0 ;853 angle_of_0_lift_rad = 0 ;854 fi = 0 ;855 mi = 0 ;856 857 equations_lhs = 0 ;858 equations_rhs = 0 ;859 equations_span = 0 ;860 fourier_terms = 0 ;861 gamma = 0 ;862 lift_coefficient_distribution = 0 ;863 induced_velocity_distribution = 0 ;864 induced_drag_coefficient_distribution = 0 ;865 lift_coefficient = 0 ; 866 induced_drag_coefficient = 0 ;867 868 // set *sections_data pointer at NULL869 for ( i = 0; i < 5; i++ ) {870 sections_data[i] = 0 ;871 }872 // setting results_uptodate as FALSE on object start - no results at all873 results_uptodate = false ;874 parameters_saved = false ;

- 76 -

Załączniki

875}876877/**878* Wing::~Wing()879* destructor880* releases results881*/882Wing::~Wing() {883 releaseResults() ;884}885886/**887* bool Wing::addSectionData( double, double, double, double, double ) 888* adds new wing cross section data set to Wing::sections_data[ ] array889* returns TRUE on success890* returns FALSE on failure (given Wing Span Y Coordinate is NOT unique OR

given891* Leading Edge X Coordinate is greater than given Trailing Edge X Coordinate

OR given892* Wing Span Y Coordinate is less than 0.0)893*/894bool Wing::addSectionData( double span_y, double le_x, double te_x, double

slope, double angle ) {895 896 double* new_sections_data[5] ;897 double data_set[5] = { span_y, le_x, te_x, slope, angle } ;898 int i, j ;899 900 // first cross section must be wing root (Y Coordinate = 0)901 if ( sections == 0 && span_y != 0.0)902 return false ;903 904 // check if given Wing Span Y Coordinate is less than 0.0905 if ( span_y < 0.0 )906 // if so return FALSE on failure907 return false ;908 909 // check if given Trailing Edge X Coordinate is greater than given

Leading Edge X Coordinate910 if ( te_x <= le_x )

- 77 -

Załączniki

911 // if NOT return FALSE on failure912 return false ;913 914 // check if new Wing Span Y Coordinate already exists in

Wing::sections_data[ ] array915 if ( checkIfSectionExists( span_y ) )916 // if exists return FALSE on failure917 return false ; 918 919 // For every value in set (Wing Span Y Coordinate, Leading Edge X

Coordinate, etc.)920 for ( i = 0; i < 5; i++ ) {921 // create new array of length greater by one than current922 new_sections_data[i] = new double[sections + 1] ;923924 // For every current existing sections925 for ( j = 0; j < sections; j++ ) {926 // copy value into new array927 new_sections_data[i][j] = sections_data[i][j] ;928 }929930 // copy new value into last element of the new array931 new_sections_data[i][sections] = data_set[i] ;932933 // delete current array934 delete [] sections_data[i] ;935 // point at new array936 sections_data[i] = new_sections_data[i] ;937 }938 939 // Increment Wing::sections by one940 sections++ ;941 942 // sort new Wing::sections_data[ ] array943 sortSectionsData() ;944 945 // recalculate Wing Geometric Data946 calculateGeometry() ;947

- 78 -

Załączniki

948 // write Wing::sections_data array to file949 writeWingInputToFile() ;950 951 // setting Wing::results_uptodate as FALSE952 results_uptodate = false ;953 954 // return TRUE on success955 return true ;956 957}958959/****************************************************************************960** Wing::compute() or the Heart of Wing Class961****************************************************************************/962963/**964* bool Wing::compute()965* computes aerodynamic characteristics of the wing966* returns TRUE on success967* returns FALSE on failure968*/969bool Wing::compute() {970 bool ret = true ;971 972 // if too few sections973 if ( sections < 2 )974 return false ;975 976 // if there is no parameters saved977 if ( ! parameters_saved )978 return false ;979 980 // releasing results981 releaseResults() ;982 983 // write parameters to file984 if ( debug_mode ) writeParametersToFile() ;985

- 79 -

Załączniki

986 // iterate Angle of Attack at first987 iterateAoA() ;988 989 // write angle of attack iterations to file990 if ( debug_mode ) writeAoAToFile() ;991 992 // iterate Cross Sections993 interpolateSections() ;994 995 // write interpolated sections arrays to file996 if ( debug_mode ) writeInterpolatedToFile() ;997 998 // rewriting sections arrays for full ( NOT semi ) span999 rewriteSectionsForFullSpan() ;1000 1001 // sorting fulls pan sections1002 sortFullSpanSections() ;1003 1004 // write full span sections arrays to file1005 if ( debug_mode ) writeFullspanToFile() ;1006 1007 // create Equations Left-Hand-Side and Right-Hand-Sides (for every Angle

of Attack)1008 createEquations() ;1009 1010 // write equations LHS and RHSs to file1011 if ( debug_mode ) writeEquationsToFile() ;1012 1013 // solve system of linear equations1014 if ( ! solveEquations() ) ret = false ;1015 1016 // write Fourier terms to file1017 if ( debug_mode && ret ) writeFourierToFile() ;1018 1019 // calculating wing aerodynamic characteristics1020 if ( ret ) calculateCharacteristics() ;1021 1022 if ( ret )1023 results_uptodate = true ;

- 80 -

Załączniki

1024 else1025 results_uptodate = false ;1026 1027 return ret ;1028}10291030/**1031* bool Wing::deleteSectionData( int ) 1032* deletes wing cross section data set from Wing::sections_data[ ]1033* returns TRUE on success1034* returns FALSE on failure (row greater than length of

Wing::sections_data[ ] array)1035*/1036bool Wing::deleteSectionData( int row ) {1037 double* new_sections_data[5] ;1038 int i, j ;1039 1040 // if more than 1 section one cannot delete 1st cross section1041 if ( sections > 1 && row == 0 )1042 return false ;1043 1044 // If row is smaller than length of Wing::sections_data[ ]1045 if ( row < sections ) {1046 // For every value in set (Wing Span Y Coordinate, Leading Edge X

Coordinate, etc.)1047 for ( i = 0; i < 5; i++) {1048 // create new array of length smaller by one than current1049 new_sections_data[i] = new double[sections - 1] ;1050 1051 // For every current existing sections1052 for ( j = 0; j < ( sections - 1 ); j++ ) {1053 switch ( j < row ) {1054 // till deleting row (excluding)1055 case true :1056 new_sections_data[i][j] = sections_data[i][j] ;1057 break ;1058 // from deleting row (including)1059 case false :1060 new_sections_data[i][j] = sections_data[i][j + 1] ;

- 81 -

Załączniki

1061 break ;1062 }1063 }1064 1065 // delete current array1066 delete [] sections_data[i] ;1067 // point at new array1068 sections_data[i] = new_sections_data[i] ;1069 }10701071 // Decrement Wing::sections by one1072 sections-- ;10731074 // recalculate Wing Geometric Data1075 calculateGeometry() ;10761077 // write Wing::sections_data array to file1078 writeWingInputToFile() ;10791080 // setting Wing::results_uptodate as FALSE1081 results_uptodate = false ;10821083 // return TRUE on success1084 return true ;10851086 // If row is greater than length of Wing::sections_data[ ]1087 } else {1088 // return FALSE on failure1089 return false ;1090 }1091}10921093/**1094* bool Wing::editSectionData( double, double, double, double, double, int ) 1095* edits wing cross section data set in Wing::sections_data[ ]1096* returns TRUE on success1097* returns FALSE on failure (row greater than length of

Wing::sections_data[ ] array OR

- 82 -

Załączniki

1098* new Wing Span Y Coordinate is NOT unique OR given Leading Edge X Coordinate is

1099* greater than given Trailing Edge X Coordinate OR given Wing Span Y Coordinate is

1100* less than 0.0)1101*/1102bool Wing::editSectionData( double span_y, double le_x, double te_x, double

slope, double angle, int row ) {1103 double data_set[5] = { span_y, le_x, te_x, slope, angle } ;1104 int i ;1105 1106 // wing root section's Y coordinate cannot be modifies1107 if ( row == 0 && span_y != 0.0 )1108 return false ;1109 1110 // check if given Wing Span Y Coordinate is less than 0.01111 if ( span_y < 0.0 )1112 // if so return FALSE on failure1113 return false ;1114 1115 // check if given Trailing Edge X Coordinate is greater than given

Leading Edge X Coordinate1116 if ( te_x <= le_x )1117 // if is NOT return FALSE on failure1118 return false ;1119 1120 // If new value is different than old value of Wing Span Y Coordinate

AND1121 // new Wing Span Y Coordinate already exists in Wing::sections_data[ ]

array1122 if ( ( span_y != sections_data[0][row] ) &&

checkIfSectionExists( span_y ) )1123 // if exists return FALSE on failure1124 return false ;1125 1126 // If row is smaller than length of Wing::wing_cs_data[ ]1127 if ( row < sections ) {1128 // For every value in set (Wing Span Y Coordinate, Leading Edge X

Coordinate, etc.)1129 for ( i = 0; i < 5; i++ ) {1130 // sets new values1131 sections_data[i][row] = data_set[i] ;

- 83 -

Załączniki

1132 }11331134 // sort new Wing::sections_data[ ] array1135 sortSectionsData() ;11361137 // recalculate Wing Geometric Data1138 calculateGeometry() ;11391140 // write Wing::sections_data array to file1141 writeWingInputToFile() ;11421143 // setting Wing::results_uptodate as FALSE1144 results_uptodate = false ;11451146 // return TRUE on success1147 return true ;11481149 // If row is NOT smaller than length of Wing::sections_data[ ]1150 } else {1151 // return FALSE on failure1152 return false ;1153 }1154}11551156/**1157* double Wing::getAoADeg( int aoa )1158* return Wing::angle_of_attack_deg[aoa]1159*/1160double Wing::getAoADeg( int aoa ) {1161 if ( aoa < aoa_iterations )1162 return angle_of_attack_deg[aoa] ;1163 else1164 return 0 ;1165}11661167/**1168* double Wing::getAoA_Finish() 1169* returns Wing::aoa_finish

- 84 -

Załączniki

1170*/1171double Wing::getAoA_Finish() {1172 return aoa_finish ;1173}11741175/**1176* double Wing::getAoA_Iterations() 1177* returns Wing::aoa_iterations1178*/1179int Wing::getAoA_Iterations() {1180 return aoa_iterations ;1181}11821183/**1184* double Wing::getAoA_Start() 1185* returns Wing::aoa_start1186*/1187double Wing::getAoA_Start() {1188 return aoa_start ;1189}11901191/**1192* double Wing::getAoA_Step() 1193* returns Wing::aoa_step1194*/1195double Wing::getAoA_Step() {1196 return aoa_step ;1197}11981199/**1200* double Wing::getAspectRatio() 1201* returns Wing::aspect_ratio1202*/1203double Wing::getAspectRatio() {1204 return aspect_ratio ;1205}12061207/**

- 85 -

Załączniki

1208* double Wing::getDragCoef( int aoa )1209* returns Wing::induced_drag_coefficient[aoa]1210*/1211double Wing::getDragCoef( int aoa ) {1212 if ( aoa < aoa_iterations )1213 return induced_drag_coefficient[aoa] ;1214 else1215 return 0 ;1216}12171218/**1219* double Wing::getDragCoefDist( int aoa, int section )1220* returns Wing::induced_drag_coefficient_distribution[aoa][section[1221*/1222double Wing::getDragCoefDist( int aoa, int section ) {1223 if ( aoa < aoa_iterations && section < sections_fullspan )1224 return induced_drag_coefficient_distribution[aoa][section] ;1225 else1226 return 0 ;1227}12281229/**1230* double Wing::getGamma( int aoa, int section )1231* return Wing::gamma[aoa][section]1232*/1233double Wing::getGamma( int aoa, int section ) {1234 if ( aoa < aoa_iterations && section < sections_fullspan )1235 return gamma[aoa][section] ;1236 else1237 return 0 ;1238}12391240/**1241* double Wing::getFluidDensity()1242* return Wing::fluid_density1243*/1244double Wing::getFluidDensity() {1245 return fluid_density ;

- 86 -

Załączniki

1246}12471248/**1249* double Wing::getFluidVelocity()1250* return Wing::fluid_velocity1251*/1252double Wing::getFluidVelocity() {1253 return fluid_velocity ;1254}12551256/**1257* int Wing::getFourierAccuracy()1258* return Wing::fourier_accuracy1259*/1260int Wing::getFourierAccuracy() {1261 return fourier_accuracy ;1262}12631264/**1265* double Wing::getLiftCoef( int aoa )1266* returns Wing::lift_coefficient1267*/1268double Wing::getLiftCoef( int aoa ) {1269 if ( aoa < aoa_iterations )1270 return lift_coefficient[aoa] ;1271 else1272 return 0 ;1273}12741275/**1276* double Wing::getLiftCoefDist( int aoa, int section )1277* returns Wing::lift_coefficient_distribution[aoa][section]1278*/1279double Wing::getLiftCoefDist( int aoa, int section ) {1280 if ( aoa < aoa_iterations && section < sections_fullspan )1281 return lift_coefficient_distribution[aoa][section] ;1282 else1283 return 0 ;

- 87 -

Załączniki

1284}12851286/**1287* int Wing::getSections() 1288* returns Wing::sections1289*/1290int Wing::getSections() {1291 return sections ;1292}12931294/**1295* int Wing::getSectionsFullspan()1296* returns Wing::sections_fullspan1297*/1298int Wing::getSectionsFullspan() {1299 return sections_fullspan ;1300}13011302/**1303* int Wing::getSectionsIterations()1304* returns Wing::sections_iterations1305*/1306int Wing::getSectionsIterations() {1307 return sections_iterations ;1308}13091310/**1311* double Wing::getSectionAngle( int )1312* returns Wing::sections_data[4][i]1313*/1314double Wing::getSectionAngle( int i ) {1315 if ( i < sections )1316 return sections_data[4][i] ;1317 else1318 return 0 ;1319}13201321/**

- 88 -

Załączniki

1322* double Wing::getSectionsLEX( int )1323* returns Wing::sections_data[1][i]1324*/1325double Wing::getSectionLEX( int i ) {1326 if ( i < sections )1327 return sections_data[1][i] ;1328 else1329 return 0 ;1330}13311332/**1333* double Wing::getSectionSlope( int )1334* returns Wing::sections_data[3][i]1335*/1336double Wing::getSectionSlope( int i ) {1337 if ( i < sections )1338 return sections_data[3][i] ;1339 else1340 return 0 ;1341}13421343/**1344* double Wing::getSectionsTEX( int )1345* returns Wing::sections_data[2][i]1346*/1347double Wing::getSectionTEX( int i ) {1348 if ( i < sections )1349 return sections_data[2][i] ;1350 else1351 return 0 ;1352}13531354/**1355* double Wing::getSectionY( int )1356* returns Wing::sections_data[0][i]1357*/1358double Wing::getSectionY( int i ) {1359 if ( i < sections )

- 89 -

Załączniki

1360 return sections_data[0][i] ;1361 else1362 return 0 ;1363}13641365/**1366* double Wing::getTaperRatio() 1367* returns Wing::taper_ratio1368*/1369double Wing::getTaperRatio() {1370 return taper_ratio ;1371}13721373/**1374* double Wing::getVelocityDistribution( int aoa, int section )1375* return Wing::induced_velocity_distribution[aoa][section]1376*/1377double Wing::getVelocityDist( int aoa, int section ) {1378 if ( aoa < aoa_iterations && section < sections_fullspan )1379 return induced_velocity_distribution[aoa][section] ;1380 else1381 return 0 ;1382}13831384/**1385* double Wing::getWingArea() 1386* returns Wing::wing_area1387*/1388double Wing::getWingArea() {1389 return wing_area ;1390}13911392/**1393* double Wing::getWingSpan() 1394* returns Wing::wing_span1395*/1396double Wing::getWingSpan() {1397 return wing_span ;

- 90 -

Załączniki

1398}13991400/**1401* double Wing::getWingSpanCoef( int section )1402* return 2 * Wing::wingspan[section] / Wing::wing_span1403* ( 2 * y / L )1404*/1405double Wing::getWingSpanCoef( int section ) {1406 if ( section < sections_fullspan )1407 return ( 2 * wingspan[section] / wing_span ) ;1408 else1409 return 0 ;1410}14111412/**1413* bool Wing::isParametersSaved()1414* returns Wing::parameters_saved1415*/1416bool Wing::isParametersSaved() {1417 return parameters_saved ; 1418}14191420/**1421* bool Wing::isResultsUpToDate() 1422* returns Wing::results_uptodate1423*/1424bool Wing::isResultsUpToDate() {1425 return results_uptodate ;1426}14271428/**1429* bool Wing::readFromFile( const char* file )1430* wing geometry, computation parameters and results from file1431* returns TRUE on success1432* returns FALSE on failure1433*/1434bool Wing::readFromFile( const char* file ) {1435 int a, i, n ;

- 91 -

Załączniki

1436 FILE* fl ;1437 1438 if ((fl=fopen(file, "r"))!=NULL) {1439 // reading number of input cross sections1440 fscanf( fl, "%d", &sections ) ;1441 // creating wing geometry input arrays1442 for ( i = 0; i < 5; i++ ) {1443 sections_data[i] = new double [sections] ;1444 }1445 // reading wing geometry input1446 for ( i = 0; i < sections; i++ ) {1447 fscanf( fl, "%lf %lf %lf %lf %lf", &sections_data[0][i],

&sections_data[1][i], &sections_data[2][i], &sections_data[3][i], &sections_data[4][i] ) ;

1448 }1449 // calculating geometry1450 calculateGeometry() ;1451 // reading parameters1452 fscanf( fl, "%lf %lf %d %lf %lf %lf %d %d\n", &aoa_start, &aoa_finish,

&aoa_iterations, &aoa_step, &fluid_velocity, &fluid_density, &sections_iterations, &fourier_accuracy ) ;

14531454 parameters_saved = true ;14551456 sections_fullspan = 2 * sections_iterations - 1 ;14571458 // checkiing if results exists1459 int are_results ;1460 fscanf( fl, "%d", &are_results ) ;14611462 // if so reading results1463 if ( are_results > 0 ) {1464 results_uptodate = true ;1465 // creating angle of attach arrays1466 angle_of_attack_deg = new double [aoa_iterations] ;1467 angle_of_attack_rad = new double [aoa_iterations] ;1468 // reading angle of attack iterations1469 for ( a = 0; a < aoa_iterations; a++ ) {1470 fscanf( fl, "%lf %lf", &angle_of_attack_deg[a], &angle_of_attack_rad[a] )

;

- 92 -

Załączniki

1471 }1472 // creating full span arrays1473 wingspan = new double [sections_fullspan] ;1474 chord_length = new double [sections_fullspan] ;1475 lift_curve_slope = new double [sections_fullspan] ;1476 angle_of_0_lift_deg = new double [sections_fullspan] ;1477 angle_of_0_lift_rad = new double [sections_fullspan] ;1478 fi = new double [sections_fullspan] ;1479 mi = new double [sections_fullspan] ;1480 // reading full span section data to file1481 for ( i = 0; i < sections_fullspan; i++ ) {1482 fscanf( fl, "%lf %lf %lf %lf %lf %lf %lf", &wingspan[i],

&chord_length[i], &lift_curve_slope[i], &angle_of_0_lift_deg[i], &angle_of_0_lift_rad[i], &fi[i], &mi[i] ) ;

1483 }1484 // creating equations' span array1485 equations_span = new double [fourier_accuracy] ;1486 // reading equations' span1487 for ( i = 0; i < fourier_accuracy; i++ ) {1488 fscanf( fl, "%lf", &equations_span[i] ) ;1489 }1490 // creating Left-Hand-Sides of equations arrays1491 equations_lhs = new double* [fourier_accuracy] ;1492 for ( i = 0; i < fourier_accuracy; i++ ) {1493 equations_lhs[i] = new double [fourier_accuracy] ;1494 }1495 // reading Left-Hand-Sides of equations1496 for ( i = 0; i < fourier_accuracy; i++ ) {1497 for ( n = 0; n < fourier_accuracy; n++ ) {1498 fscanf( fl, "%lf", &equations_lhs[i][n] ) ;1499 }1500 }1501 // creating Right-Hand-Sides of equations arrays and Fouerier series

terms array1502 equations_rhs = new double* [aoa_iterations] ;1503 fourier_terms = new double* [aoa_iterations] ;1504 for ( a = 0; a < aoa_iterations; a++ ) {1505 equations_rhs[a] = new double [fourier_accuracy] ;1506 fourier_terms[a] = new double [fourier_accuracy] ;

- 93 -

Załączniki

1507 }1508 // reading Right-Hand-Sides of equations1509 for ( i = 0; i < fourier_accuracy; i++ ) {1510 for ( a = 0; a < aoa_iterations; a++ ) {1511 fscanf( fl, "%lf", &equations_rhs[a][i] ) ;1512 }1513 }1514 // reading Fourier series terms1515 for ( n = 0; n < fourier_accuracy; n++ ) {1516 for ( a = 0; a < aoa_iterations; a++ ) {1517 fscanf( fl, "%lf", &fourier_terms[a][n] ) ;1518 }1519 }1520 // creating spanwise distribution characteristics' arrays1521 gamma = new double* [aoa_iterations] ;1522 lift_coefficient_distribution = new double* [aoa_iterations] ;1523 induced_velocity_distribution = new double* [aoa_iterations] ;1524 induced_drag_coefficient_distribution = new double* [aoa_iterations] ;1525 for ( a = 0; a < aoa_iterations; a++ ) {1526 gamma[a] = new double [sections_fullspan] ;1527 lift_coefficient_distribution[a] = new double [sections_fullspan] ;1528 induced_velocity_distribution[a] = new double [sections_fullspan] ;1529 induced_drag_coefficient_distribution[a] = new double [sections_fullspan]

;1530 }1531 // reading Wing::gamma (circulation)1532 for ( i = 0; i < sections_fullspan; i++ ) {1533 for ( a = 0; a < aoa_iterations; a++ ) {1534 fscanf( fl, "%lf", &gamma[a][i] ) ;1535 }1536 }1537 // reading Wing::lift_coefficient_distribution1538 for ( i = 0; i < sections_fullspan; i++ ) {1539 for ( a = 0; a < aoa_iterations; a++ ) {1540 fscanf( fl, "%lf", &lift_coefficient_distribution[a][i] ) ;1541 }1542 }1543 // reading Wing::induced_velocity_distribution1544 for ( i = 0; i < sections_fullspan; i++ ) {

- 94 -

Załączniki

1545 for ( a = 0; a < aoa_iterations; a++ ) {1546 fscanf( fl, "%lf", &induced_velocity_distribution[a][i] ) ;1547 }1548 }1549 // reading Wing::induced_drag_coefficient_distribution1550 for ( i = 0; i < sections_fullspan; i++ ) {1551 for ( a = 0; a < aoa_iterations; a++ ) {1552 fscanf( fl, "%lf", &induced_drag_coefficient_distribution[a][i] ) ;1553 }1554 }1555 }1556 // creating arrays of angle of attack dependent characteristics1557 lift_coefficient = new double [aoa_iterations] ;1558 induced_drag_coefficient = new double [aoa_iterations] ;1559 // reading Wing::lift_coefficient1560 for ( a = 0; a < aoa_iterations; a++ ) {1561 fscanf( fl, "%lf", &lift_coefficient[a] ) ;1562 }1563 // reading Wing::induced_drag_coefficient1564 for ( a = 0; a < aoa_iterations; a++ ) {1565 fscanf( fl, "%lf", &induced_drag_coefficient[a] ) ;1566 }1567 fclose( fl ) ;1568 strcpy( file_name, file ) ;1569 return true ;1570 } else1571 return false ;1572}15731574/** bool Wing::setParametres( double, double, int, double, double, int,

int )1575* sets parameters and deletes Wing::equation_lhs array 1576* returns TRUE on success1577* returns FALSE on failure1578*/1579bool Wing::setParameters( double a_start, double a_finish, int a_iterations,

double f_velocity, double f_density, int s_iterations, int f_accuracy ) {1580 bool input_valid = true ;1581

- 95 -

Załączniki

1582 // AoA Iteration Start Value cannot be greater than AoA Iteration Finish Value

1583 if ( a_start == a_finish ) {1584 // if AoA Iteration Start Value eq. to AoA Iteration Finish Value1585 // AoA Number of Iterations should be 11586 if ( ! a_iterations == 1 ) input_valid = false ;1587 } else if ( a_start < a_finish ) {1588 // if AoA Iteration Start Value less than AoA Iteration Finish Value1589 // AoA Number of Iterations should be greater than 11590 if ( ! a_iterations > 1 ) input_valid = false ;1591 } else1592 input_valid = false ;1593 1594 // Fluid Velocity should be greater than 0.01595 if ( ! f_velocity > 0.0 ) input_valid = false ;1596 1597 // Fluid Density should be greater than 0.01598 if ( ! f_density > 0.0 ) input_valid = false ;1599 1600 // Number of Cross Sections should be greater or equal to Wing::sections1601 if ( ! s_iterations >= sections ) input_valid = false ;1602 1603 // Fourier Series Accuracy should be smaller than Number of Cross

Section less by 11604 if ( ! s_iterations > f_accuracy ) input_valid = false ;1605 1606 // If all parameters are valid delete Wing::equations_lhs and save

parameters1607 if ( input_valid ) {1608 aoa_start = a_start ;1609 aoa_finish = a_finish ;1610 aoa_iterations = a_iterations ;1611 fluid_velocity = f_velocity ;1612 fluid_density = f_density ;1613 sections_iterations = s_iterations ;1614 fourier_accuracy = 2 * f_accuracy - 1 ;1615 parameters_saved = true ;1616 }1617

- 96 -

Załączniki

1618 return input_valid ;1619}16201621/**1622* bool Wing::writeToDefaultFile()1623* rewrites wing geometry, computation parameters and results to file1624* if file exists (file_name exists)1625* returns TRUE on success1626* returns FALSE on failure1627*/1628bool Wing::writeToDefaultFile() {1629 if ( file_name ) {1630 return writeToFile(file_name) ;1631 } else1632 return false ;1633}16341635/**1636* bool Wing::writeToFile( const char* file )1637* writes wing geometry, computation parameters and results to file1638* returns TRUE on success1639* returns FALSE on failure1640*/1641bool Wing::writeToFile( const char* file ) {1642 int a, i, n ;1643 FILE* fl ;1644 1645 if ((fl=fopen(file, "w"))!=NULL) {1646 // writing number of input cross sections1647 fprintf( fl, "%d\n", sections ) ;1648 // writing wing geometry inptu1649 for ( i = 0; i < sections; i++ ) {1650 fprintf( fl, "%f %f %f %f %f\n", sections_data[0][i], sections_data[1]

[i], sections_data[2][i], sections_data[3][i], sections_data[4][i] ) ;1651 }1652 // writing parameters1653 fprintf( fl, "%f %f %d %f %f %f %d %d\n", aoa_start, aoa_finish,

aoa_iterations, aoa_step, fluid_velocity, fluid_density, sections_iterations, fourier_accuracy ) ;

- 97 -

Załączniki

1654 // writing results1655 if ( results_uptodate ) {1656 // results exists1657 fprintf( fl, "%d\n", 1 ) ;1658 // writing angle of attack iterations1659 for ( a = 0; a < aoa_iterations; a++ ) {1660 fprintf( fl, "%f %f\n", angle_of_attack_deg[a],

angle_of_attack_rad[a] ) ;1661 }1662 // writing full span section data to file1663 for ( i = 0; i < sections_fullspan; i++ ) {1664 fprintf( fl, "%f %f %f %f %f %f %f\n", wingspan[i], chord_length[i],

lift_curve_slope[i], angle_of_0_lift_deg[i], angle_of_0_lift_rad[i], fi[i], mi[i] ) ;

1665 }1666 // writing equations' span1667 for ( i = 0; i < fourier_accuracy; i++ ) {1668 fprintf( fl, "%f\n", equations_span[i] ) ;1669 }1670 // writing Left-Hand-Sides of equations1671 for ( i = 0; i < fourier_accuracy; i++ ) {1672 for ( n = 0; n < fourier_accuracy; n++ ) {1673 if ( n == fourier_accuracy -1 )1674 fprintf( fl, "%f", equations_lhs[i][n] ) ;1675 else1676 fprintf( fl, "%f ", equations_lhs[i][n] ) ;1677 }1678 fprintf( fl, "\n" ) ;1679 }1680 // writing Right-Hand-Sides of equations1681 for ( i = 0; i < fourier_accuracy; i++ ) {1682 for ( a = 0; a < aoa_iterations; a++ ) {1683 if ( a == aoa_iterations -1 )1684 fprintf( fl, "%f", equations_rhs[a][i] ) ;1685 else1686 fprintf( fl, "%f ", equations_rhs[a][i] ) ;1687 }1688 fprintf( fl, "\n" ) ;1689 }

- 98 -

Załączniki

1690 // writing Fourier series terms1691 for ( n = 0; n < fourier_accuracy; n++ ) {1692 for ( a = 0; a < aoa_iterations; a++ ) {1693 if ( a == aoa_iterations -1 )1694 fprintf( fl, "%f", fourier_terms[a][n] ) ;1695 else1696 fprintf( fl, "%f ", fourier_terms[a][n] ) ;1697 }1698 fprintf( fl, "\n" ) ;1699 }1700 // writing Wing::gamma (circulation)1701 for ( i = 0; i < sections_fullspan; i++ ) {1702 for ( a = 0; a < aoa_iterations; a++ ) {1703 if ( a == aoa_iterations -1 )1704 fprintf( fl, "%f", gamma[a][i] ) ;1705 else1706 fprintf( fl, "%f ", gamma[a][i] ) ;1707 }1708 fprintf( fl, "\n" ) ;1709 }1710 // writing Wing::lift_coefficient_distribution1711 for ( i = 0; i < sections_fullspan; i++ ) {1712 for ( a = 0; a < aoa_iterations; a++ ) {1713 if ( a == aoa_iterations -1 )1714 fprintf( fl, "%f", lift_coefficient_distribution[a][i] ) ;1715 else1716 fprintf( fl, "%f ", lift_coefficient_distribution[a][i] ) ;1717 }1718 fprintf( fl, "\n" ) ;1719 }1720 // writing Wing::induced_velocity_distribution1721 for ( i = 0; i < sections_fullspan; i++ ) {1722 for ( a = 0; a < aoa_iterations; a++ ) {1723 if ( a == aoa_iterations -1 )1724 fprintf( fl, "%f", induced_velocity_distribution[a][i] ) ;1725 else1726 fprintf( fl, "%f ", induced_velocity_distribution[a][i] ) ;1727 }

- 99 -

Załączniki

1728 fprintf( fl, "\n" ) ;1729 }1730 // writing Wing::induced_drag_coefficient_distribution1731 for ( i = 0; i < sections_fullspan; i++ ) {1732 for ( a = 0; a < aoa_iterations; a++ ) {1733 if ( a == aoa_iterations -1 )1734 fprintf( fl, "%f", induced_drag_coefficient_distribution[a][i] ) ;1735 else1736 fprintf( fl, "%f ", induced_drag_coefficient_distribution[a][i] ) ;1737 }1738 fprintf( fl, "\n" ) ;1739 }1740 // writing Wing::lift_coefficient1741 for ( a = 0; a < aoa_iterations; a++ ) {1742 fprintf( fl, "%f\n", lift_coefficient[a] ) ;1743 }1744 // writing Wing::induced_drag_coefficient1745 for ( a = 0; a < aoa_iterations; a++ ) {1746 fprintf( fl, "%f\n", induced_drag_coefficient[a] ) ;1747 }1748 } else {1749 // results doesnt exist1750 fprintf( fl, "%d", 0 ) ;1751 }1752 fclose( fl) ;1753 strcpy( file_name, file ) ;1754 return true ;1755 } else {1756 return false ;1757 }1758}

Listing A-4 Wing.class.cpp

- 100 -

Załączniki

B – Streszczenie

Celem pracy było opracowanie oprogramowania służącego do wyznaczania

podstawowych charakterystyk aerodynamicznych płata nośnego, to jest:

▪ współczynnika siły nośnej,

▪ współczynnika oporu aerodynamicznego,

▪ rozkładu współczynnika siły nośnej wzdłuż rozpiętości,

▪ rozkładu współczynnika oporu indukowanego wzdłuż rozpiętości,

▪ rozkładu prędkości indukowane wzdłuż rozpiętości.

Do realizacji tego celu opracowany został algorytm obliczeniowy oparty

o opracowaną na początku XX wieku przez Ludwika Prandtla teorię linii nośnej

i jej rozwiązanie z pomocą metody Glauerta. Teoria linii nośnej znajduje zastosowanie

do wyznaczania wyżej wymienionych charakterystyk dla płatów nośnych cechujących się

dużym wydłużeniem (rzędu 5 i większym) oraz niewielkim kątem skosu (do ok. 15 stopni)

w liniowym zakresie siły nośnej. Przeprowadzenie obliczeń dla szeregu kątów natarcia

umożliwia wyznaczenie charakterystyk od niego zależnych, a więc: pochodnej

aerodynamicznej i współczynników siły nośnej oraz oporu indukowanego w funkcji kata

natarcia.

Podstawowym założeniem teorii linii nośnej sprowadza się do zastąpienia płata

nośnego linią nośną i rozkładem cyrkulacji wzdłuż niej. Z wyznaczonego rozkładu

cyrkulacji wyznaczyć można wymienione powyżej charakterystyki.

Implementacja opracowanego algorytmu odbyła się z wykorzystaniem języka

programowania C++. Opracowana została klasa Wing odpowiadająca za zarządzanie

danymi, zarówno wejściowymi jak i wynikami, oraz realizująca obliczenia. Interfejs

graficzny zaprojektowany został z wykorzystaniem aplikacji Qt Designer.

Analiza uzyskanych wyników wykazała, że są one poprawne i zgadzają

się z obliczeniami analitycznymi z wykorzystaniem teorii linii nośnej oraz symulacją

numeryczną.

- 101 -

Załączniki

C – Bibliografia

[1] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.370[2] Phillips, F.: Mechanics of Flight. Hoboken. NJ: John Wiley & Sons Inc., 2004, p.24[3] Paraschivoiu, I.: Subsonic Aerodynamics. Montréal, QC: Presses Internationales Polytechnique, 2003, p.151[4] Paraschivoiu, I.: Subsonic Aerodynamics. Montréal, QC: Presses Internationales Polytechnique, 2003, p.153[5] Paraschivoiu, I.: Subsonic Aerodynamics. Montréal, QC: Presses Internationales Polytechnique, 2003, p.153[6] Phillips, F.: Mechanics of Flight. Hoboken. NJ: John Wiley & Sons Inc., 2004, p.24[7] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.356[8] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.357[9] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.358[10] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.358[11] Kundu, P.; Cohen, I.: Fluid Mechanics. Burlington, MA: Academic Press Inc., 2004, p.674-675[12] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.358[13] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.358[14] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.358-359[15] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.359[16] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.43-46[17] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.360[18] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.360[19] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.279[20] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.361[21] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.362[22] Prosnak, W.: Mechanika Płynów. T.1. Warszawa: PWN, 1970, s.363[23] Operating System Market Share [online]. Aliso Viejo, CA: Net Applications [dostęp: 2009-02-20].

Dostępny w Internecie: http://marketshare.hitslink.com/operating-system-market-share.aspx?qprid=8[24] Nokia to acquire Trolltech to accelerate software strategy [online]. Keilalahdentie: Nokia ShowPressRelease

[dostęp: 2009-02-20]. Dostępny w Internecie: http://www.nokia.com/A4136001?newsid=1185531[25] Grębosz, J.: Symfonia C++. T.2. Kraków: Oficyna Kallimach, 1999, s.263-264[26] Eckel, B.: Thinking in C++. Gliwice: Helion: 2002, s.184-186[27] Abbott, H.: Theory of Wing Sections, Dover: Courier Dover Publications, 1959, p.570

- 102 -