ΠΡ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠ΅Π°Π»ΠΈΡΡΠΈΡΠ½ΡΡ ΡΠΈΠΌΡΠ»ΡΡΠΈΡ ΡΠ΅ΡΠ½ΠΎΠΉ Π΄ΡΡΡ Ρ ΡΡΠ΅ΡΠΎΠΌ ΠΎΠ±ΡΠ΅ΠΉ ΡΠ΅ΠΎΡΠΈΠΈ ΠΎΡΠ½ΠΎΡΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΈ Π³ΡΠ°Π²ΠΈΡΠ°ΡΠΈΠΎΠ½Π½ΠΎΠ³ΠΎ Π·Π°ΠΌΠ΅Π΄Π»Π΅Π½ΠΈΡ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ!
ΠΠΎΠ΄Π΅Π»Ρ ΡΠ΅ΡΠ½ΠΎΠΉ Π΄ΡΡΡ Π¨Π²Π°ΡΡΡΠΈΠ»ΡΠ΄Π°:
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);
}