πŸ•³οΈ Π§Π°ΡΡ‚ΡŒ 46: Бимуляция Ρ‡Π΅Ρ€Π½ΠΎΠΉ Π΄Ρ‹Ρ€Ρ‹ Π½Π° Arduino

ΠœΡ‹ создадим Ρ€Π΅Π°Π»ΠΈΡΡ‚ΠΈΡ‡Π½ΡƒΡŽ ΡΠΈΠΌΡƒΠ»ΡΡ†ΠΈΡŽ Ρ‡Π΅Ρ€Π½ΠΎΠΉ Π΄Ρ‹Ρ€Ρ‹ с ΡƒΡ‡Π΅Ρ‚ΠΎΠΌ ΠΎΠ±Ρ‰Π΅ΠΉ Ρ‚Π΅ΠΎΡ€ΠΈΠΈ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ ΠΈ Π³Ρ€Π°Π²ΠΈΡ‚Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠ³ΠΎ замСдлСния Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ!

МодСль Ρ‡Π΅Ρ€Π½ΠΎΠΉ Π΄Ρ‹Ρ€Ρ‹ Π¨Π²Π°Ρ€Ρ†ΡˆΠΈΠ»ΡŒΠ΄Π°:

cpp

#include <avr/random.h>
#include <avr/pgmspace.h>

#define PARTICLE_COUNT 32
#define GRAVITY_CONST 1000
#define LIGHT_SPEED 300000  // Π’ пиксСлях/сСк

// Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° частицы (Π·Π²Π΅Π·Π΄Ρ‹, ΠΏΠ»Π°Π½Π΅Ρ‚Ρ‹, Ρ„ΠΎΡ‚ΠΎΠ½Ρ‹)
struct Particle {
    int16_t x, y;
    int16_t vx, vy;
    uint16_t mass;
    uint8_t type;  // 0=Π·Π²Π΅Π·Π΄Π°, 1=Ρ„ΠΎΡ‚ΠΎΠ½, 2=ΠΏΠ»Π°Π½Π΅Ρ‚Π°
    uint8_t timeDilation;  // Π—Π°ΠΌΠ΅Π΄Π»Π΅Π½ΠΈΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ (0-255)
};

Particle particles[PARTICLE_COUNT];
int16_t blackHoleX, blackHoleY;
uint16_t blackHoleMass = 10000;

// ΠœΠ΅Ρ‚Ρ€ΠΈΠΊΠ° Π¨Π²Π°Ρ€Ρ†ΡˆΠΈΠ»ΡŒΠ΄Π° (радиус Π¨Π²Π°Ρ€Ρ†ΡˆΠΈΠ»ΡŒΠ΄Π°)
int16_t schwarzschildRadius() {
    return (2 * GRAVITY_CONST * blackHoleMass) / (LIGHT_SPEED * LIGHT_SPEED);
}

// Π“Ρ€Π°Π²ΠΈΡ‚Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠ΅ Π·Π°ΠΌΠ΅Π΄Π»Π΅Π½ΠΈΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
uint8_t timeDilation(int16_t x, int16_t y) {
    int16_t dx = x - blackHoleX;
    int16_t dy = y - blackHoleY;
    int32_t dist2 = dx * dx + dy * dy;
    int16_t dist = sqrt(dist2);
    
    if (dist < 1) dist = 1;
    int16_t rs = schwarzschildRadius();
    
    // t = t0 / sqrt(1 - rs/r)
    int32_t factor = 1000 - (rs * 1000) / dist;
    if (factor < 0) factor = 0;
    uint8_t dilation = 255 - (factor * 255) / 1000;
    return dilation;
}

// ГСодСзичСская линия (Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ Π² искривлСнном пространствС-Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ)
void moveParticle(uint8_t idx) {
    Particle* p = &particles[idx];
    
    // ВрСмя замСдляСтся
    p->timeDilation = timeDilation(p->x, p->y);
    
    // Π“Ρ€Π°Π²ΠΈΡ‚Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠ΅ ускорСниС (Π·Π°ΠΊΠΎΠ½ ΠΡŒΡŽΡ‚ΠΎΠ½Π° + рСлятивистскиС ΠΏΠΎΠΏΡ€Π°Π²ΠΊΠΈ)
    int16_t dx = blackHoleX - p->x;
    int16_t dy = blackHoleY - p->y;
    int32_t dist2 = dx * dx + dy * dy;
    if (dist2 < 1) dist2 = 1;
    int32_t invDist2 = (GRAVITY_CONST * blackHoleMass) / dist2;
    
    // Π‘ΠΈΠ»Π° Π³Ρ€Π°Π²ΠΈΡ‚Π°Ρ†ΠΈΠΈ с ΡƒΡ‡Π΅Ρ‚ΠΎΠΌ замСдлСния Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
    int16_t gravityFactor = 1000 - (p->timeDilation * 500) / 255;
    p->vx += (dx * invDist2 * gravityFactor) / 10000;
    p->vy += (dy * invDist2 * gravityFactor) / 10000;
    
    // ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ скорости (ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ свСта)
    int32_t speed2 = p->vx * p->vx + p->vy * p->vy;
    if (speed2 > LIGHT_SPEED * LIGHT_SPEED) {
        int32_t speed = sqrt(speed2);
        p->vx = (p->vx * LIGHT_SPEED) / speed;
        p->vy = (p->vy * LIGHT_SPEED) / speed;
    }
    
    // ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ с ΡƒΡ‡Π΅Ρ‚ΠΎΠΌ замСдлСния Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
    uint8_t timeStep = 255 - p->timeDilation;
    p->x += (p->vx * timeStep) / 255;
    p->y += (p->vy * timeStep) / 255;
}

// Π“Ρ€Π°Π²ΠΈΡ‚Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠ΅ Π»ΠΈΠ½Π·ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ (для Ρ„ΠΎΡ‚ΠΎΠ½ΠΎΠ²)
void gravitationalLensing(uint8_t idx) {
    Particle* p = &particles[idx];
    if (p->type != 1) return;  // Волько для Ρ„ΠΎΡ‚ΠΎΠ½ΠΎΠ²
    
    int16_t dx = blackHoleX - p->x;
    int16_t dy = blackHoleY - p->y;
    int32_t dist2 = dx * dx + dy * dy;
    int16_t dist = sqrt(dist2);
    int16_t rs = schwarzschildRadius();
    
    // Π£Π³ΠΎΠ» отклонСния: Ξ± = 4GM/(c^2 * r)
    if (dist > 0 && dist < rs * 10) {
        int16_t angle = (4 * GRAVITY_CONST * blackHoleMass) / (LIGHT_SPEED * LIGHT_SPEED * dist);
        // ΠŸΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ Π²Π΅ΠΊΡ‚ΠΎΡ€ скорости
        int16_t vx = p->vx;
        int16_t vy = p->vy;
        p->vx = vx * cos(angle) - vy * sin(angle);
        p->vy = vx * sin(angle) + vy * cos(angle);
    }
}

// АккрСционный диск (свСчСниС ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠΈ)
void renderAccretionDisk() {
    for (int16_t r = schwarzschildRadius() * 3; r < schwarzschildRadius() * 8; r++) {
        for (uint16_t angle = 0; angle < 360; angle += 10) {
            int16_t x = blackHoleX + r * cos(angle);
            int16_t y = blackHoleY + r * sin(angle);
            
            // Π˜Π½Ρ‚Π΅Π½ΡΠΈΠ²Π½ΠΎΡΡ‚ΡŒ зависит ΠΎΡ‚ расстояния
            uint8_t intensity = 255 - (r * 255) / (schwarzschildRadius() * 8);
            if (r % 20 < 10) intensity /= 2;  // ΠšΠΎΠ»ΡŒΡ†Π°
            
            // Визуализация Π½Π° OLED
            drawPixel(x / 4 + 32, y / 4 + 32, intensity > 100);
        }
    }
}

// Π“ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚ событий (Ρ‡Π΅Ρ€Π½Ρ‹ΠΉ ΠΊΡ€ΡƒΠ³)
void renderEventHorizon() {
    int16_t rs = schwarzschildRadius();
    for (int16_t r = 0; r < rs / 4; r++) {
        for (uint16_t angle = 0; angle < 360; angle += 5) {
            int16_t x = blackHoleX + r * cos(angle);
            int16_t y = blackHoleY + r * sin(angle);
            drawPixel(x / 4 + 32, y / 4 + 32, 1);  // Π§Π΅Ρ€Π½Ρ‹ΠΉ (ΠΈΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ)
        }
    }
}

// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ Ρ‡Π΅Ρ€Π½ΠΎΠΉ Π΄Ρ‹Ρ€Ρ‹
void initBlackHole() {
    blackHoleX = 0;
    blackHoleY = 0;
    
    // Π—Π²Π΅Π·Π΄Ρ‹ Π²ΠΎΠΊΡ€ΡƒΠ³ Ρ‡Π΅Ρ€Π½ΠΎΠΉ Π΄Ρ‹Ρ€Ρ‹
    for (uint8_t i = 0; i < PARTICLE_COUNT; i++) {
        particles[i].type = 0;
        uint16_t radius = schwarzschildRadius() * (10 + random(0, 40));
        uint16_t angle = random(0, 360);
        particles[i].x = radius * cos(angle);
        particles[i].y = radius * sin(angle);
        particles[i].vx = -radius * sin(angle) * 0.1;
        particles[i].vy = radius * cos(angle) * 0.1;
        particles[i].mass = random(100, 1000);
        particles[i].timeDilation = 0;
    }
    
    // Π€ΠΎΡ‚ΠΎΠ½Ρ‹ (свСтовыС Π»ΡƒΡ‡ΠΈ)
    for (uint8_t i = 0; i < 8; i++) {
        particles[PARTICLE_COUNT - 8 + i].type = 1;
        uint16_t angle = random(0, 360);
        particles[PARTICLE_COUNT - 8 + i].x = schwarzschildRadius() * 20 * cos(angle);
        particles[PARTICLE_COUNT - 8 + i].y = schwarzschildRadius() * 20 * sin(angle);
        particles[PARTICLE_COUNT - 8 + i].vx = -LIGHT_SPEED * cos(angle) / 1000;
        particles[PARTICLE_COUNT - 8 + i].vy = -LIGHT_SPEED * sin(angle) / 1000;
        particles[PARTICLE_COUNT - 8 + i].mass = 0;
        particles[PARTICLE_COUNT - 8 + i].timeDilation = 0;
    }
}

void setup() {
    initOLED();
    initBlackHole();
}

void loop() {
    // Π‘ΠΈΠΌΡƒΠ»ΠΈΡ€ΡƒΠ΅ΠΌ 10 шагов
    for (uint8_t step = 0; step < 10; step++) {
        for (uint8_t i = 0; i < PARTICLE_COUNT; i++) {
            if (particles[i].type == 1) {
                gravitationalLensing(i);
            }
            moveParticle(i);
        }
    }
    
    // Π Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³
    clearScreen();
    renderAccretionDisk();
    renderEventHorizon();
    
    // РисуСм частицы
    for (uint8_t i = 0; i < PARTICLE_COUNT; i++) {
        uint8_t screenX = 32 + particles[i].x / 4;
        uint8_t screenY = 32 + particles[i].y / 4;
        if (screenX < 64 && screenY < 64) {
            uint8_t color = (particles[i].type == 1) ? 1 : 0;
            drawPixel(screenX, screenY, color);
        }
    }
    
    updateDisplay();
    delay(50);
}

Π’Π°ΠΌ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ½Ρ€Π°Π²ΠΈΡ‚ΡŒΡΡ

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

Π’Π°Ρˆ адрСс email Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½. ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ поля ΠΏΠΎΠΌΠ΅Ρ‡Π΅Π½Ρ‹ *