파이썬으로 지구과학 시험문제 내기

힘센캥거루·2024-12-18

1. 2025학년도 9월 지구과학1 20번 문제

올해 9월에 지구과학 모의고사를 풀다가 골깨지는 문제가 하나 있었다.

20번 외계 행성계 탐사 문제였는데 아무리 봐도 주기가 없다.

alt text

결국 해결하지 못하고 EBS 강의를 보는 굴욕을 치뤘다.

해답은 그래프의 주기.

그래프에서 주기가 t1 ~ t4 까지이니, 시선속도가 -30~+30m/s인 지점에서 전체 주기의 1/3을 회전한 것.

따라서 t1 ~ t2에서 회전각은 120도이므로 시선속도가 +30인 지점에서 시선방향-공전중심-중심별의 사이는 60도가 된다.

말하면서도 이게 뭔가 싶어서 그림으로 표현해 보았다.

alt text

그럼 t2 지점에서의 시선 속도를 구해보면 아래와 같다.

alt text

여기서 Vr = V * cos30º 이고 Vr = 30 m/s 이므로, V = Vr / cos30º 이다.

그래서 ㄷ이 맞다는 충격적인 결론이다.

alt text

이걸 어케 1분만에 푸냐...

이건 가우스가 환생해서 와도도 1분 안에는 못 풀것 같다.

어쨌든 이 문제를 2학년 아이들에게 풀이하는 방법을 모두 알려주고 똑같은 문제를 수행평가로 내기로 했다.

물론, 풀이를 하면서 이 문제가 수행평가일 것이라고는 말해주지 않았다.

2. 수행평가를 치다.

지구과학1 수업반이 모두 월요일에 몰려 있어서 월요일에 시험을 치기로 했다.

그런데...?

alt text

반에 들어갔더니 애들의 절반이 없었다.

문제가 어렵다는 소문이 났고, 수행평가를 준비하지 못했던 학생들이 병조퇴를 한 것.

진짜 아팠던 아이들도 있지만 이대로 똑같은 시험지로 시험을 칠 순 없었다.

정직하게 시험을 친 학생들이 기존의 문제를 그대로 한다면 평가의 형평성에 문제가 있지 않냐는 이의를 제기했다.

그래서 파이썬으로 그래프를 그리게 되었다.

3. 파이썬으로 수행평가 내기

문제의 유형은 같게 하고 값이나 주기 자체를 변경시키기로 했다.

그리고 계속 값을 변경시키고 확인하기 쉽도록 주피터 환경에서 진행했다.

먼저 모듈을 호출하고 한글이 깨지는걸 막기 위해 폰트 설정부터 해준다.

from matplotlib import pyplot as plt
import matplotlib
import numpy as np
from numpy import pi
matplotlib.rcParams["font.family"] = "batang"
 
matplotlib.rcParams["font.size"] = 13
plt.rcParams['axes.unicode_minus'] = False

그리고 그래프의 x값의 범위와 최대 속력을 정해준다.

xStart = -pi
xEnd = 3*pi
maxV = 20*(3**0.5)
 
x = np.arange(xStart, xEnd, 0.1)
y = np.sin(x)*maxV

파이 값은 numpy 의 pi를 호출하면 간편하게 사용할 수 있다.

그리고 이미지 크기를 적절하게 설정한 다음 실행 코드를 누르면 아래와 같은 그림을 얻는다.

plt.figure(figsize=(7,3))
plt.plot(x,y, color="black")

그래프 중간1

아직 뭔가 많이 부족하다.

이제 이 그림에서 필요한 부분을 잘라내고 각 축을 설정해보자.

xthicks와 ythicks로 축값을 변경하고 xlim, ylim으로 그래프를 적절하게 잘라준다.

그리고 그리드를 그려주면 그럴듯한 그림이 생긴다.

plt.xticks(np.arange(xStart, xEnd, 2*pi/3),[f"t{x}" for x in range(6)])
plt.yticks([-45,  -30, -15, 0, 15, 30, 45])
plt.xlim(xStart+2*pi/3, xEnd-pi*2/3)
plt.ylim(-45,45)
plt.grid(linestyle='--')

그래프 중간2

마지막으로 scatter로 내가 원하는 값을 하나 찍고 축의 이름을 설정한다.

z = np.arcsin(-(3**0.5)/2)
plt.scatter(z+2*pi,np.sin(z)*maxV, color="black")
plt.xlabel("시간 →", loc="right")
plt.ylabel("시선속도(m/s)")

완성

이제 여기서 함수의 주기를 바꿔주거나, 최댓값과 최솟값을 바꾸면 문제 변형이 가능하다.

4. 응용하기

이번 2차 지필에서는 아래의 문제에서 오른쪽 그래프의 시선속도 값을 뒤집고 최댓값을 30으로 변경하고 싶었다.

그래서 위의 방식으로 코드를 만들어 보았다.

alt text

grape.ipynb
from matplotlib import pyplot as plt
import matplotlib
import numpy as np
from numpy import pi
# matplotlib.rcParams["font.family"] = "AppleGothic"
matplotlib.rcParams["font.family"] = "batang"
 
matplotlib.rcParams["font.size"] = 13
plt.rcParams['axes.unicode_minus'] = False
xStart = 0
xEnd = 4*pi
maxV = 30
 
x = np.arange(xStart, xEnd, 0.1)
y = np.sin(x)*30
plt.figure(figsize=(2,2))
plt.plot(x,y, color="black")
plt.xticks([])
plt.yticks([-30, 0, 30], ["-30", 0 ,"+30"])
# plt.grid(linestyle="--")
plt.xlim([0, 2*pi])
plt.xlabel("시간 →", loc="right")
plt.plot([0, pi/2],[30, 30], color="black", linestyle="--",linewidth=0.5)
plt.plot([0, pi*3/2],[-30, -30], color="black", linestyle="--",linewidth=0.5)
plt.plot([0, pi*3],[0, 0], color="black", linewidth=0.5)
ylabel = plt.ylabel("시\n\n\n\n(m/s)", rotation=0, labelpad=18)
ylabel.set_position((0,0.3))

처음에는 중간에 점선을 어떻게 표현할지 살짝 생각했데, 그냥 직선으로 그리면 끝나는 문제였다.

결과물은 상당히 만족스러웠다.

결과

5. 후기

시험문제의 완성도도 올라가고, 코딩 공부도 함께할 수 있는 시간이었다.

앞으로도 많이 응용할 예정이다.