Prior Observation Detector-CCC Test Kits Available
The Prior Observation Detector is a plug and play box that houses the experimental apparatus necessary to run tests of the consciousness causes collapse interpretation of quantum mechanics utilizing subliminal priming methodology. The apparatus can also be used as a functional detector of prior conscious observation. This is fundamentally the same experimental protocol that was used in the four previously published experiments (Lucido, 2023, 2024, 2025). The box contains a Geiger counter that measures a local and private source of radioactive decay that is automatically processed within the system and converted into subliminal primes. All of the processing is done inside of the box. If you do not already have a device but want to obtain one please send a request to [email protected]
What Makes a Prior Observation Detector Possible?
In the orthodox interpretation of quantum mechanics, quantum phenomena remain in a state of superposition until the act of measurement, which then collapses the wavefunction into a specific state. One of the many alternatives to this interpretation is the notion that collapse does not occur at the point in which quantum phenomena interact with a physical measurement device (such as a Geiger counter) but only at the point where the outcome of that measurement interacts with a conscious observer. This gap between the measurement device and the conscious observation of its output can be exploited to create a means of detecting prior observation. Specifically, this gap allows for macro level superpositions to be created, the effects of which can be measured by leveraging subliminal priming methodologies from cognitive psychology. For more information visit: testingtheccc.com.
Using The Prior Observation Detector
If shipped within the United States, a sample of uranium ore will arrive in its own container inside the box. Please remove the ore from the container and place it at the location marked with an “x”. Please follow safety instructions listed on the uranium ore container. I regret that I cannot send a uranium ore sample to researchers outside of the United States due to legal prohibitions on shipping even small quantities of radioactive material. It is also important to note the following. The sound on the Geiger Counter is set to off and it needs to stay this way. A covering has been placed over the light indicator, please do not remove it. Lastly, please make sure the lid is on the box while the experiment is running, and that the room is empty while the quantum data are being generated.
This device requires a standalone USB Keyboard and a standalone monitor (not a laptop). Connect your keyboard to the Raspberry Pi processer in the box via USB, connect your monitor to the Raspberry Pi with an HMDI cord, and then connect the Raspberry Pi to a power source (either a battery or a wall outlet) through the micro USB port. The thumb drive must be inserted into the Raspberry Pi for the device to work. The experimental program should automatically start running after about 10-20 seconds. Just follow the instructions on your screen.
Your prior observation detector works by analyzing the results from a cognitive psychology task. The detector is set to collect data in blocks of 60 trials each. Each of the trials contain a subliminal prime, a number that is presented for a period of time too short to be consciously experienced, followed by a number that the participant will be asked to rapidly respond to. The 60 trials are a combination of 30 Category A trials and 30 Category B trials. The Category A trials contain subliminal primes that are always shielded from conscious observation. The category B trials contain primes that can either be observed or not. The choice is left to the operator. Previous research indicates that unobserved primes are significantly less effective at influencing participant response times than primes that have been subjected to deliberate prior observation (Aggregated CCC Results). Based on the reaction times of the user, the program will provide a score that can be used to make a prediction regarding whether or not the primes were observed by the operator before the start of the reaction time task.
Interpreting The Score
Each time the game is played the user obtains a score. The score is the mean congruent vs. incongruent difference for trials whose primes were chosen to be observed or not by the operator (Category B) minus the mean congruent vs. incongruent difference within trials whose primes remained completely unobserved (Category A). It is organized in the same way as previous evaluations of the CCC using subliminal priming (testingtheccc.com). The higher the score, the greater the difference between the two conditions, which is what would be expected if the Category B primes were previously observed. In other words, on average, higher scores should be produced when the Category B primes were observed and lower scores would be produced when they remained unobserved.
Proposed Classification System for Scores:
21 or higher: the primes were likely Observed
14 to 20: too close to tell…try again
13 or less (including negative numbers): the primes were likely Unobserved
Please note that a single game is too small a sample for the score to be reliable. Accuracy would be greatly increased by aggregating the data over multiple trials. This can be done by playing the game multiple times and making the same decision to either observe or not observe the primes and then placing the mean score from those games within the classification ranges provided (i.e., using a rolling average). Or, alternatively, playing the game 4 or 6 times and choosing for half of those games to observe and the other half to not observe, The mean score of your “observed” games should be higher than the mean score of your “unobserved” games. The data for each game is made available as a CSV file to allow for maximum freedom in data analysis. Specifically, by column listed are the participant identifier, session number, trial number, timestamp, category of prime, the prime, the stimulus number, congruency, participant response, correctness of response, response times, and observation status for category B primes. The CSV file is located on the flash drive in the box.
Using The Prior Observation Detector To Test The CCC
Although tests of prior observation are also tests of the CCC, the focus on detection of prior observation could also be completely removed from the protocol. A user could choose to use this apparatus to focus more directly on testing the Consciousness Causes Collapse (CCC) interpretation of quantum mechanics. To use this detector to collect data as a means of testing the CCC, simply choose to repeat this test multiple times with multiple participants (being careful not to have any one participant play more than four times) and always choose to observe the primes. Doing so will ensure that the category B primes will constitute the “observed condition” which can then be compared to the category A primes which will be the “unobserved condition“. Please note that the person observing the primes does not need to be the one who plays the game. Please see the following link for more information testingtheccc.com
Important Note
When collecting data, limit the number of games that any one individual plays to no more than four games or 250 trials. There is likely perceptual learning that is occurring when a person repeats several hundred trials. This learning will likely diminish the results obtained. To avoid this, simply rotate subjects. For more information please see: https://www.testingtheccc.com/experimental-procedures.html
How To Obtain The Device
If you do not already have a device but are interested in obtaining one please send an email request to [email protected] At the present time I have the means to distribute several devices at no cost to those with interest in either potentially completing a scientific study, or otherwise publishing or posting the results they obtain, especially if they resolve to pass the device on to another interested party when they have finished using it.
The materials, packing, and shipping needed to produce and distribute each device total about 200 U.S. dollars. At present this distribution project is 100% self-funded. However, individuals interested in paying it forward can choose to donate all or part of the cost of the device they received on this website. This will help make the device free for the next person. However, taking the device in no way obligates you to make any future donation.
What Makes a Prior Observation Detector Possible?
In the orthodox interpretation of quantum mechanics, quantum phenomena remain in a state of superposition until the act of measurement, which then collapses the wavefunction into a specific state. One of the many alternatives to this interpretation is the notion that collapse does not occur at the point in which quantum phenomena interact with a physical measurement device (such as a Geiger counter) but only at the point where the outcome of that measurement interacts with a conscious observer. This gap between the measurement device and the conscious observation of its output can be exploited to create a means of detecting prior observation. Specifically, this gap allows for macro level superpositions to be created, the effects of which can be measured by leveraging subliminal priming methodologies from cognitive psychology. For more information visit: testingtheccc.com.
Using The Prior Observation Detector
If shipped within the United States, a sample of uranium ore will arrive in its own container inside the box. Please remove the ore from the container and place it at the location marked with an “x”. Please follow safety instructions listed on the uranium ore container. I regret that I cannot send a uranium ore sample to researchers outside of the United States due to legal prohibitions on shipping even small quantities of radioactive material. It is also important to note the following. The sound on the Geiger Counter is set to off and it needs to stay this way. A covering has been placed over the light indicator, please do not remove it. Lastly, please make sure the lid is on the box while the experiment is running, and that the room is empty while the quantum data are being generated.
This device requires a standalone USB Keyboard and a standalone monitor (not a laptop). Connect your keyboard to the Raspberry Pi processer in the box via USB, connect your monitor to the Raspberry Pi with an HMDI cord, and then connect the Raspberry Pi to a power source (either a battery or a wall outlet) through the micro USB port. The thumb drive must be inserted into the Raspberry Pi for the device to work. The experimental program should automatically start running after about 10-20 seconds. Just follow the instructions on your screen.
Your prior observation detector works by analyzing the results from a cognitive psychology task. The detector is set to collect data in blocks of 60 trials each. Each of the trials contain a subliminal prime, a number that is presented for a period of time too short to be consciously experienced, followed by a number that the participant will be asked to rapidly respond to. The 60 trials are a combination of 30 Category A trials and 30 Category B trials. The Category A trials contain subliminal primes that are always shielded from conscious observation. The category B trials contain primes that can either be observed or not. The choice is left to the operator. Previous research indicates that unobserved primes are significantly less effective at influencing participant response times than primes that have been subjected to deliberate prior observation (Aggregated CCC Results). Based on the reaction times of the user, the program will provide a score that can be used to make a prediction regarding whether or not the primes were observed by the operator before the start of the reaction time task.
Interpreting The Score
Each time the game is played the user obtains a score. The score is the mean congruent vs. incongruent difference for trials whose primes were chosen to be observed or not by the operator (Category B) minus the mean congruent vs. incongruent difference within trials whose primes remained completely unobserved (Category A). It is organized in the same way as previous evaluations of the CCC using subliminal priming (testingtheccc.com). The higher the score, the greater the difference between the two conditions, which is what would be expected if the Category B primes were previously observed. In other words, on average, higher scores should be produced when the Category B primes were observed and lower scores would be produced when they remained unobserved.
Proposed Classification System for Scores:
21 or higher: the primes were likely Observed
14 to 20: too close to tell…try again
13 or less (including negative numbers): the primes were likely Unobserved
Please note that a single game is too small a sample for the score to be reliable. Accuracy would be greatly increased by aggregating the data over multiple trials. This can be done by playing the game multiple times and making the same decision to either observe or not observe the primes and then placing the mean score from those games within the classification ranges provided (i.e., using a rolling average). Or, alternatively, playing the game 4 or 6 times and choosing for half of those games to observe and the other half to not observe, The mean score of your “observed” games should be higher than the mean score of your “unobserved” games. The data for each game is made available as a CSV file to allow for maximum freedom in data analysis. Specifically, by column listed are the participant identifier, session number, trial number, timestamp, category of prime, the prime, the stimulus number, congruency, participant response, correctness of response, response times, and observation status for category B primes. The CSV file is located on the flash drive in the box.
Using The Prior Observation Detector To Test The CCC
Although tests of prior observation are also tests of the CCC, the focus on detection of prior observation could also be completely removed from the protocol. A user could choose to use this apparatus to focus more directly on testing the Consciousness Causes Collapse (CCC) interpretation of quantum mechanics. To use this detector to collect data as a means of testing the CCC, simply choose to repeat this test multiple times with multiple participants (being careful not to have any one participant play more than four times) and always choose to observe the primes. Doing so will ensure that the category B primes will constitute the “observed condition” which can then be compared to the category A primes which will be the “unobserved condition“. Please note that the person observing the primes does not need to be the one who plays the game. Please see the following link for more information testingtheccc.com
Important Note
When collecting data, limit the number of games that any one individual plays to no more than four games or 250 trials. There is likely perceptual learning that is occurring when a person repeats several hundred trials. This learning will likely diminish the results obtained. To avoid this, simply rotate subjects. For more information please see: https://www.testingtheccc.com/experimental-procedures.html
How To Obtain The Device
If you do not already have a device but are interested in obtaining one please send an email request to [email protected] At the present time I have the means to distribute several devices at no cost to those with interest in either potentially completing a scientific study, or otherwise publishing or posting the results they obtain, especially if they resolve to pass the device on to another interested party when they have finished using it.
The materials, packing, and shipping needed to produce and distribute each device total about 200 U.S. dollars. At present this distribution project is 100% self-funded. However, individuals interested in paying it forward can choose to donate all or part of the cost of the device they received on this website. This will help make the device free for the next person. However, taking the device in no way obligates you to make any future donation.
Technical Details
Primary Hardware & Materials:
Gravity: Geiger Counter Module Ionizing Radiation Detector Gravity: Geiger Counter Module Ionizing Radiation Detector Wiki - DFRobot
Elegoo UNO R3 Amazon.com: ELEGOO UNO R3 Board ATmega328P with USB Cable(Arduino-Compatible) for Arduino : Electronics
Raspberry Pi 3 Amazon.com: New Raspberry Pi 3 Model B+ Board (3B+) Raspberry PI 3B+ (1GB) (3B Plus) : Electronics
Uranium Ore Small Uraninite Mesa County Colorado Cloud Chamber Source Radioactive Element Uranium Ore Geiger Check Source for Nuclear Radiation Gamma Alpha Beta Radium: Amazon.com: Industrial & Scientific
The GND on Elegoo Uno connects to the GND on the Geiger counter. The 5V on Elegoo connects to the 5V on the Geiger counter, and the VIN on the Geiger counter to the D2 on Elegoo. A USB cord connects the Elegoo to the Raspberry Pi. To use you must first connect a keyboard to the Raspberry Pi via USB, connect the monitor to the Raspberry Pi with an HMDI cord, and then connect the Raspberry Pi to a power source (either a battery or a wall outlet) through the micro USB port. The cords are all provided and labeled. The thumb drive also needs to be inserted into the Raspberry Pi or the program will not run. Lastly, the uranium ore would need to be placed at the location marked with an X adjacent to the Geiger counter.
Experimental Protocol:
The number of Geiger counter clicks during a four second interval of time determines the primes in every trial. Zero clicks yield a prime of one, one click yields a prime of two, two clicks yield a prime of three and so on, with the pattern repeating where eight clicks again yield a prime of one and nine clicks yields a prime of two and so on. Each experimental block is comprised of 30 trials with Category A Primes (always unobserved) and 30 trials with Category B Primes (primes that may be observed at the operator’s choice). The primes are randomly distributed based on a classical randomizing function within the program. For each trial both the forward and the backwards masks were randomly drawn from a pool of 42 different series of nonsense letters and symbols. The program does not allow for the same forward and backwards mask to be used for any one trial. This increase in the complexity and the variability of the mask is a change from previous versions of this protocol. Each items starts with a forward mask of nonsense symbols that remain on the screen for a duration of 167 milliseconds. This is followed by the prime that remains on the screen for 50 milliseconds. The prime is immediately followed by a backwards mask that remains on the screen for 33 milliseconds. After that the stimulus number is presented and remains on the screen for 800 milliseconds. There is a 1,200 millisecond pause in-between items. There is a response floor of 250 milliseconds and a response ceiling of 800 milliseconds for each item. Incorrect responses will not be counted, nor will responses that fall outside of the response window. Data is outputted to a CSV file. The experimental code is listed below if any changes are desired.
Code:
Arudino Code **************************************************************
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/* =========================
OLED CONFIGURATION
========================= */
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
/* =========================
GEIGER CONFIGURATION
========================= */
#define GEIGER_PIN 2 // Gravity Geiger signal pin
volatile unsigned long clickCount = 0;
unsigned long lastIntervalTime = 0;
const unsigned long INTERVAL_MS = 4000; // 4 seconds
/* =========================
INTERRUPT HANDLER
========================= */
void geigerISR() {
clickCount++;
}
/* =========================
SETUP
========================= */
void setup() {
Serial.begin(9600);
pinMode(GEIGER_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(GEIGER_PIN), geigerISR, FALLING);
Wire.begin();
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
while (true); // Halt if OLED fails
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("CCC DEVICE READY");
display.println("");
display.println("Awaiting primes...");
display.display();
lastIntervalTime = millis();
}
/* =========================
LOOP
========================= */
void loop() {
unsigned long currentTime = millis();
if (currentTime - lastIntervalTime >= INTERVAL_MS) {
// Copy & reset count safely
noInterrupts();
unsigned long count = clickCount;
clickCount = 0;
interrupts();
// Output ONLY ONE number every 4s
Serial.println(count);
// Prime mapping (1–8)
int prime = (count % 8) + 1;
display.clearDisplay();
display.setCursor(0, 0);
display.println("Quantum Output");
display.println("");
display.print("Clicks: ");
display.println(count);
display.print("Prime: ");
display.println(prime);
display.display();
Experimental Code******************************************************************
import pygame
import random
import csv
import os
import sys
from datetime import datetime
from geiger_input import GeigerPrimeSource
# --------------------------
# CONFIG
# --------------------------
NUM_PRIMES = 30
STIMULI_NUMBERS = list(range(1, 9))
OBS_WINDOW_MS = 24000
INTER_TRIAL_INTERVAL = 1200
# (Your updated MASKS list goes here)
MASKS = [
"@X&#G","TNVWP","#$%YB","!BASG#","EP$X@","XG@#&","WHG##","Q@#♣K",
"&VK%X","$CXPQ","UJ@#@","$sTQ#\\", "I[I]P[","I#$QW","//SA//","#$&@D",
"D?S?Y!","!A[[|","@∏flG","◊OWNP","#Y♀B","!ąfflS","$X@", "∏Ω∑@","‰À≤◊W",
"QX∑¿ÐK","∏flËØ","$PAQ","zU#@","$Q#\\","IM[!","IQW","/////", "≠∏flË",
"D?᥉!","[|▲◊●","≠∏flË","ÂDπòû!","[fi♠♪♣|","չÔğȶᄊ","$PAQ","zU#@","$Q#\\",
"II][!","IQpW","/©÷ë†/","CVBDË","ąER∏!","[¥flË","ÂBBD","₩₡֎‼"
]
RESPONSE_KEYS = {'e': 'even', 'o': 'odd'}
RESPONSE_WINDOW = (250, 800)
# --------------------------
# ROBUST USB DATA PATH (RESTORED FROM OLD CODE)
# --------------------------
def find_usb():
# This is the strict logic from your working code
base = "/media"
if os.path.exists(base):
for user in os.listdir(base):
path = os.path.join(base, user)
if os.path.isdir(path):
for dev in os.listdir(path):
full_path = os.path.join(path, dev)
return full_path
return None
# FIND USB OR STOP
usb_path = find_usb()
if usb_path is None:
# If we can't find the USB, we stop immediately so we don't save to the wrong place.
# Since we are in a box without a console, we init pygame just to show the error.
pygame.init()
screen = pygame.display.set_mode((800, 600))
font_err = pygame.font.SysFont("Arial", 40)
screen.fill((0,0,0))
label = font_err.render("NO USB DETECTED", True, (255, 0, 0))
screen.blit(label, (50, 250))
label2 = font_err.render("Insert USB and Restart", True, (255, 255, 255))
screen.blit(label2, (50, 320))
pygame.display.flip()
pygame.time.delay(5000)
sys.exit()
csv_path = os.path.join(usb_path, "ccc_data.csv")
# --------------------------
# PYGAME INIT
# --------------------------
pygame.init()
# ... (Your Font and Screen setup logic here) ...
pygame.init()
# ... (Your Font and Screen setup logic here) ...
FONTS = ["dejavuserif", "timesnewroman", "couriernew", "liberationmono", "bookmanoldstyle", "liberationsans", "freemono"]
FONT_SIZE = int(32 * 1.15)
SESSION_FONT_NAME = random.choice(FONTS)
SESSION_FONT_PATH = pygame.font.match_font(SESSION_FONT_NAME)
font = pygame.font.Font(SESSION_FONT_PATH, FONT_SIZE) if SESSION_FONT_PATH else pygame.font.SysFont("Arial", FONT_SIZE)
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("CCC Experiment")
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# --------------------------
# HELPER FUNCTIONS
# --------------------------
# (Keep your draw_wrapped, draw_centered, wait_space, get_input functions here)
def draw_wrapped(text):
screen.fill(BLACK)
paragraphs = text.split("\n")
final_lines = []
for para in paragraphs:
words = para.split(" ")
line = ""
for word in words:
test = line + word + " "
if font.size(test)[0] < 700:
line = test
else:
final_lines.append(line)
line = word + " "
final_lines.append(line)
y = 80
for l in final_lines:
if l.strip():
surf = font.render(l, True, WHITE)
screen.blit(surf, (50, y))
y += 45
pygame.display.flip()
def draw_centered(text):
screen.fill(BLACK)
surf = font.render(text, True, WHITE)
rect = surf.get_rect(center=(400, 300))
screen.blit(surf, rect)
pygame.display.flip()
def wait_space(text):
draw_wrapped(text)
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT: sys.exit()
if e.type == pygame.KEYDOWN and e.key == pygame.K_SPACE: return
def get_input(prompt):
text = ""
while True:
draw_wrapped(prompt + "\n" + text)
for e in pygame.event.get():
if e.type == pygame.QUIT: sys.exit()
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_RETURN: return text
elif e.key == pygame.K_BACKSPACE: text = text[:-1]
else: text += e.unicode
# --------------------------
# EXPERIMENT FLOW
# --------------------------
wait_space('Are you ready to play a metaphysical game? Press SPACE to continue.')
pid = get_input('Enter Participant ID, then press ENTER')
session = get_input('Enter Session Number, then press ENTER')
# --- INITIALIZE CSV IMMEDIATELY ---
# This ensures headers exist before the game starts
headers = ["Participant","Session","Trial","Timestamp","Category","Prime","Stimulus","Congruency","Response","RT","Accuracy","Condition"]
try:
write_header = not os.path.exists(csv_path) or os.path.getsize(csv_path) == 0
with open(csv_path, "a", newline="") as f:
w = csv.writer(f)
if write_header:
w.writerow(headers)
# FORCE DISK WRITE
f.flush()
os.fsync(f.fileno())
except Exception as e:
# If this fails, the USB might be read-only
draw_wrapped(f"ERROR WRITING TO USB:\n{e}\n\nCheck drive and restart.")
pygame.time.delay(5000)
sys.exit()
source = GeigerPrimeSource()
draw_wrapped('Please make sure the box is closed and leave the room while quantum measurements are taken. You can return in 4 minutes.')
A = [source.read_prime() for _ in range(NUM_PRIMES)]
B = [source.read_prime() for _ in range(NUM_PRIMES)]
wait_space('Measurements are complete. I will ask if you want to make an observation, then we will play a 2 minute game. From your results we will predict if the observation was made. Press SPACE to continue.')
# --- OBSERVATION PHASE ---
draw_wrapped('Do you want to observe the numbers? Press Y for Yes or N for No.')
observe_key = None
while observe_key not in ['y', 'n']:
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_y: observe_key = 'y'
elif e.key == pygame.K_n: observe_key = 'n'
if observe_key == 'y':
primes_text = ' '.join(str(p) for p in B)
draw_wrapped(f'Category B primes: {primes_text}')
pygame.time.delay(20000)
# --- PRACTICE ---
wait_space('Practice trials are about to begin. You will see a series of numbers. Please respond to each number by pressing the E key for even or the O key for odd. Go as fast as you can without making mistakes. Press SPACE to start.')
# (Insert your practice loop here - abbreviated for clarity)
for stim in [6, 7, 4, 1]:
draw_centered(random.choice(MASKS))
pygame.time.delay(250)
draw_centered(str(stim))
pygame.time.delay(800)
wait_space('Now we will play for real. Press SPACE to continue.')
# --------------------------
# MAIN TRIALS (WITH CONTINUOUS SAVING)
# --------------------------
trials = [(p, 'A') for p in A] + [(p, 'B') for p in B]
random.shuffle(trials)
rows = []
for tnum, (prime, cat) in enumerate(trials, 1):
stim = random.choice(STIMULI_NUMBERS)
timestamp = datetime.now().isoformat()
# --- STIMULUS DISPLAY ---
draw_centered(random.choice(MASKS))
pygame.time.delay(167)
draw_centered(str(prime))
pygame.time.delay(50)
draw_centered(random.choice(MASKS))
pygame.time.delay(33)
draw_centered(str(stim))
# --- RESPONSE ---
start_rt = pygame.time.get_ticks()
key, rt = None, None
while pygame.time.get_ticks() - start_rt < 800:
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_e: key = 'e'
elif e.key == pygame.K_o: key = 'o'
if key:
rt = pygame.time.get_ticks() - start_rt
break
if key: break
# --- DATA LOGIC ---
correct_key = 'e' if stim % 2 == 0 else 'o'
accuracy = "correct" if (key == correct_key) else "incorrect"
final_rt = rt if (accuracy == "correct" and rt and rt >= 250) else ""
condition = "observed" if (cat == 'B' and observe_key == 'y') else "unobserved"
row_data = [
pid, session, tnum, timestamp, cat, prime, stim,
"congruent" if prime % 2 == stim % 2 else "incongruent",
key if key else "None",
final_rt, accuracy, condition
]
rows.append(row_data)
# --- SAVE IMMEDIATELY ---
try:
with open(csv_path, "a", newline="") as f:
w = csv.writer(f)
w.writerow(row_data)
f.flush()
os.fsync(f.fileno())
except Exception as e:
print(f"Write error: {e}")
screen.fill(BLACK)
pygame.display.flip()
pygame.time.delay(INTER_TRIAL_INTERVAL)
# --------------------------
# SCORING & FINAL SCREEN
# --------------------------
def get_condition_mean(data, category, congruency):
"""
Calculates mean RT for a specific Category (A/B) and Congruency (congruent/incongruent).
Filters out invalid RTs (empty strings or None).
"""
# Index 4 is Category, Index 7 is Congruency, Index 9 is RT
valid_rts = [
row[9] for row in data
if row[4] == category
and row[7] == congruency
and isinstance(row[9], (int, float))
]
# Avoid division by zero if a participant gets everything wrong in one category
if not valid_rts:
return 0
return sum(valid_rts) / len(valid_rts)
# Calculate the four specific means
mean_a_con = get_condition_mean(rows, 'A', 'congruent')
mean_a_inc = get_condition_mean(rows, 'A', 'incongruent')
mean_b_con = get_condition_mean(rows, 'B', 'congruent')
mean_b_inc = get_condition_mean(rows, 'B', 'incongruent')
# Calculate the priming effects (Incongruent - Congruent)
diff_a = mean_a_inc - mean_a_con
diff_b = mean_b_inc - mean_b_con
# Final Score: Category B Difference - Category A Difference
score = diff_b - diff_a
# --------------------------
# FINAL SCREENS
# --------------------------
if score >= 21:
interpretation = ' The numbers were likely OBSERVED.'
elif 14 <= score <= 20:
interpretation = ' too close to tell. Try again.'
else:
interpretation = ' The numbers were likely UNOBSERVED.'
# --- Screen 1: Score & Interpretation ---
screen_1_text = (
f"Your Score: {round(score, 2)}\n\n"
f"{interpretation}\n\n"
"To increase accuracy, play again and make the same choice to observe or not. "
"Then average scores across games. Averaging three or more games greatly increases detection accuracy.\n\n"
"Press SPACE to continue."
)
wait_space(screen_1_text)
# --- Screen 2: Scoring Details ---
screen_2_text = (
"SCORING GUIDE:\n\n"
"The higher the score, the more likely the numbers were observed.\n\n"
"* Scores higher than 15 are rated as likely OBSERVED.\n\n"
"* Scores of 7 or lower are rated as likely UNOBSERVED.\n\n"
"Press SPACE to continue."
)
wait_space(screen_2_text)
# --- Screen 3: Perceptual Learning Warning ---
screen_3_text = (
"IMPORTANT NOTE:\n\n"
"Please note that after a person plays about 4 games, the accuracy of the detector "
"may decrease due to 'perceptual learning'.\n\n"
"To avoid this, set a 4 game limit per individual. The effects of perceptual learning may fade over time.\n\n"
"Press SPACE to continue."
)
wait_space(screen_3_text)
# --- Screen 4: Thank You & Link ---
screen_4_text = (
"Thank you for playing.\n\n"
"More information about this prior observation detector and how this protocol tests "
"the 'Consciousness Causes Collapse' interpretation of quantum mechanics can be found at:\n\n"
"testingtheccc.com\n\n"
"Press SPACE to exit."
)
wait_space(screen_4_text)
pygame.quit()
sys.exit()
SD Card*******************************************************************
The Raspberry Pi-3 SD card contains other code related to the set up and processing of the computer unit itself, such as the location of the files and the AutoStart commands, that are directly related to the experimental protocol. I did not copy it here for the sake of clarity, but it can be accessed physically from the Raspberry Pi unit.
END NOTE
An updated version of this guide will be kept at testingtheccc.com. Please refer back to it or feel free to email [email protected] with specific questions of any kind. Thank you for your interest in this device and in the Consciousness Causes Collapse Interpretation of Quantum Mechanics.
Primary Hardware & Materials:
Gravity: Geiger Counter Module Ionizing Radiation Detector Gravity: Geiger Counter Module Ionizing Radiation Detector Wiki - DFRobot
Elegoo UNO R3 Amazon.com: ELEGOO UNO R3 Board ATmega328P with USB Cable(Arduino-Compatible) for Arduino : Electronics
Raspberry Pi 3 Amazon.com: New Raspberry Pi 3 Model B+ Board (3B+) Raspberry PI 3B+ (1GB) (3B Plus) : Electronics
Uranium Ore Small Uraninite Mesa County Colorado Cloud Chamber Source Radioactive Element Uranium Ore Geiger Check Source for Nuclear Radiation Gamma Alpha Beta Radium: Amazon.com: Industrial & Scientific
The GND on Elegoo Uno connects to the GND on the Geiger counter. The 5V on Elegoo connects to the 5V on the Geiger counter, and the VIN on the Geiger counter to the D2 on Elegoo. A USB cord connects the Elegoo to the Raspberry Pi. To use you must first connect a keyboard to the Raspberry Pi via USB, connect the monitor to the Raspberry Pi with an HMDI cord, and then connect the Raspberry Pi to a power source (either a battery or a wall outlet) through the micro USB port. The cords are all provided and labeled. The thumb drive also needs to be inserted into the Raspberry Pi or the program will not run. Lastly, the uranium ore would need to be placed at the location marked with an X adjacent to the Geiger counter.
Experimental Protocol:
The number of Geiger counter clicks during a four second interval of time determines the primes in every trial. Zero clicks yield a prime of one, one click yields a prime of two, two clicks yield a prime of three and so on, with the pattern repeating where eight clicks again yield a prime of one and nine clicks yields a prime of two and so on. Each experimental block is comprised of 30 trials with Category A Primes (always unobserved) and 30 trials with Category B Primes (primes that may be observed at the operator’s choice). The primes are randomly distributed based on a classical randomizing function within the program. For each trial both the forward and the backwards masks were randomly drawn from a pool of 42 different series of nonsense letters and symbols. The program does not allow for the same forward and backwards mask to be used for any one trial. This increase in the complexity and the variability of the mask is a change from previous versions of this protocol. Each items starts with a forward mask of nonsense symbols that remain on the screen for a duration of 167 milliseconds. This is followed by the prime that remains on the screen for 50 milliseconds. The prime is immediately followed by a backwards mask that remains on the screen for 33 milliseconds. After that the stimulus number is presented and remains on the screen for 800 milliseconds. There is a 1,200 millisecond pause in-between items. There is a response floor of 250 milliseconds and a response ceiling of 800 milliseconds for each item. Incorrect responses will not be counted, nor will responses that fall outside of the response window. Data is outputted to a CSV file. The experimental code is listed below if any changes are desired.
Code:
Arudino Code **************************************************************
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/* =========================
OLED CONFIGURATION
========================= */
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
/* =========================
GEIGER CONFIGURATION
========================= */
#define GEIGER_PIN 2 // Gravity Geiger signal pin
volatile unsigned long clickCount = 0;
unsigned long lastIntervalTime = 0;
const unsigned long INTERVAL_MS = 4000; // 4 seconds
/* =========================
INTERRUPT HANDLER
========================= */
void geigerISR() {
clickCount++;
}
/* =========================
SETUP
========================= */
void setup() {
Serial.begin(9600);
pinMode(GEIGER_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(GEIGER_PIN), geigerISR, FALLING);
Wire.begin();
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
while (true); // Halt if OLED fails
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("CCC DEVICE READY");
display.println("");
display.println("Awaiting primes...");
display.display();
lastIntervalTime = millis();
}
/* =========================
LOOP
========================= */
void loop() {
unsigned long currentTime = millis();
if (currentTime - lastIntervalTime >= INTERVAL_MS) {
// Copy & reset count safely
noInterrupts();
unsigned long count = clickCount;
clickCount = 0;
interrupts();
// Output ONLY ONE number every 4s
Serial.println(count);
// Prime mapping (1–8)
int prime = (count % 8) + 1;
display.clearDisplay();
display.setCursor(0, 0);
display.println("Quantum Output");
display.println("");
display.print("Clicks: ");
display.println(count);
display.print("Prime: ");
display.println(prime);
display.display();
Experimental Code******************************************************************
import pygame
import random
import csv
import os
import sys
from datetime import datetime
from geiger_input import GeigerPrimeSource
# --------------------------
# CONFIG
# --------------------------
NUM_PRIMES = 30
STIMULI_NUMBERS = list(range(1, 9))
OBS_WINDOW_MS = 24000
INTER_TRIAL_INTERVAL = 1200
# (Your updated MASKS list goes here)
MASKS = [
"@X&#G","TNVWP","#$%YB","!BASG#","EP$X@","XG@#&","WHG##","Q@#♣K",
"&VK%X","$CXPQ","UJ@#@","$sTQ#\\", "I[I]P[","I#$QW","//SA//","#$&@D",
"D?S?Y!","!A[[|","@∏flG","◊OWNP","#Y♀B","!ąfflS","$X@", "∏Ω∑@","‰À≤◊W",
"QX∑¿ÐK","∏flËØ","$PAQ","zU#@","$Q#\\","IM[!","IQW","/////", "≠∏flË",
"D?᥉!","[|▲◊●","≠∏flË","ÂDπòû!","[fi♠♪♣|","չÔğȶᄊ","$PAQ","zU#@","$Q#\\",
"II][!","IQpW","/©÷ë†/","CVBDË","ąER∏!","[¥flË","ÂBBD","₩₡֎‼"
]
RESPONSE_KEYS = {'e': 'even', 'o': 'odd'}
RESPONSE_WINDOW = (250, 800)
# --------------------------
# ROBUST USB DATA PATH (RESTORED FROM OLD CODE)
# --------------------------
def find_usb():
# This is the strict logic from your working code
base = "/media"
if os.path.exists(base):
for user in os.listdir(base):
path = os.path.join(base, user)
if os.path.isdir(path):
for dev in os.listdir(path):
full_path = os.path.join(path, dev)
return full_path
return None
# FIND USB OR STOP
usb_path = find_usb()
if usb_path is None:
# If we can't find the USB, we stop immediately so we don't save to the wrong place.
# Since we are in a box without a console, we init pygame just to show the error.
pygame.init()
screen = pygame.display.set_mode((800, 600))
font_err = pygame.font.SysFont("Arial", 40)
screen.fill((0,0,0))
label = font_err.render("NO USB DETECTED", True, (255, 0, 0))
screen.blit(label, (50, 250))
label2 = font_err.render("Insert USB and Restart", True, (255, 255, 255))
screen.blit(label2, (50, 320))
pygame.display.flip()
pygame.time.delay(5000)
sys.exit()
csv_path = os.path.join(usb_path, "ccc_data.csv")
# --------------------------
# PYGAME INIT
# --------------------------
pygame.init()
# ... (Your Font and Screen setup logic here) ...
pygame.init()
# ... (Your Font and Screen setup logic here) ...
FONTS = ["dejavuserif", "timesnewroman", "couriernew", "liberationmono", "bookmanoldstyle", "liberationsans", "freemono"]
FONT_SIZE = int(32 * 1.15)
SESSION_FONT_NAME = random.choice(FONTS)
SESSION_FONT_PATH = pygame.font.match_font(SESSION_FONT_NAME)
font = pygame.font.Font(SESSION_FONT_PATH, FONT_SIZE) if SESSION_FONT_PATH else pygame.font.SysFont("Arial", FONT_SIZE)
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("CCC Experiment")
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# --------------------------
# HELPER FUNCTIONS
# --------------------------
# (Keep your draw_wrapped, draw_centered, wait_space, get_input functions here)
def draw_wrapped(text):
screen.fill(BLACK)
paragraphs = text.split("\n")
final_lines = []
for para in paragraphs:
words = para.split(" ")
line = ""
for word in words:
test = line + word + " "
if font.size(test)[0] < 700:
line = test
else:
final_lines.append(line)
line = word + " "
final_lines.append(line)
y = 80
for l in final_lines:
if l.strip():
surf = font.render(l, True, WHITE)
screen.blit(surf, (50, y))
y += 45
pygame.display.flip()
def draw_centered(text):
screen.fill(BLACK)
surf = font.render(text, True, WHITE)
rect = surf.get_rect(center=(400, 300))
screen.blit(surf, rect)
pygame.display.flip()
def wait_space(text):
draw_wrapped(text)
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT: sys.exit()
if e.type == pygame.KEYDOWN and e.key == pygame.K_SPACE: return
def get_input(prompt):
text = ""
while True:
draw_wrapped(prompt + "\n" + text)
for e in pygame.event.get():
if e.type == pygame.QUIT: sys.exit()
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_RETURN: return text
elif e.key == pygame.K_BACKSPACE: text = text[:-1]
else: text += e.unicode
# --------------------------
# EXPERIMENT FLOW
# --------------------------
wait_space('Are you ready to play a metaphysical game? Press SPACE to continue.')
pid = get_input('Enter Participant ID, then press ENTER')
session = get_input('Enter Session Number, then press ENTER')
# --- INITIALIZE CSV IMMEDIATELY ---
# This ensures headers exist before the game starts
headers = ["Participant","Session","Trial","Timestamp","Category","Prime","Stimulus","Congruency","Response","RT","Accuracy","Condition"]
try:
write_header = not os.path.exists(csv_path) or os.path.getsize(csv_path) == 0
with open(csv_path, "a", newline="") as f:
w = csv.writer(f)
if write_header:
w.writerow(headers)
# FORCE DISK WRITE
f.flush()
os.fsync(f.fileno())
except Exception as e:
# If this fails, the USB might be read-only
draw_wrapped(f"ERROR WRITING TO USB:\n{e}\n\nCheck drive and restart.")
pygame.time.delay(5000)
sys.exit()
source = GeigerPrimeSource()
draw_wrapped('Please make sure the box is closed and leave the room while quantum measurements are taken. You can return in 4 minutes.')
A = [source.read_prime() for _ in range(NUM_PRIMES)]
B = [source.read_prime() for _ in range(NUM_PRIMES)]
wait_space('Measurements are complete. I will ask if you want to make an observation, then we will play a 2 minute game. From your results we will predict if the observation was made. Press SPACE to continue.')
# --- OBSERVATION PHASE ---
draw_wrapped('Do you want to observe the numbers? Press Y for Yes or N for No.')
observe_key = None
while observe_key not in ['y', 'n']:
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_y: observe_key = 'y'
elif e.key == pygame.K_n: observe_key = 'n'
if observe_key == 'y':
primes_text = ' '.join(str(p) for p in B)
draw_wrapped(f'Category B primes: {primes_text}')
pygame.time.delay(20000)
# --- PRACTICE ---
wait_space('Practice trials are about to begin. You will see a series of numbers. Please respond to each number by pressing the E key for even or the O key for odd. Go as fast as you can without making mistakes. Press SPACE to start.')
# (Insert your practice loop here - abbreviated for clarity)
for stim in [6, 7, 4, 1]:
draw_centered(random.choice(MASKS))
pygame.time.delay(250)
draw_centered(str(stim))
pygame.time.delay(800)
wait_space('Now we will play for real. Press SPACE to continue.')
# --------------------------
# MAIN TRIALS (WITH CONTINUOUS SAVING)
# --------------------------
trials = [(p, 'A') for p in A] + [(p, 'B') for p in B]
random.shuffle(trials)
rows = []
for tnum, (prime, cat) in enumerate(trials, 1):
stim = random.choice(STIMULI_NUMBERS)
timestamp = datetime.now().isoformat()
# --- STIMULUS DISPLAY ---
draw_centered(random.choice(MASKS))
pygame.time.delay(167)
draw_centered(str(prime))
pygame.time.delay(50)
draw_centered(random.choice(MASKS))
pygame.time.delay(33)
draw_centered(str(stim))
# --- RESPONSE ---
start_rt = pygame.time.get_ticks()
key, rt = None, None
while pygame.time.get_ticks() - start_rt < 800:
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_e: key = 'e'
elif e.key == pygame.K_o: key = 'o'
if key:
rt = pygame.time.get_ticks() - start_rt
break
if key: break
# --- DATA LOGIC ---
correct_key = 'e' if stim % 2 == 0 else 'o'
accuracy = "correct" if (key == correct_key) else "incorrect"
final_rt = rt if (accuracy == "correct" and rt and rt >= 250) else ""
condition = "observed" if (cat == 'B' and observe_key == 'y') else "unobserved"
row_data = [
pid, session, tnum, timestamp, cat, prime, stim,
"congruent" if prime % 2 == stim % 2 else "incongruent",
key if key else "None",
final_rt, accuracy, condition
]
rows.append(row_data)
# --- SAVE IMMEDIATELY ---
try:
with open(csv_path, "a", newline="") as f:
w = csv.writer(f)
w.writerow(row_data)
f.flush()
os.fsync(f.fileno())
except Exception as e:
print(f"Write error: {e}")
screen.fill(BLACK)
pygame.display.flip()
pygame.time.delay(INTER_TRIAL_INTERVAL)
# --------------------------
# SCORING & FINAL SCREEN
# --------------------------
def get_condition_mean(data, category, congruency):
"""
Calculates mean RT for a specific Category (A/B) and Congruency (congruent/incongruent).
Filters out invalid RTs (empty strings or None).
"""
# Index 4 is Category, Index 7 is Congruency, Index 9 is RT
valid_rts = [
row[9] for row in data
if row[4] == category
and row[7] == congruency
and isinstance(row[9], (int, float))
]
# Avoid division by zero if a participant gets everything wrong in one category
if not valid_rts:
return 0
return sum(valid_rts) / len(valid_rts)
# Calculate the four specific means
mean_a_con = get_condition_mean(rows, 'A', 'congruent')
mean_a_inc = get_condition_mean(rows, 'A', 'incongruent')
mean_b_con = get_condition_mean(rows, 'B', 'congruent')
mean_b_inc = get_condition_mean(rows, 'B', 'incongruent')
# Calculate the priming effects (Incongruent - Congruent)
diff_a = mean_a_inc - mean_a_con
diff_b = mean_b_inc - mean_b_con
# Final Score: Category B Difference - Category A Difference
score = diff_b - diff_a
# --------------------------
# FINAL SCREENS
# --------------------------
if score >= 21:
interpretation = ' The numbers were likely OBSERVED.'
elif 14 <= score <= 20:
interpretation = ' too close to tell. Try again.'
else:
interpretation = ' The numbers were likely UNOBSERVED.'
# --- Screen 1: Score & Interpretation ---
screen_1_text = (
f"Your Score: {round(score, 2)}\n\n"
f"{interpretation}\n\n"
"To increase accuracy, play again and make the same choice to observe or not. "
"Then average scores across games. Averaging three or more games greatly increases detection accuracy.\n\n"
"Press SPACE to continue."
)
wait_space(screen_1_text)
# --- Screen 2: Scoring Details ---
screen_2_text = (
"SCORING GUIDE:\n\n"
"The higher the score, the more likely the numbers were observed.\n\n"
"* Scores higher than 15 are rated as likely OBSERVED.\n\n"
"* Scores of 7 or lower are rated as likely UNOBSERVED.\n\n"
"Press SPACE to continue."
)
wait_space(screen_2_text)
# --- Screen 3: Perceptual Learning Warning ---
screen_3_text = (
"IMPORTANT NOTE:\n\n"
"Please note that after a person plays about 4 games, the accuracy of the detector "
"may decrease due to 'perceptual learning'.\n\n"
"To avoid this, set a 4 game limit per individual. The effects of perceptual learning may fade over time.\n\n"
"Press SPACE to continue."
)
wait_space(screen_3_text)
# --- Screen 4: Thank You & Link ---
screen_4_text = (
"Thank you for playing.\n\n"
"More information about this prior observation detector and how this protocol tests "
"the 'Consciousness Causes Collapse' interpretation of quantum mechanics can be found at:\n\n"
"testingtheccc.com\n\n"
"Press SPACE to exit."
)
wait_space(screen_4_text)
pygame.quit()
sys.exit()
SD Card*******************************************************************
The Raspberry Pi-3 SD card contains other code related to the set up and processing of the computer unit itself, such as the location of the files and the AutoStart commands, that are directly related to the experimental protocol. I did not copy it here for the sake of clarity, but it can be accessed physically from the Raspberry Pi unit.
END NOTE
An updated version of this guide will be kept at testingtheccc.com. Please refer back to it or feel free to email [email protected] with specific questions of any kind. Thank you for your interest in this device and in the Consciousness Causes Collapse Interpretation of Quantum Mechanics.