--- title: "AFPT -- Basic Usage" author: "Marco Klein Heerenbrink" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: fig_caption: yes html_document: toc: true toc_depth: 2 bibliography: references.bib csl: refstyle_authoryear.csl vignette: > %\VignetteIndexEntry{Basic Usage} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r} library('afpt') ``` 1. Define a bird description using the `Bird()` constructor. 2. Compute flight performance using `computeFlightPerformance()`. ## Bird description A bird can be defined using the `Bird()` construction function. This function ensures that the generated object contains all required parameters that describe the bird. ```{r} myBird <- Bird( massTotal = 0.215, # weight in kg wingSpan = 0.67, # wingspan in m wingArea = 0.0652, # wing area in m2 name = 'Jackdaw', name.scientific = 'Corvus monedula', type = 'passerine', source = 'KleinHeerenbrink M, Warfvinge K and Hedenstrom A (2016) J.Exp.Biol. 219: 10, 1572--1581' ) ``` Any parameters that are not specified, but that are required by any of the flight performance calculations will be filled in with either defaults or estimated with allometric scaling relationships. For instance, the body frontal area, that is used for computing body drag, is in this case calculated based on the specified `massTotal` from an allometric relationship for `type='passerine'`: ```{r} myBird$bodyFrontalArea ``` It is possible to modify the bird description simply by reassigning the variables in the list, i.e. ```{r} myBird$wingbeatFrequency <- 5 ``` However, it should be noted that some of the variables are related to others (e.g. `massTotal` is the sum of `massEmpty`, `massFat` and `massLoad`), so that manual changes can lead to unexpected results. The default bird settings mostly follow the suggestions in @Pennycuick2008. ## Compute flight performance Flight performance can be computed using `computeFlightPerformance()`. It calculates maximum available mechanical power from the muscles, aerodynamic (mechanical) power for flapping flight as a function of airspeed and the corresponding chemical power. ```{r} flightperf <- computeFlightPerformance(myBird) flightperf ``` This is the simplest call to `computeFlightPerformance()`. The `print()` of the `flightperf` shows a summary of the computed powercurve. The function `computeFlightPerformance()` has calculated several characteristic airspeeds: - `minimumSpeed`: the required aerodynamic power equals the maximum available muscle power[^1]. - `minimumPower`: the required aerodynamic/chemical power is minimal, i.e. this is the speed for maximum endurance. - `maximumRange`: the cost of transport is minimal, i.e this is the speed for maximum range. - `maximumSpeed`: required aerodynamic power equals the maximum available muscle power. [^1]: At the minimum speed, the assumption of fast forward flight may be invalid. See also the section about validity flags. These characteristic speeds are stored as a `data.frame` named `table`, which contains several more advanced variables not shown in the `print`, as explained in the following sections. The function `computeFlightPerformance()` also estimates the best climb performance, i.e. the maximum climb rate that can be achieved given the power available from the muscles. This data point is stored in the `data.frame` named `maxClimb`. It contains the same variables as `table`, plus an additional one: `climbRate`. Similarly, the function also produces a `data.frame` named `minTime`, which holds the flight performance for time minimizing migratory flight. At this airspeed, which will be slightly higher than the maximum range speed, the bird balances flight time with the time it takes to (re)gain the energy lost during flight. Finally, `computeFlightPerformance()` also computes a powercurve for a range of speeds. The length of this curve can be specified by providing a `length.out` argument, but the default produces 10 points. This curve can be used to visualize the speed dependency of the various variables. ```{r, fig.show='hold', fig.width=3.45, fig.cap="**Powercurves** -- aerodynamic power in black; chemical power in red. **Peak amplitude** -- optimal flapping amplitude corresponding to powercurve "} powercurve <- flightperf$powercurve plot(flightperf,symbol.speed="U") plot(powercurve$speed,powercurve$amplitude,xlab=NA,ylab=NA,type='b',xlim=c(0,20),ylim=c(20,60)) mtext(side = 1, line = 2, 'Airspeed (m/s)') mtext(side = 2, line = 2, 'Peak amplitude (deg)') ``` ### Wingbeat kinematics In the current example, the strokeplane is optimized. The model also implicitly optimizes the wingbeat amplitude for minimum induced power, so essentially the returned powercurve represents the optimal wingbeat for a given wingbeat frequency. ```{r} flightperf$table[c('speed','frequency','strokeplane','amplitude')] ``` By default, `computeFlightPerformance()` will try to optimize the strokeplane angle for minimum power at any given speed. This optimization is performed many times, which results in a high computational load. The optimization can be avoided by explicitly specifying a strokeplane angle, e.g. `computeFlightPerformance(myBird,strokeplane=0)`. ### Validity flags `table` contains flags that indicate whether the data point is outside the validity range of the model: ```{r} flightperf$table[,grep('^flags.',names(flightperf$table))] ``` In this case the flags indicate the the minimum speed is outside the model's validity range, indicating too high reduced frequency and too high thrust requirement. The model was obtained for reduced frequencies $1 \leq k_f \leq 6$ and thrust requirements (thrust to lift ratio) $0 \leq \frac{T}{L} \leq 0.3$. The flag `flags.speedLo` indicates that the data point is below the low speed limit of the model ($U<2w_\mathrm{i,h}$; airspeed is lower than twice the induced downwash in hover[^2]). Data points with flags may be reasonable extrapolations of the model, but it is safer to assume flagged data points are invalid. [^2]:see @KleinHeerenbrink2015 p. 13. ### Non-flapping drag components Stored in the `table` are also the drag components. Only the non-flapping (`Dnf`) components are stored: ```{r} flightperf$table[,grep('^Dnf.',names(flightperf$table))] ``` These are the induced drag, zero lift profile drag, lift dependent profile drag and parasitic drag, respectively. The latter includes the body drag, but also any other additional drag (e.g. the drag component of weight during climb). ```{r, fig.show='hold', fig.width=3.45, fig.cap="**Non-flapping drag components** -- Red: induced drag; green: zero-lift profile drag; blue: lift-dep. profile drag; yellow: parasitic drag;"} par(mar=c(3.1,3.1,0.4,1.1),mgp=c(1.9,.7,0),cex=0.75) with(powercurve , plot( speed, Dnf.ind, type='b', col='red3', xlab=NA, ylab=NA, xlim=c(0,20), ylim=c(0.0,0.20))) with(powercurve , lines( speed, Dnf.pro0, type='b', col='green3')) with(powercurve , lines( speed, Dnf.pro2, type='b', col='blue3')) with(powercurve , lines( speed, Dnf.par, type='b', col='yellow3')) mtext(side = 1, line = 2,'Airspeed (m/s)') mtext(side = 2, line = 2,'Drag (N)') ``` The above figure shows the magnitude of the non-flapping drag components for different speeds. The lift dependent components are very large at low speeds and they decrease rapidly with increasing speed. The parasitic drag shows the classic quadratic behaviour with speed. The zero-lift profile drag is near zero at low speeds, and increases more linearly with speed. This is due to the strong dependence of the friction coefficient on the Reynolds number. As non-flapping effectively means gliding, these drag components can be used to construct a drag polar for gliding flight. However, this ignores the wing flex that typically occurs at higher speeds. ### Drag factors and power factors Flapping the wings alters the drag experienced by the wings: $D = k_D D^\prime$ (using $D^\prime$ for non-flapping drag) [^3]. The factors $k_D$ depend on the wingbeat kinematics and are returned in `table`: ```{r} flightperf$table[,grep('^kD.',names(flightperf$table))] ``` These factors are for induced drag, zero lift profile drag and lift dependent profile drag respectively. [^3]: flapping flight factors as per @KleinHeerenbrink2015. The aerodynamic power components for flapping flight can be computed in a similar way: $P = k_P D^\prime U$. The factors $k_P$ depend on the wingbeat kinematics and are also stored in `table`: ```{r} flightperf$table[,grep('^kP.',names(flightperf$table))] ``` ```{r, fig.show='hold', fig.width=3.45, fig.cap="**Drag factors** -- Red: induced drag; green: zero-lift profile drag; blue: lift-dep. profile drag; there is no factor for parasitic drag, because this component is assumed independent of wingbeat kinematics. **Power factors** -- same legend."} par(mar=c(3.1,3.1,0.4,1.1),mgp=c(1.9,.7,0),cex=0.75) with(powercurve , plot( speed, kD.ind, type='b', col='red3', xlab=NA, ylab=NA, xlim=c(0,20), ylim=c(0.5,2.5))) with(powercurve , lines( speed, kD.pro0, type='b', col='green3')) with(powercurve , lines( speed, kD.pro2, type='b', col='blue3')) mtext(side = 1, line = 2,'Airspeed (m/s)') mtext(side = 2, line = 2,'Drag factors (-)') with(powercurve , plot( speed, kP.ind, type='b', col='red3', xlab=NA, ylab=NA, xlim=c(0,20), ylim=c(0.5,2.5))) with(powercurve , lines( speed, kP.pro0, type='b', col='green3')) with(powercurve , lines( speed, kP.pro2, type='b', col='blue3')) mtext(side = 1, line = 2,'Airspeed (m/s)') mtext(side = 2, line = 2,'Power factors (-)') ``` The above figure shows the speed dependency of the drag factors and power factors. At low speeds the lift-dependent drag factors have a low value. There is even a tendency for the factors to drop below 1. The zero-lift profile drag instead takes very large values. At these low speeds the velocity of the wings starts to become more dominant than the flight speed. ### miscellaneous Several other variables are also stored in `table`: ```{r} flightperf$table[c('frequency','L','ReynoldsNumber','CDpro0')] ``` These are respectively the wingbeat frequency (in this case as specified in `myBird`), the lift force (in this case just equal to weight), the mean chord Reynolds number, and the zero lift profile drag coefficient (dependent on mean chord Reynolds number). ## Flight condition All models by default use the internal `FLIGHTCONDITION`, which describes the standard atmosphere, with air density $\rho=1.225$ kg m^3^, gravitational acceleration $g=9.81$ m s^-2^ and kinematic viscosity $\nu=14.61\times 10^{-6}$ m^2^ s^-1^. It is possible to define an alternative flight condition: ```{r} myFlightCondition <- list( density = 0.9093, # [kg/m3] 3 km altitude gravity = 9.81, # [m/s2] viscosity = 18.63E-6, # [m2/s] 3 km altitude windSpeed = 0,# [m/s] windDir = 0 # [degrees] 0 degrees means wind is along the track direction ) ``` Air density decreases with altitude, and a density of $\rho=0.909$ kg m^3^ corresponds to a flight altitude of 3 km above sea level in the international standard atmosphere. At this altitude the kinematic viscosity has increased to $\nu=18.63\times 10^{-6}$ m^2^ s^-1^. This alternative flight condition can be used in the performance calculation as: ```{r} flightperf.ISA3 <- computeFlightPerformance(myBird,flightcondition=myFlightCondition) flightperf.ISA3 ``` Note how the power requirements have increased (this is only apparent from the `minimumPower` and `maximumRange`, as the maximum available power is unchanged), but the characteristic speeds also increased. Looking at the energetic cost per traveled distance: ```{r} COT.ISA0 <- with(flightperf$table,power.chem/speed) COT.ISA3 <-with(flightperf.ISA3$table,power.chem/speed) list(ISA0 = COT.ISA0, ISA3 = COT.ISA3) COT.ISA3/COT.ISA0 ``` it appears that flying at the maximum range speed at a higher altitude will actually reduce the maximum range (which can be attributed to the increase in kinematic viscosity, increasing the profile drag coefficient). However, the 1% increase in flight cost does pay back as a 15% reduction in flight time. In fact, if the bird cares about time minimization, flying at altitude is highly advantageous, increasing the maximum flight speed while reducing the associated cost of transport. ## References