Φανταστείτε ότι φτάνουμε σε μια λίμνη και μετράμε τα νούφαρα.
Επιστρέφοντας την επόμενη μέρα παρατηρούμε αύξηση 10%. Ο στόχος μας είναι:
Πώς, ξεκινώντας από αυτή την απλή παρατήρηση, καταλήγουμε στον τύπο της εκθετικής αύξησης μέσω μιας διαφορικής εξίσωσης;
Το ταξίδι έχει τρεις σταθμούς:
Σε χρόνο \(\Delta t = 1\) ημέρα, η μεταβολή του πληθυσμού είναι:
\[ \Delta N \;=\; N_1 - N_0 \;=\; 110 - 100 \;=\; 10 \]
Δεν μας ενδιαφέρει η απόλυτη μεταβολή (10 νούφαρα), γιατί αυτή εξαρτάται από το πόσα νούφαρα είχαμε στην αρχή. Μας ενδιαφέρει πόσο μεταβλήθηκε ο πληθυσμός ανά άτομο, ανά μονάδα χρόνου:
\[ r \;=\; \frac{\Delta N}{N \cdot \Delta t} \;=\; \frac{10}{100 \cdot 1} \;=\; 0{,}1 \;=\; 10\%/\text{ημέρα} \]
Το \(r\) ονομάζεται εγγενής (intrinsic) ρυθμός αύξησης του πληθυσμού. Είναι η βασική παράμετρος όλης της κλασικής πληθυσμιακής δυναμικής.
# Υπολογισμός του r από τα δεδομένα
N0 <- 100
N1 <- 110
dt <- 1 # μέρες
r <- (N1 - N0) / (N0 * dt)
r## [1] 0.1
Αν υποθέσουμε ότι αυτός ο ρυθμός παραμένει σταθερός, τότε σε κάθε χρονικό βήμα \(\Delta t\):
\[ \Delta N \;=\; r \, N \, \Delta t \quad\Longleftrightarrow\quad \frac{\Delta N}{\Delta t} \;=\; r N \]
| N | ΔΝ/Δt |
|---|---|
| 100 | 10 |
| 200 | 20 |
| 1000 | 100 |
| 5000 | 500 |
Αυτή είναι μια διακριτή προσέγγιση: μετράμε τον πληθυσμό σε διακριτά βήματα (κάθε μέρα).
Όμως τα νούφαρα δεν περιμένουν την αυγή για να αυξηθούν — αυξάνονται συνεχώς. Παίρνοντας το όριο όταν το χρονικό βήμα γίνεται απειροελάχιστο:
\[ \lim_{\Delta t \to 0} \frac{\Delta N}{\Delta t} \;=\; \frac{dN}{dt} \]
Καταλήγουμε στη διαφορική εξίσωση της εκθετικής αύξησης:
\[ \boxed{\;\frac{dN}{dt} \;=\; r\,N\;} \]
Διαισθητική ερμηνεία: Ο ρυθμός μεταβολής του πληθυσμού σε κάθε χρονική στιγμή είναι ανάλογος του τρέχοντος μεγέθους του πληθυσμού. Όσα περισσότερα νούφαρα, τόσο πιο γρήγορα εμφανίζονται καινούρια.
Θα λύσουμε τη \(\frac{dN}{dt} = rN\) με τη μέθοδο του χωρισμού μεταβλητών.
\[ \frac{dN}{N} \;=\; r\,dt \]
(Όλα τα \(N\) στο αριστερό μέλος, όλα τα \(t\) στο δεξί.)
\[ \int \frac{dN}{N} \;=\; \int r\,dt \quad\Longrightarrow\quad \ln(N) \;=\; r\,t + C \]
όπου \(C\) είναι σταθερά ολοκλήρωσης.
\[ N(t) \;=\; e^{rt + C} \;=\; e^{C} \cdot e^{rt} \]
Στο \(t = 0\) έχουμε \(N(0) = N_0\), οπότε:
\[ N_0 \;=\; e^{C} \cdot e^{0} \;=\; e^{C} \quad\Longrightarrow\quad e^{C} = N_0 \]
\[ \boxed{\;N(t) \;=\; N_0\, e^{r t}\;} \]
Αυτός είναι ο τύπος της εκθετικής αύξησης.
Ας σχεδιάσουμε την \(N(t) = 100 \cdot e^{0{,}1\,t}\) για 60 ημέρες:
N0 <- 100
r <- 0.1
t <- seq(0, 60, by = 0.1)
N_analytical <- N0 * exp(r * t)
df_analytical <- data.frame(t = t, N = N_analytical)
ggplot(df_analytical, aes(x = t, y = N)) +
geom_line(linewidth = 1, colour = "steelblue") +
labs(
title = "Εκθετική αύξηση πληθυσμού νούφαρων",
subtitle = expression(paste(N(t) == N[0] * e^{r*t}, ", ",
N[0] == 100, ", ", r == 0.1)),
x = "Χρόνος (ημέρες)",
y = "Πληθυσμός N(t)"
)Σε 60 ημέρες ο πληθυσμός φτάνει τα 4.0343^{4} νούφαρα — μη ρεαλιστικό για μια πεπερασμένη λίμνη! Αυτό είναι το πρόβλημα της εκθετικής αύξησης που θα αντιμετωπίσουμε αργότερα με το λογιστικό μοντέλο.
deSolveΠολύ συχνά στη βιολογία οι διαφορικές εξισώσεις δεν λύνονται αναλυτικά. Τότε χρησιμοποιούμε αριθμητικούς ολοκληρωτές. Για το συγκεκριμένο μοντέλο, που το ξέρουμε ήδη αναλυτικά, αυτό μας δίνει μια ευκαιρία να ελέγξουμε αν η αριθμητική μέθοδος συμφωνεί.
# 1. Ορίζουμε τη διαφορική εξίσωση ως συνάρτηση
exponential_model <- function(t, state, parameters) {
with(as.list(c(state, parameters)), {
dN <- r * N # dN/dt = rN
list(dN)
})
}
# 2. Παράμετροι, αρχική συνθήκη, χρόνος
parameters <- c(r = 0.1)
state <- c(N = 100)
times <- seq(0, 60, by = 0.1)
# 3. Επίλυση
out <- ode(y = state, times = times, func = exponential_model, parms = parameters)
out_df <- as.data.frame(out)
head(out_df)df_compare <- data.frame(
t = times,
Αναλυτική = N0 * exp(r * times),
Αριθμητική = out_df$N
)
ggplot(df_compare, aes(x = t)) +
geom_line(aes(y = Αναλυτική), linewidth = 1.2, colour = "steelblue") +
geom_point(aes(y = Αριθμητική),
data = df_compare[seq(1, nrow(df_compare), by = 50), ],
colour = "tomato", size = 2) +
labs(
title = "Αναλυτική (γραμμή) έναντι αριθμητικής (κουκίδες) λύσης",
x = "Χρόνος (ημέρες)",
y = "Πληθυσμός N(t)"
)## [1] 0.008490642
Το σφάλμα είναι αμελητέο — οι δύο λύσεις συμπίπτουν.
Παρατηρήστε κάτι: ξεκινήσαμε λέγοντας “αύξηση 10% την ημέρα”. Αυτή είναι μια διακριτή δήλωση. Όμως μετά γράψαμε \(r = 0{,}1\) μέσα σε συνεχή διαφορική εξίσωση. Είναι τα δύο όντως ίσα;
Αν κάθε μέρα ο πληθυσμός πολλαπλασιάζεται με το \(1{,}10\):
\[ N(t) \;=\; N_0 \cdot (1+r)^{t} \;=\; 100 \cdot 1{,}1^{t} \]
days <- 0:30
N_discrete <- 100 * (1 + 0.1)^days
N_continuous <- 100 * exp(0.1 * days)
df_dc <- data.frame(
day = rep(days, 2),
N = c(N_discrete, N_continuous),
model = factor(rep(c("Διακριτό N0·(1+r)^t",
"Συνεχές N0·exp(rt)"), each = length(days)))
)
ggplot(df_dc, aes(x = day, y = N, colour = model)) +
geom_line(linewidth = 1) +
geom_point(size = 1.5) +
labs(
title = "Διακριτή έναντι συνεχούς εκθετικής αύξησης",
subtitle = "Με την ίδια τιμή r = 0,1 τα δύο μοντέλα **δεν** ταυτίζονται",
x = "Ημέρες", y = "Πληθυσμός", colour = ""
) +
theme(legend.position = "bottom")data.frame(
Ημέρα = c(1, 5, 10, 20, 30),
Διακριτό = round(100 * 1.1^c(1, 5, 10, 20, 30), 1),
Συνεχές = round(100 * exp(0.1 * c(1, 5, 10, 20, 30)), 1)
)Στο διακριτό μοντέλο, “10% αύξηση/ημέρα” σημαίνει: στο τέλος της μέρας ο πληθυσμός είναι 110% του αρχικού.
Στο συνεχές μοντέλο με \(r = 0{,}1\), ο στιγμιαίος ρυθμός είναι 10%, αλλά επειδή τα νεογέννητα νούφαρα παράγουν αμέσως κι αυτά νέα νούφαρα (συνεχής ανατοκισμός!), στο τέλος της μέρας έχουμε:
\[ N(1) \;=\; 100 \cdot e^{0{,}1} \;\approx\; 110{,}52 \]
δηλαδή λίγο παραπάνω από 10% αύξηση.
Αν θέλουμε το συνεχές μοντέλο να δίνει ακριβώς 10% αύξηση ανά μέρα, χρειαζόμαστε:
\[ e^{r_{\text{cont}}} = 1{,}1 \quad\Longrightarrow\quad r_{\text{cont}} \;=\; \ln(1{,}1) \;\approx\; 0{,}0953 \]
## [1] 0.09531018
Στην οικολογική πράξη, τις περισσότερες φορές δουλεύουμε στο συνεχές μοντέλο και θεωρούμε \(r\) τον στιγμιαίο ρυθμό. Η διαφορά είναι μικρή για μικρά \(r\), αλλά καλό είναι να ξέρετε ότι υπάρχει.
Παίρνοντας λογάριθμο στον τύπο \(N(t) = N_0 e^{rt}\):
\[ \ln N(t) \;=\; \ln N_0 \;+\; r\,t \]
Δηλαδή ο \(\ln N\) είναι γραμμική συνάρτηση του \(t\) με κλίση ίση με \(r\). Αυτό είναι εξαιρετικά χρήσιμο πρακτικά:
Αν τα δεδομένα σας σε ημι-λογαριθμικό διάγραμμα (\(\ln N\) ως προς \(t\)) σχηματίζουν ευθεία, τότε ο πληθυσμός αυξάνεται εκθετικά, και η κλίση της ευθείας σας δίνει το \(r\).
ggplot(df_analytical, aes(x = t, y = N)) +
geom_line(linewidth = 1, colour = "steelblue") +
scale_y_log10() +
labs(
title = "Εκθετική αύξηση σε ημι-λογαριθμικό άξονα",
subtitle = "Η ευθεία γραμμή υποδηλώνει εκθετική αύξηση",
x = "Χρόνος (ημέρες)",
y = "log10(N(t))"
)# Προσομοιωμένα δεδομένα με λίγο θόρυβο
set.seed(42)
sim_days <- 0:30
sim_N <- 100 * exp(0.1 * sim_days) * exp(rnorm(length(sim_days), 0, 0.05))
# Γραμμική παλινδρόμηση log(N) ~ t
fit <- lm(log(sim_N) ~ sim_days)
summary(fit)$coefficients## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.63477789 0.021337509 217.21270 3.966003e-48
## sim_days 0.09829637 0.001221782 80.45327 1.212714e-35
## Εκτιμώμενο r = 0.0983 (πραγματικό r = 0.1)
## Εκτιμώμενο N0 = 103.01 (πραγματικό N0 = 100)
Μια χρήσιμη ποσότητα: σε πόσο χρόνο διπλασιάζεται ο πληθυσμός;
\[ 2 N_0 = N_0 e^{r T_2} \;\Longleftrightarrow\; T_2 = \frac{\ln 2}{r} \]
## Χρόνος διπλασιασμού των νούφαρων: 6.93 ημέρες
Άρα τα νούφαρα διπλασιάζονται περίπου κάθε 7 μέρες.
Παίξτε με το \(r\). Σχεδιάστε στο ίδιο διάγραμμα την εκθετική αύξηση για \(r = 0{,}05\), \(r = 0{,}1\) και \(r = 0{,}2\). Πώς αλλάζει ο χρόνος διπλασιασμού;
Αρνητικό \(r\). Τι συμβαίνει αν \(r < 0\); Σχεδιάστε την περίπτωση \(r = -0{,}05\) και ερμηνεύστε βιολογικά.
Εκτίμηση από πραγματικά δεδομένα. Σας δίνονται οι παρακάτω μετρήσεις:
Εκτιμήστε το \(r\) με γραμμική παλινδρόμηση στο \(\ln N\) και προβλέψτε τον πληθυσμό στις 60 ημέρες.
Ο μαθηματικός κίνδυνος. Με \(r = 0{,}1\) και \(N_0 = 100\) νούφαρα, σε πόσες μέρες τα νούφαρα θα ξεπεράσουν τον αριθμό των ατόμων στη Γη (\(\approx 8 \times 10^{9}\)); Τι μας λέει αυτό για τους περιορισμούς του εκθετικού μοντέλου;
Το εκθετικό μοντέλο δεν μπορεί να ισχύει για πάντα. Σε μια πραγματική λίμνη υπάρχουν περιορισμοί: χώρος, φως, θρεπτικά συστατικά. Σε κάποιο σημείο ο πληθυσμός θα κορεστεί.
Στο επόμενο μάθημα θα τροποποιήσουμε τη διαφορική εξίσωση ώστε να συμπεριλάβει τη φέρουσα ικανότητα \(K\) του περιβάλλοντος:
\[ \frac{dN}{dt} \;=\; r N \left(1 - \frac{N}{K}\right) \]
Αυτή είναι η λογιστική εξίσωση — και είναι το θέμα του επόμενου εργαστηρίου.
## R version 4.6.1 (2026-06-24)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.4 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.12.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Europe/Athens
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] deSolve_1.42 ggplot2_4.0.3
##
## loaded via a namespace (and not attached):
## [1] vctrs_0.7.3 cli_3.6.6 knitr_1.51 rlang_1.2.0
## [5] xfun_0.57 otel_0.2.0 S7_0.2.2 jsonlite_2.0.0
## [9] labeling_0.4.3 glue_1.8.1 htmltools_0.5.9 sass_0.4.10
## [13] scales_1.4.0 rmarkdown_2.31 grid_4.6.1 evaluate_1.0.5
## [17] jquerylib_0.1.4 fastmap_1.2.0 yaml_2.3.12 lifecycle_1.0.5
## [21] compiler_4.6.1 RColorBrewer_1.1-3 farver_2.1.2 digest_0.6.39
## [25] R6_2.6.1 bslib_0.10.0 tools_4.6.1 withr_3.0.2
## [29] gtable_0.3.6 cachem_1.1.0