Inspired by Scott’s QFD, I attempted a modified version of the experiment described in the referenced paper. Using a Logitech C270 webcam, each photodiode on the webcam sensor acts as a noise source, analogous to the Zener diodes in the original experiment.
Part of the webcam’s internal plastic housing was trimmed and the built-in indicator LED bent to illuminate the sensor.
Some limitations are:
- Sample rate: The webcam operates at 30 fps (30 Hz), far lower than the 1000 Hz sampling rate used in the original experiment.
- Dynamic range: The webcam’s limited dynamic range is likely insufficient for reading quantum noise.
The live chart shows:
- Temporal coherence: Measured by averaging the autocorrelation of the signals from the selected pixels (16 evenly-spaced pixels) across a short time window (133.33 ms / 4 frames).
- Spatial coherence: Measured by averaging the Pearson correlation between signals from the selected pixels.
The code (tested on Windows)
import cv2
import subprocess
import sys
import platform
import math
import numpy as np
import time
import winsound
import threading
import matplotlib.pyplot as plt
from collections import deque
from scipy.stats import pearsonr
TEMPORAL_COHERENCE_ANOMALY_THRESHOLD = 0.3
SPATIAL_COHERENCE_ANOMALY_THRESHOLD = 0.1
def list_cameras():
cameras = {}
if platform.system() == "Windows":
try:
import pygrabber.dshow_graph
graph = pygrabber.dshow_graph.FilterGraph()
devices = graph.get_input_devices()
cameras = {i: name for i, name in enumerate(devices)}
except ImportError:
print("Install 'pygrabber' for better camera detection on Windows: pip install pygrabber")
elif platform.system() in ["Linux", "Darwin"]:
try:
result = subprocess.run(["ffmpeg", "-f", "avfoundation", "-list_devices", "true", "-i", ""], capture_output=True, text=True)
lines = result.stderr.split("\n")
for i, line in enumerate(lines):
if "[AVFoundation input device @ " in line:
cam_name = line.split("]")[1].strip().strip('"')
cameras[i] = cam_name
except FileNotFoundError:
print("Install 'ffmpeg' for better camera detection: https://ffmpeg.org/download.html")
return cameras
def find_camera_index(camera_name):
cameras = list_cameras()
for index, name in cameras.items():
if camera_name.lower() in name.lower():
return index
return None
def temporal_coherence_alert():
winsound.Beep(4000, 200)
def spatial_coherence_alert():
winsound.Beep(4000, 200)
time.sleep(0.1)
winsound.Beep(4000, 200)
buffer = [[] for _ in range(16)]
temporal_coherence_history = deque(maxlen=60)
spatial_coherence_history = deque(maxlen=60)
time_stamps = deque(maxlen=60)
if len(sys.argv) < 2:
print('Usage: ./webcam_qfd.py <camera_name_keyword>\n')
print('Example: ./webcam_qfd.py "logi c270"\n')
print('Available cameras:')
cameras = list_cameras()
for index, name in cameras.items():
print(f"{index}: {name}")
exit()
# The sensor should ideally be uniformly illuminated by a diffused LED
camera_name_to_search = sys.argv[1]
cap = cv2.VideoCapture(find_camera_index(camera_name_to_search))
if not cap.isOpened():
print("Error: Could not open webcam.")
exit()
plt.ion()
fig, ax = plt.subplots()
while True:
ret, frame = cap.read()
if not ret:
print("Error: Could not read frame.")
break
height, width, _ = frame.shape
grid_size_x = width // 5
grid_size_y = height // 5
pixel_positions = [(i * grid_size_x, j * grid_size_y) for i in range(1, 5) for j in range(1, 5)]
for i, (x, y) in enumerate(pixel_positions):
buffer[i].append(int(frame[y, x, 1]))
for (x, y) in pixel_positions:
cv2.circle(frame, (x, y), 1, (0, 0, 0), -1)
cv2.imshow("Webcam Noise Coherence Tracker", frame)
if len(buffer[0]) == 30:
avg_samples = np.mean(np.nan_to_num(buffer), axis=0)
autocorrelation_values = [np.corrcoef(avg_samples[:-lag], avg_samples[lag:])[0, 1] for lag in range(3, 8)]
temporal_coherence = np.mean(np.nan_to_num(autocorrelation_values))
if abs(temporal_coherence) > TEMPORAL_COHERENCE_ANOMALY_THRESHOLD:
print(f"Temporal coherence anomaly detected at {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}: {temporal_coherence}")
threading.Thread(target=temporal_coherence_alert).start()
temporal_coherence_history.append(temporal_coherence)
correlations = []
for i in range(len(buffer)):
for j in range(i + 1, len(buffer)):
corr, _ = pearsonr(buffer[i], buffer[j])
if math.isnan(corr):
corr = 0
correlations.append(corr)
spatial_coherence = np.mean(np.nan_to_num(correlations))
if abs(spatial_coherence) > SPATIAL_COHERENCE_ANOMALY_THRESHOLD:
print(f"Spatial coherence anomaly detected at {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}: {spatial_coherence}")
threading.Thread(target=spatial_coherence_alert).start()
spatial_coherence_history.append(spatial_coherence)
time_stamps.append(time.time())
ax.clear()
ax.plot(time_stamps, list(temporal_coherence_history), label='Temporal Coherence')
ax.plot(time_stamps, list(spatial_coherence_history), label='Spatial Coherence')
ax.set_ylim(-0.5, 0.5)
ax.set_title("Live Noise Coherence Tracking")
ax.set_ylabel("Coherence Value")
ax.set_xticks([])
ax.legend()
plt.draw()
plt.pause(0.01)
buffer = [[] for _ in range(len(buffer))]
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
plt.ioff()
plt.show()
While this is nowhere near a functional setup, it could be a fun experiment for exploring the idea using cheap readily available hardware.





