IntoMindLearn

Lab 3 · Middle school

Age Detector

An AI model on the IntoMind One estimates your age from your EEG. How good is its guess, really?

Get ready

You need

  • An IntoMind One, charged, with its cable unplugged
  • A computer with Chrome or Edge
  • A chair for the wearer
  • A slip of paper for each person
  • A clean microfiber, soft cotton or eyeglass cloth

Roles

Wearer
Wears the IntoMind One and sits still, eyes open.
Timekeeper
Calls out each minute: one, two, three.
Recorder
Writes down the number at each minute.
Skeptic
Watches the wearer, and writes down every blink, word or movement.

Take turns, so everyone who wants to can be the wearer. In a group of three, the timekeeper is the skeptic too.

Rules

  • Unplug the cable before anyone puts it on.
  • Wearing it is your choice. Every role is a real one.
  • Nobody has to say their age.
  • Wipe the electrodes between wearers with the soft cloth, since a rough one can scratch their gold coating.

Steps

  1. Put it on and connect

    A head from the front, with an orange area on the forehead.A head from the front, with an orange area on the forehead.Forehead
    A head from above, with an orange area on the top.A head from above, with an orange area on the top.Top
    A head from behind, with an orange area on the back.A head from behind, with an orange area on the back.Back

    This time, any of these places works: wherever the strap holds the IntoMind One and its electrodes touch skin. This model learned from recordings made with electrodes in many different places, so there is no one right spot.

    Unplug the cable. The wearer sits down. Put it on, part the hair under each electrode so it touches skin, and press it down until it feels firm but not tight.

    Open the Age Detector demo, press Connect your IntoMind One, and choose yours from the list.

    You should seeConnected at the top right. After a few seconds, a number that jumps around at first, with “± 9 years” and a count of windows under it.

  2. Sit still for three minutes

    PredictBetween minutes two and three, the number will move than between minutes one and two.

    The wearer sits still with eyes open. At one, two and three minutes, the timekeeper calls out, and the recorder writes down the number, and at three minutes the count of windows too.

    Press Save image only if the wearer wants a picture of their estimate. The picture is theirs to keep or delete.

    WearerAt 1 minuteAt 2 minutesAt 3 minutesWindows at 3 minutesSkeptic's notes
    1
    2
    3
    4

    You should seeThe number changing less and less each minute.

  3. Work out your error, privately

    On your slip of paper, not on this page: subtract your real age from your final number. That is the model's error for you. Keep your age to yourself.

    Then, on the same slip, write how many years your age is from the most common age in your class. If you want to, put your slip in the box, with no name on it.

    You should seeAn error that could be anywhere from zero to well past nine years, too high or too low.

  4. The class's errors

    Your teacher reads out the slips. Work out the average size of the model's errors, ignoring whether each was too high or too low. Then do the same for the second number on each slip: the error of guessing that everyone is the class's most common age.

    Work it outThe model missed by years on average. Guessing the class's most common age missed by years.

    You should seeThe simple guess winning, by a long way.

What happened

This model learned from the EEG of thousands of people whose ages were known. It looks at four seconds of your EEG at a time, and makes a guess. The number on the screen is the average of its guesses so far, which is why it settled.

Every guess can be wrong. When the model was tested on people it had never learned from, it was off by about nine years on average. That is its error, and it is what “± 9 years” means.

Guessing that everyone is the class's most common age is a baseline: something simple to compare the model against. In a class of people the same age, the baseline wins. The number doesn't tell you how old your brain is. It shows that this model can find a little information about age in EEG, with a large error.

Simulated One guess for every four seconds of EEG, in gray, and their average so far, in orange, with the model's error of about nine years on either side. The average settles.

Talk about it

  1. The screen said ± 9 years. What does that mean?

  2. Your class is all about the same age. Who guesses better: the model, or someone who says everyone is the class's age? Why?

  3. Does the number tell you how old your brain is?

Lab 3 · High school

Age Detector

An AI model on the IntoMind One estimates your age from your EEG. How big is its error, and is it any better than a guess that ignores your brain completely?

Background

Read it the night before.

A model on the chip

The IntoMind One's encoder sums up each four seconds of EEG as 76 numbers, its embedding, and a small model, the age head, turns those 76 numbers into an age. The head learned from the EEG of 3,742 people of known age, in 93 studies.

The demo shows the average of the head's estimates so far, one for each four-second window, so the number settles as more windows come in.

The model on the chip Four seconds of EEG go into the encoder and come out as 76 numbers. The age head reads them and gives one answer.

Its error, and what to compare it with

The head was tested on whole studies it had never seen. Averaging a person's windows, its error was 9.16 years on average: that is the “± 9 years” on the screen.

Whether that is good depends on what you compare it with. A baseline that ignores the brain completely, always guessing the average age of the people the head learned from, was off by 9.77 years.

Published How many years better the head did than each baseline, averaging a person's windows, with a 95 percent interval over studies. Against the average age, the interval crosses zero.

Where it goes, and why

Anywhere. The encoder reads its four seconds of EEG without being told where the electrodes are, and the head was scored across studies that placed their electrodes differently, so the published error already includes that variety. The top of the head, Cz, is on the midline and easy to find, and the back, Oz, and the forehead, Fpz, work too.

Any site The IntoMind One at Cz, the top of the head. Oz, at the back, and Fpz, at the front, work as well.

Get ready

You need

  • An IntoMind One, charged, with its cable unplugged
  • A computer with Chrome or Edge
  • A chair for the wearer
  • A slip of paper for each person
  • A clean microfiber, soft cotton or eyeglass cloth

Roles

Wearer
Wears the IntoMind One and sits still, eyes open.
Timekeeper
Calls out each minute: one, two, three.
Recorder
Writes down the number and the windows at each minute.
Skeptic
Watches the wearer, and writes down every blink, word or movement.

Take turns, so everyone who wants to can be the wearer. In a group of three, the timekeeper is the skeptic too.

Rules

  • Unplug the cable before anyone puts it on.
  • Wearing it is your choice. Every role is a real one.
  • Nobody has to say their age.
  • Wipe the electrodes between wearers with the soft cloth, since a rough one can scratch their gold coating.

Steps

  1. Put it on and connect

    A head from the front, with an orange area on the forehead.A head from the front, with an orange area on the forehead.Fpz
    A head from above, with an orange area on the top.A head from above, with an orange area on the top.Cz
    A head from behind, with an orange area on the back.A head from behind, with an orange area on the back.Oz

    Choose a site, and put the IntoMind One on there, with the strap around the head. Unplug the cable first. Part the hair under each electrode so it touches skin, and press it down until it feels firm but not tight.

    Open the Age Detector demo, press Connect your IntoMind One, and choose yours from the list.

    You should seeConnected at the top right. After a few seconds, a number that jumps at first, with “± 9 years” and the count of windows under it.

  2. Sit still for three minutes

    PredictBetween minutes two and three, the number will move than between minutes one and two, because .

    The wearer sits still with eyes open. At one, two and three minutes, the timekeeper calls out, and the recorder writes down the number and the count of windows.

    Press Save image only if the wearer wants a picture of their estimate. The picture is theirs to keep or delete.

    WearerAt 1 minuteAt 2 minutesAt 3 minutesWindows at 3 minutesSkeptic's notes
    1
    2
    3
    4

    You should seeThe number changing less and less each minute.

  3. Work out your error, privately

    On your slip of paper, not on this page: subtract your real age from your final number. That is the head's error for you. Keep your age to yourself.

    On the same slip, write how many years your age is from the most common age in your class. If you want to, put your slip in the box, with no name on it.

  4. The class's errors

    Your teacher reads out the slips. Work out the mean error of the head, ignoring whether each was too high or too low, and the mean error of guessing the class's most common age.

    Work it outFrom slips: the head's mean error was years, and the class's most common age missed by .

    You should seeThe simple guess winning, by a long way.

Work it out

Work it outFor the first wearer, the number moved between minutes one and two, and between two and three. Did it settle the way you predicted?

Talk about it

  1. Averaging a person's windows, the head was off by 9.16 years, and always guessing the average age of the people it learned from was off by 9.77. What does that tell you?

  2. On a single four-second window, the head was off by 9.93 years, and the average-age guess by 9.75. Why does averaging windows help the head, and not the guess?

  3. Why was the head tested on whole studies it never saw, rather than on new readings from people it learned from?

  4. Was the class's mean error bigger or smaller than nine years? Give a reason it might differ.

Sources

IntoMind (2026). Heads for encoder e2f9b60f411f0e73. github.com/intomind/eeg-foundation-model-heads.

Lab 3 · College

Age Detector

The age head is said to read any site on the head. Does moving the IntoMind One change one person's estimate by more than the spread of its own windows, and in this room, does the head beat guessing the room's most common age?

Background

Read it before the lab.

What runs, and where

Every four seconds the IntoMind One's encoder turns the EEG into 76 numbers, and the age head, built into the model and selected from power on, turns them into years. The demo averages the estimates, leaving out windows with a gap in the signal, and shows the mean with the published error, ± 9 years.

The encoder takes no electrode positions, and the head was scored with the positions hidden, on montages of 2, 4 and 8 electrodes. So it should read any site: a claim you can test on one person.

Simulated An estimate from every four seconds of EEG, and the mean so far, with the published error either side. The mean settles. The band doesn't narrow: ± 9 years is the error after a person's windows are averaged.

What the evaluation says

Averaged over a person's windows, the head misses by 9.16 years on studies it never saw, against 9.77 for always guessing the training studies' mean age: 0.61 years better, with a 95 percent interval from 0.03 worse to 1.25 better. It isn't clearly better than a guess that ignores the brain, and its estimates are pulled toward that mean.

In one room, the fair guess is the room's own most common age, and it can do far better.

Published How many years better the age head is, averaged over a person's windows, with 95 percent intervals over studies.

Comparing two sites fairly

Neighboring windows are alike, so thirty windows aren't thirty independent estimates. Average them in blocks of five, and compare the two sites' blocks with a permutation test: every way of splitting the blocks into two sites, scored the same way.

Hypothesis

Write it before anyone puts the IntoMind One on.

HypothesisMoving the IntoMind One from to will change the estimate by . In this room, the head's mean error will be than the error of guessing the room's most common age.

Get ready

You need

  • An IntoMind One, charged, with its cable unplugged
  • A computer with Chrome or Edge, Python 3 with the intomind package, and the demos' source
  • A chair for the wearer, and a slip of paper
  • A clean microfiber, soft cotton or eyeglass cloth

Roles

Wearer
Wears the IntoMind One, and sits still with the eyes open.
Operator
Runs the demo and the program, and saves each run.
Analyst
Writes down each run, and every blink or movement.

Rotate, so everyone who wants to is the wearer once.

Rules

  • Unplug the cable before anyone puts it on.
  • Wearing it is your choice. Every role is a real one.
  • Nobody has to say their age. Errors go in the box without names.
  • Wipe the electrodes between wearers with the soft cloth, since a rough one can scratch their gold coating.

Procedure

  1. Put it on at the first site

    Any site your group chooses. The top of the head, at Cz, is easy to hold with the strap. Unplug the cable, part the hair under each electrode, and press it down until it feels firm but not tight.

  2. Check it on the demo

    Open the Age Detector demo and connect. Watch the estimate for a minute while the wearer sits still with the eyes open, then close the tab: the IntoMind One talks to one program at a time.

    You should seeA number that jumps at first and then settles, with ± 9 years and the count of windows under it.

  3. Run the head from code

    cd python
    python3 -u age.py | tee w1-first.txt

    From the demos' source, run the same head as a program for two minutes, and keep what it prints. Each wearer in turn, with their number in the file's name.

    You should seeA line for every four-second window, its estimate and the mean so far, any window with a gap marked and kept out of the mean, and the published error at the end.

  4. A second site

    One wearer per group: move the IntoMind One far from the first site, to the back of the head or the forehead, press it down, and run it again into w1-second.txt.

  5. Your error, privately

    On a slip, with no name: your final estimate minus your age, and the room's most common age minus your age. Put it in the box only if you want to.

    WearerSiteSaved asWindows usedMean estimateSpread of the windowsNotes
    1w1-first.txt
    1w1-second.txt
    2w2-first.txt
    3w3-first.txt

Analysis

Read each saved run, compare the two sites in blocks of five windows, and test the difference by permuting the blocks.

import re
from itertools import combinations
import numpy as np

def estimates(path):
    """Each window's estimate from a saved run of age.py, leaving out the flagged windows."""
    lines = [l for l in open(path) if l.startswith("window ") and "kept out" not in l]
    return np.array([float(re.search(r": ([\d.]+) years", l).group(1)) for l in lines])

def blocks(x, size=5):
    """Means of consecutive blocks of windows: neighboring windows are alike."""
    n = len(x) // size
    return x[:n * size].reshape(n, size).mean(axis=1)

first, second = estimates("w1-first.txt"), estimates("w1-second.txt")   # the runs you saved
for name, x in (("first", first), ("second", second)):
    print(name, "site:", len(x), "windows, mean", round(x.mean(), 1), "spread", round(x.std(ddof=1), 1))

a, b = blocks(first), blocks(second)
diff = b.mean() - a.mean()
both = np.r_[a, b]
null = [both[list(c)].mean() - np.delete(both, list(c)).mean()
        for c in combinations(range(len(both)), len(b))]
print("difference", round(diff, 1), "years, two-sided p", round(np.mean(np.abs(null) >= abs(diff)), 3))

Work it outThe two sites differ by , with a p of . From the slips, the head's mean error in this room is , and guessing the room's most common age misses by .

Report

  1. The question, and the hypothesis as you wrote it before recording.
  2. Methods: the sites, the runs, the windows kept and left out, and the block permutation test.
  3. Results: each run's mean and spread, the difference between the sites with its p, and the room's errors against the room's most common age.
  4. Interpretation: what the any-site claim predicts, why estimates sit near the training mean, and what the published evaluation already says about this head.
  5. Limitations: one person at two sites, contact and blinks that differ between sites, estimates printed in whole years, and windows that aren't independent.
  6. Your code, as an appendix.

Problems

  1. What do the encoder, the embedding and the head each do here, and where does each run?

  2. The evaluation leaves out whole studies, not people. Why?

  3. Why test the sites on blocks of five windows rather than on single windows?

  4. Why do the estimates cluster near the training studies' mean age, whoever wears it?

Sources

IntoMind (2026). Heads for encoder e2f9b60f411f0e73. github.com/intomind/eeg-foundation-model-heads.

Mitchell, M., and others (2019). Model cards for model reporting. Proceedings of the Conference on Fairness, Accountability, and Transparency.

Lab 3 · Graduate

Age Detector

In a room of people close in age, how much of the age head's error is bias toward its training mean and how much scatter, does its estimate depend on where the device sits, and what would it take to show that it doesn't?

The demo, exactly

PartWhat it doesSource
The headThe open age head, built into the device's model and selected from power on, in slot 0. Fitted on 183,642 windows from 3,742 people in 93 studies.github.com/intomind/eeg-foundation-model-heads
An estimateOne for every four-second window, a new one every four seconds, computed on the device from the window's embedding.the device's model
The numberThe mean of the estimates so far, leaving out any window with a gap in the signal, shown with ± 9 years, the published error of a person's averaged windows.age-detector/main.js, lib/openhead.js
The programTwo minutes of the same head: every window's estimate in whole years, the running mean, flagged windows marked and left out, then the published errors.python/age.py, python/shipped_head.py

What it leaves out: any calibration to the people in front of it. A least-squares head on a weak signal predicts toward its training mean, so a room younger than that mean is predicted older, by the same pull for everyone. The published error is an average over studies, not this room's. Consecutive windows overlap in what they describe, so thirty windows are fewer than thirty independent estimates.

Preregister

Fill it in before the lab, and change nothing after the first run. The report names every deviation.

ItemYour plan, before any data
The two sites, and why
Hypotheses: the site difference, the room's bias, the head against the room's median
The equivalence margin for "any site", and why that size
Exclusions: flagged windows, contact, movement
Tests, and what would count against each hypothesis

Get ready

You need

  • An IntoMind One, charged, with its cable unplugged
  • A computer with Chrome or Edge, Python 3 with the intomind package and SciPy, and the demos' source
  • Slips of paper, and the two boxes
  • A clean microfiber, soft cotton or eyeglass cloth

Roles

Wearer
Wears the IntoMind One and sits still, eyes open, during each run.
Operator
Runs the demo and the program, and saves each run.
Analyst
Keeps the sheet, and notes movement and anything that disturbs the contact.

Rotate, so everyone who wants to is the wearer once.

Rules

  • Unplug the cable before anyone puts it on.
  • Wearing it is your choice. Every role is a real one.
  • Your age and your estimate are yours. Nobody has to share either.
  • Wipe the electrodes between wearers with the soft cloth, since a rough one can scratch their gold coating.

Procedure

  1. Put it on at the first site

    Two sites far apart test the claim best, such as Oz at the back and Fpz on the forehead. Unplug the cable, part the hair under each electrode, and press it down until it feels firm but not tight.

  2. Check it on the demo

    Open the Age Detector demo and connect. Watch the estimate for a minute while the wearer sits still with the eyes open, then close the tab: the IntoMind One talks to one program at a time.

    You should seeA number that jumps at first and then settles, with ± 9 years and the count of windows under it.

  3. Run it at the first site

    cd python
    python3 -u age.py | tee w1-site1.txt

    Two minutes, eyes open, sitting still, and everything it prints kept in a file named for the wearer and the site.

    You should seeA line for every window, about thirty, with its estimate and the mean so far, and the published errors at the end.

  4. Run it at the second site

    Move the IntoMind One to the second site, press it down, and run it again into w1-site2.txt. Then the next wearer, with w2, and so on.

  5. Your errors, privately

    On a slip with no name, write two numbers: your final mean estimate minus your age, and the room's median age minus your age. Put it in the second box only if you want to.

    WearerSiteSaved asWindows usedNotes
    1w1-site1.txt
    1w1-site2.txt
    2w2-site1.txt
    2w2-site2.txt
    3w3-site1.txt
    3w3-site2.txt

Analyses

For each wearer, privately: the spread of the window estimates, how much consecutive windows agree, and how many independent windows that leaves. Then the two sites: their difference, tested by permuting blocks of five windows, and whether it is shown to lie inside a margin, by an equivalence test of two one-sided tests (Lakens, 2017). Then the room, from the slips: the head's bias and scatter, against the room's median age.

import re
from itertools import combinations
import numpy as np
from scipy import stats

def estimates(path):
    """Each window's estimate from a saved run of age.py, in order, flagged windows left out."""
    found = (re.match(r"window \d+: (\d+) years", line) for line in open(path)
             if "kept out" not in line)
    return np.array([float(m.group(1)) for m in found if m])

def describe(x):
    """Mean, spread, lag-one autocorrelation, and the windows' worth of independent evidence."""
    r = np.corrcoef(x[:-1], x[1:])[0, 1]
    n_eff = len(x) * (1 - r) / (1 + r)
    return x.mean(), x.std(ddof=1), r, n_eff, x.std(ddof=1) / np.sqrt(n_eff)

def blocks(x, size=5):
    n = len(x) // size
    return x[:n * size].reshape(n, size).mean(axis=1)

site1, site2 = estimates("w1-site1.txt"), estimates("w1-site2.txt")   # the runs you saved
for name, x in (("site 1", site1), ("site 2", site2)):
    m, sd, r, n_eff, se = describe(x)
    print(f"{name}: {len(x)} windows, mean {m:.1f}, sd {sd:.1f}, lag-one r {r:.2f}, "
          f"worth {n_eff:.0f} independent windows, standard error {se:.1f}")

# The difference between sites, by permuting blocks of five windows.
a, b = blocks(site1), blocks(site2)
diff = b.mean() - a.mean()
both = np.r_[a, b]
null = np.array([both[list(c)].mean() - np.delete(both, list(c)).mean()
                 for c in combinations(range(len(both)), len(b))])
print(f"difference {diff:+.1f} years, two-sided p {np.mean(np.abs(null) >= abs(diff)):.3f}")

# Equivalence: two one-sided tests on the blocks, that the difference is inside 3 years.
margin = 3.0
p_low = stats.ttest_ind(b + margin, a, alternative="greater").pvalue
p_high = stats.ttest_ind(b - margin, a, alternative="less").pvalue
print(f"inside ±{margin:.0f} years: p = {max(p_low, p_high):.3f}")

# The room, from the slips: each wearer's estimate minus their age, and the room's median age
# minus their age, written side by side with no name.
head = np.array([7, 12, 3, 9, 15, 6, 10, -2, 8, 11])
median = np.array([2, -1, 0, 3, 1, -3, 0, -5, 1, 2])
print(f"the head: bias {head.mean():+.1f} years, scatter {head.std(ddof=1):.1f}, "
      f"mean error {np.abs(head).mean():.1f}")
print(f"the room's median age: mean error {np.abs(median).mean():.1f}, "
      f"paired p {stats.wilcoxon(np.abs(head), np.abs(median)).pvalue:.3f}")

Then report:

  1. Each wearer's site difference, with its p and its equivalence test, and what the two together say about "any site".
  2. The class's site differences together, and how many wearers and windows an equivalence test at your margin would need.
  3. The room's bias and scatter, the head against the room's median, and what the bias says about the head's training mean.
  4. What test of "any site" the published evaluation would need, and whether it has one.

Open problems

  1. Any site, tested. A claim that a head reads any site needs the same people scored at several sites, on studies no part of the model saw, compared site by site against an equivalence margin set in advance. The published evaluation scored nine montages and reports their mean, so that comparison is still to be made.
  2. What age is in the EEG. The aperiodic exponent, alpha's frequency and its power all change with age, and how much of a head's skill is any one of them is not known.
  3. The gap as a marker. Whether the gap between predicted and actual age says anything about a person's health, beyond the model's own bias, is debated (Butler and others, 2021).

Report

  1. The preregistration as written, and every deviation from it, each with its reason.
  2. Methods: the sites, the runs, the windows left out and why, the tests and the equivalence margin.
  3. Results: the site comparison wearer by wearer and for the class, then the room's bias and scatter against its median.
  4. What the published evaluation does and doesn't support, and what a test of "any site" would need.
  5. The code, and no one's age or estimate beyond what they put in the box.

Sources

Lakens, D. (2017). Equivalence tests: a practical primer for t tests, correlations, and meta-analyses. Social Psychological and Personality Science.

Smith, S. M., Vidaurre, D., Alfaro-Almagro, F., Nichols, T. E., and Miller, K. L. (2019). Estimation of brain age delta from brain imaging. NeuroImage.

Butler, E. R., and others (2021). Pitfalls in brain age analyses. Human Brain Mapping.

Engemann, D. A., and others (2022). A reusable benchmark of brain-age prediction from M/EEG resting-state signals. NeuroImage.

IntoMind (2026). Heads for encoder e2f9b60f411f0e73. github.com/intomind/eeg-foundation-model-heads.