# LTP field recording statistics: fEPSP slope as percent of baseline, slices within animals and the time course

> Express fEPSP slope as percent of baseline, average over a pre-set late window for each animal, and compare animals. In simulation, testing every minute with slices as n found a false effect in 28% of studies. Python and R code.

Canonical: https://www.licklider.ai/guides/ltp-field-potential-analysis/
Section: Guides › Nested measurements
Author: Licklider · Published 2026-11-12 · Last reviewed 2026-11-12 (UTC)

> **Quick answer.** For LTP from field recordings, express each slice's fEPSP slope as **percent of its own pre-induction baseline**, average a **late window chosen in advance** (for example minutes 51–60 after high-frequency stimulation), average the slices of each **animal**, and compare animals with a Welch t-test. Show the whole time course, but do not test it minute by minute. Set baseline-stability and exclusion rules before recording, and do not exclude slices because they failed to potentiate. In a simulation of 6 vs 6 mice with 1–3 slices each and no real difference, slices as n gave false positives in 14.1% of studies; a t-test at every post-HFS minute found at least one "significant" minute in 28.3% with slices as n and in 12.6% even with mice as n; one pre-set window with mice as n gave 4.0%.

**Terms used below.** *Field excitatory postsynaptic potential (fEPSP)*: the summed synaptic response recorded extracellularly in a brain slice; its initial *slope*, fitted to the same part of the rising phase after the fibre volley in every slice (state which part; units mV/ms), measures synaptic strength; this page starts from one slope value per minute. *Baseline*: responses before induction (here 20 min). *High-frequency stimulation (HFS)*: the burst of stimuli that induces LTP. *Long-term potentiation (LTP)*: a lasting increase in fEPSP slope after induction, expressed as percent of baseline. *Post-tetanic potentiation*: the larger, short-lived increase in the first minutes after HFS. *Late window*: the minutes used to measure LTP (here 51–60). *Slice*: one brain slice recorded once; several slices often come from one animal. *Paired-pulse ratio* and *input–output curve*: checks of baseline synaptic function. *Percentage points*: the difference between two percentages (152% vs 135% of baseline is a 17-point difference). *n*: the number of independent units in a test; "slices as n" counts slices as if they were independent. *Mixed model*: a regression with a random effect (an adjustment for each animal), so slices of one animal are not treated as independent; Satterthwaite and Kenward–Roger are small-sample corrections for its test. *Welch t-test*: a two-group t-test that does not assume equal spread. *95% confidence interval (CI)*: the range of values compatible with the data. *Power*: the chance of detecting an effect that is really there. *False positive*: a "significant" result when there is no real effect.

## Which analysis for your question

| Question | Analysis | Report |
| --- | --- | --- |
| Does a genotype or drug change LTP magnitude? | Percent of baseline averaged over a pre-set late window per slice, mean per animal, Welch t-test across animals | Difference in percentage points with 95% CI, n animals (slices) |
| Uneven slices per animal | The animal mean is still the unit (the safe default); or a mixed model of one value per slice with animal as a random effect and Satterthwaite or Kenward–Roger degrees of freedom (in R: `library(lmerTest); summary(lmer(ltp ~ genotype + (1 \| mouse), data = slices))`, with one row per slice in `slices`) | Difference with 95% CI |
| Does the time course differ (early vs late)? | Each animal's change between two pre-set windows (for example post-tetanic 1–5 min minus late 51–60 min), compared across animals with a Welch t-test, or a window × group mixed model with animal as a random effect; a "significant" window next to a non-significant one does not show that the time course differs; not one test per minute | Difference in change with 95% CI |
| Is basal transmission changed? | Input–output slope and paired-pulse ratio per animal, compared across animals | Differences with 95% CI |
| A drug applied to slices from the same animals | Paired comparison within animals (drug vs vehicle slices), animals as n | Paired difference with 95% CI |

Grafe and colleagues recorded "until a stable baseline was achieved for 20 min (<10% change; <0.5 change in slope over 20 min)", calculated "paired pulse ratios ... as the slope of pulse 2/slope of pulse 1", and generated "input–output curves ... by increasing pulse width from 30 to 300 µs" ([Grafe et al. 2022](https://doi.org/10.3390/nu14102004)). Do not copy their inclusion criteria, "a minimum of 10% long-term potentiation and having a stable post-conditioning response from 50–60 min post-HFS", when the question is whether LTP differs: both criteria select slices on the outcome being compared. Lazic notes that when "several brains may be sliced into sections", the *n* "must therefore represent the number of independent observations", and lists averaging over observations or including random effects as the solutions for nested data, with summary-measure analysis for repeated measures ([Lazic 2010](https://doi.org/10.1186/1471-2202-11-5)).

## Worked example: a knockout with no real effect

Constructed data: **6 wild-type and 6 knockout mice**, 1–3 hippocampal slices each (23 slices), with the fEPSP slope recorded every minute for 20 min of baseline and 60 min after HFS. Potentiation varies between mice (standard deviation 0.35 on the log scale of the rise above baseline) and between slices within a mouse (0.30); post-tetanic potentiation decays over the first minutes; every reading has 4% noise. By design, **the knockout does not change LTP**. The data's random seed was the first one tried and was not chosen for its result. Stored code and data: [fepsp.csv](/guides/ltp-field-potential-analysis/fepsp.csv), [model.py](/guides/ltp-field-potential-analysis/model.py), [make_data.py](/guides/ltp-field-potential-analysis/make_data.py), [analysis.py](/guides/ltp-field-potential-analysis/analysis.py), [analysis.R](/guides/ltp-field-potential-analysis/analysis.R) and [the analysis output](/guides/ltp-field-potential-analysis/analysis_output.txt); analysis.py and analysis.R print the same output.

In these constructed data, LTP over minutes 51–60 was 152% of baseline in wild-type mice (range across mice 122 to 178%; 11 slices) and 135% in knockouts (118 to 178%; 12 slices).

| Analysis of constructed data with no real effect, knockout − wild-type | Result |
| --- | --- |
| A. (Not valid: slices share animals) Slices as n (12 vs 11), Welch t-test | difference −18.2 points, p = 0.091 |
| B. (Not valid: 60 tests, slices as n; these "significant" minutes are noise) A Welch t-test at each post-HFS minute | 11 minutes with p < 0.05; smallest p = 0.0098 |
| **C. Mice as n (6 vs 6), mean of each mouse's slices, Welch t-test** | **difference −17.2 points (95% CI −47.7 to 13.2), p = 0.23** |

Here the slices-as-n test (A) happened to stay above 0.05, but the per-minute tests (B) did not. A plot of the time course with stars on 11 minutes would suggest that the knockout impairs LTP; the analysis with mice as n shows that the data are compatible with anything from a 48-point decrease to a 13-point increase. Across 5,000 simulated studies of this design ([simulation.py](/guides/ltp-field-potential-analysis/simulation.py), [the simulation output](/guides/ltp-field-potential-analysis/simulation_output.txt)):

| Scenario | A. Slices as n (invalid) | B. Any of 60 minutes, slices as n (invalid) | C. Mice as n, pre-set window | D. Any of 60 minutes, mice as n (invalid) |
| --- | --- | --- | --- | --- |
| No effect, 6 vs 6 mice (false positives) | **14.1%** | **28.3%** | 4.0% | **12.6%** |
| Rise above baseline reduced by 40%, about 150% to 130% of baseline, 6 vs 6 mice (power; inflated for A, B and D) | 64.9% | 81.2% | 38.6% | 61.4% |
| No effect, 12 vs 12 mice (false positives) | 12.8% | 26.2% | 4.1% | 11.6% |
| Rise above baseline reduced by 40%, 12 vs 12 mice (power; inflated for A, B and D) | 89.4% | 95.2% | **76.4%** | 89.4% |

These percentages describe this simulated design (1–3 slices per mouse, the variation in model.py), not every LTP study. Slices as n treats slices from one mouse as independent; testing every minute adds 60 chances; it still gave 12.6% false positives with mice as n. One pre-set window with mice as n kept false positives near 5%.

With 6 mice per group, that valid analysis detected a 40% reduction in potentiation in only 38.6% of studies; with 12 per group, in 76.4%. In a design like this one, moderate changes in LTP need 12 or more mice per group.

The code expects one row per slice and minute with columns `genotype` (labels exactly `wild-type` and `knockout`), `mouse` (unique across genotypes), `slice`, `minute` (negative or zero for baseline, 1–60 after HFS; if your files count minutes from the start of recording, subtract the minute of HFS) and `slope`. Rename your columns and labels to match, change the window if yours differs, save the table as fepsp.csv (or change the file name in the code), and run the code in that folder (`python analysis.py` or `Rscript analysis.R`). Python needs NumPy, pandas and SciPy 1.11 or later (`pip install numpy pandas scipy`); the R code uses base R only. If you already have one LTP value per slice, start at the line that averages slices per mouse. Run the code once on fepsp.csv first: it should print a difference of −17.2 points.

```python
import numpy as np, pandas as pd
from scipy import stats

d = pd.read_csv("fepsp.csv"); d["sl"] = d.genotype + "-" + d.mouse.astype(str) + "-" + d.slice.astype(str)
d["pct"] = 100 * d.slope / d.sl.map(d[d.minute <= 0].groupby("sl").slope.mean())   # percent of own baseline
s = d[d.minute.between(51, 60)].groupby(["genotype", "mouse", "sl"]).pct.mean()    # LTP per slice
m = s.groupby(["genotype", "mouse"]).mean()                                       # LTP per mouse
t = stats.ttest_ind(m["knockout"], m["wild-type"], equal_var=False); ci = t.confidence_interval()
print(f"difference {m['knockout'].mean() - m['wild-type'].mean():.1f} points (95% CI {ci.low:.1f} to {ci.high:.1f}), p = {t.pvalue:.2g}")
# difference -17.2 points (95% CI -47.7 to 13.2), p = 0.23
```

```r
d <- read.csv("fepsp.csv"); d$sl <- paste(d$genotype, d$mouse, d$slice)
base <- tapply(d$slope[d$minute <= 0], d$sl[d$minute <= 0], mean); d$pct <- 100 * d$slope / base[d$sl]
s <- aggregate(pct ~ genotype + mouse + sl, data = d[d$minute >= 51 & d$minute <= 60, ], FUN = mean)
m <- aggregate(pct ~ genotype + mouse, data = s, FUN = mean)                      # LTP per mouse
t.test(pct ~ genotype, data = m)    # Welch; knockout - wild-type -17.2 points, 95% CI -47.7 to 13.2, p = 0.23
```

## Before you analyse

1. **Write down the baseline-stability rule, the late window and the exclusion criteria before recording**, and base exclusions on baseline quality or technical failure, never on whether a slice potentiated. Decide in advance what happens to a slice with missing minutes in the late window, and apply these rules to the table before running the code, which averages whatever minutes are present.
2. **Record blind to genotype or drug** where possible, and keep stimulation intensity rules (for example a fixed fraction of the maximal response) the same for every slice.
3. **Check basal transmission** (input–output curves, paired-pulse ratio) per animal, so that a change in LTP is not a change in baseline synaptic function.
4. **Average slices within animals** and plan the number of animals; extra slices from the same mouse add little.
5. **Plot the full time course with the per-animal variation**, but test only the pre-set windows ([repeated measures](/guides/repeated-measures-anova-vs-mixed-model/)).
6. **Record litter and cage**: mice from one litter or cage are not independent; use one mouse per litter, or include litter in the analysis ([what counts as n](/guides/what-counts-as-n/)).

## Check what an AI assistant ran

1. **The assistant used slices as n.** Ask for one value per animal.
2. **The assistant ran a t-test at every minute and starred the significant minutes.** Ask for the pre-set window.
3. **The assistant chose the window after looking at the curves.** Ask which window was planned.
4. **The assistant excluded slices with little potentiation.** Ask for the exclusion rules and the result with all slices that met the baseline criteria.

## Report it

> Field excitatory postsynaptic potentials (fEPSPs) were recorded in [CA1] of [1–3] slices per mouse from [6] wild-type and [6] knockout mice. After a stable [20]-min baseline ([criterion, for example less than 10% drift]), LTP was induced by [HFS protocol]; slopes were expressed as percent of each slice's baseline, and LTP was the mean of minutes [51–60], set in advance. Slice values were averaged per mouse and genotypes compared with a Welch t-test (R [4.3.3]). Slices were excluded only for [baseline criteria]; [0] slices were excluded.

> In the constructed example, which has no effect built in, LTP did not clearly differ between genotypes (knockout − wild-type [−17.2] percentage points, 95% CI [−47.7] to [13.2]; p = [0.23]; n = [6] mice per genotype, [23] slices).

Replace the bracketed values with your own.

## References

- Grafe EL, Wade MMM, Hodson CE, Thomas JD, Christie BR (2022). Postnatal choline supplementation rescues deficits in synaptic plasticity following prenatal ethanol exposure. *Nutrients* 14:2004. [doi:10.3390/nu14102004](https://doi.org/10.3390/nu14102004)
- Lazic SE (2010). The problem of pseudoreplication in neuroscientific studies: is it affecting your analysis? *BMC Neuroscience* 11:5. [doi:10.1186/1471-2202-11-5](https://doi.org/10.1186/1471-2202-11-5)

## Related

- [Patch-clamp statistics](https://www.licklider.ai/guides/patch-clamp-statistics/)
- [Repeated measures ANOVA vs mixed model](https://www.licklider.ai/guides/repeated-measures-anova-vs-mixed-model/)
- [What counts as n](https://www.licklider.ai/guides/what-counts-as-n/)
- [When can you exclude an outlier?](https://www.licklider.ai/guides/when-can-you-exclude-an-outlier/)

## How this page was made

- Written and published by Licklider. Recommendations cite peer-reviewed methods papers listed under References; cited passages were checked against the source text.
- The worked example uses constructed data. Its numbers were produced by stored code (Python 3.13 with SciPy 1.18.1; R 4.3.3, base R), and the two languages print identical output; the simulation was run in Python.
- Separate review passes checked the statistics, the citations and readability before publication.
