{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "It's at the [MIAM](https://miam.org/) (Miam Musée International des Arts Modestes) in Sète, France, that I could for the first time experience really the [Dreamachine](https://en.wikipedia.org/wiki/Dreamachine). It's an optical system which consists of a central light which is periodically occluded by a rotating (cardboard?) cylinder. \n", "\n", "The magic of it is that the frequency of occlusion is around $12$ Hz, an important resonant state for sensory system. For the first time, I could really try it out at the MIAM - the important point being to close your lids and rest quiet while looking at the stroboscopic light source. Surprisingly, you see the emergence of \"psychedelic patterns\" (of course, less than in hippie's movies) yet of the order of the color pattern that may arise in [Benham's Disk](https://en.wikipedia.org/wiki/Fechner_color).\n", "\n", "It's difficult to reproduce this pattern on a screen, yet it is still possible to give an *impression of it*. The goal is here :\n", "\n", "* to generate a complex visual stimulation flickering on average at $12$ Hz\n", "\n", "* to project it on a retinotopic space to maximise the \"psychelic\" effect\n", "\n", "![retino_alpha](../files/2022-01-30-dreamachine/retino_alpha.gif)\n", "\n", "\n", "\n", "Let's first initialize the notebook:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from __future__ import division, print_function\n", "import numpy as np\n", "np.set_printoptions(precision=6, suppress=True)\n", "import os\n", "%matplotlib inline\n", "%config InlineBackend.figure_format='retina'\n", "#%config InlineBackend.figure_format = 'svg'\n", "import matplotlib.pyplot as plt\n", "phi = (np.sqrt(5)+1)/2\n", "fig_width = 10\n", "figsize = (fig_width, fig_width/phi)\n", "# https://docs.python.org/3/library/warnings.html#warning-filter\n", "import warnings\n", "warnings.simplefilter(\"ignore\")\n", "\n", "%load_ext autoreload\n", "%autoreload 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## a flickering motion cloud" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A simple way to generate a flickering stimulus is to combine two sinusiods going in two opposite directions, following :\n", "\n", "$$\n", "\\sin(\\omega_x \\cdot x + \\omega_t \\cdot v \\cdot t) + \\sin(\\omega_x \\cdot x - \\omega_t \\cdot v \\cdot t) = 2\\cdot \\cos(\\omega_x \\cdot x) \\cdot \\cos(\\omega_t \\cdot v \\cdot t)\n", "$$\n", "\n", "\n", "A first solution is to use an existing library for generating band-pass filtered noise, with a parameterization which fits well natural scenes:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "https://github.com/NeuralEnsemble/MotionClouds/blob/master/MotionClouds/MotionClouds.py" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import os\n", "name = 'alpha'\n", "DOWNSCALE = 2\n", "import MotionClouds as mc" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "mc.figpath = '../files/2022-01-30-dreamachine'\n", "os.makedirs(mc.figpath, exist_ok=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's explore parameters:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mSignature:\u001b[0m\n", "\u001b[0mmc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0menvelope_gabor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mfx\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mfy\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mft\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mV_X\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mV_Y\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mB_V\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0msf_0\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.125\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mB_sf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mloggabor\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mtheta\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mB_theta\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.19634954084936207\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0malpha\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m\n", "Returns the Motion Cloud kernel, that is the product of:\n", " * a speed envelope\n", " * an orientation envelope\n", " * an orientation envelope\n", "\u001b[0;31mFile:\u001b[0m ~/.local/lib/python3.9/site-packages/MotionClouds.py\n", "\u001b[0;31mType:\u001b[0m function\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "mc.envelope_gabor?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To find that which will best will what we wish to do:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "N_X=128, N_Y=128, N_frame=144\n" ] } ], "source": [ "T_movie = 2.4 # period in seconds\n", "fps = 60 # frames per second\n", "sf_0 = 0.05 # spatial frequency per period\n", "TF_0 = 12. # peak temporal frequency\n", "seed = 1234\n", "N_X, N_Y, N_frame = 256//DOWNSCALE, 256//DOWNSCALE, int(T_movie*fps)\n", "print(f'{N_X=}, {N_Y=}, {N_frame=}')" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "V_X=4.0, sf_0=0.05, tf_0=0.2\n" ] } ], "source": [ "fx, fy, ft = mc.get_grids(N_X, N_Y, N_frame)\n", "\n", "tf_0 = TF_0/fps # temporal frequency per period\n", "V_X = tf_0 / sf_0\n", "B_V = 0.12\n", "theta = 0\n", "B_theta = .1\n", "print(f'{V_X=}, {sf_0=}, {tf_0=}')" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "z_1 = mc.envelope_gabor(fx, fy, ft, V_X=V_X, sf_0=sf_0, B_V=B_V, theta=theta, B_theta=B_theta)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ffmpeg version 4.4-6ubuntu5 Copyright (c) 2000-2021 the FFmpeg developers\n", "built with gcc 11 (Ubuntu 11.2.0-7ubuntu1)\n", "configuration: --prefix=/usr --extra-version=6ubuntu5 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared\n", "libavutil 56. 70.100 / 56. 70.100\n", "libavcodec 58.134.100 / 58.134.100\n", "libavformat 58. 76.100 / 58. 76.100\n", "libavdevice 58. 13.100 / 58. 13.100\n", "libavfilter 7.110.100 / 7.110.100\n", "libswscale 5. 9.100 / 5. 9.100\n", "libswresample 3. 9.100 / 3. 9.100\n", "libpostproc 55. 9.100 / 55. 9.100\n" ] }, { "data": { "text/html": [ "\n", "