서비스·생활

JJY 시뮬레이터

유선 이어폰으로 일본 표준전파 JJY를 흉내 내, 해외에서도 전파시계를 현지 시각으로 맞추게 해 주는 웹페이지입니다.

분야서비스·생활플랫폼Web (ko · en · ja)기술Vanilla JS (ES 모듈) · Web Audio API · Intl.DateTimeFormat · SVG · d3-geo · topojson (지도) · Node 테스트(assert)
지도에서 도시를 고르면 그 현지 시각으로 타임코드를 만들어 송신합니다.
지도에서 도시를 고르면 그 현지 시각으로 타임코드를 만들어 송신합니다.

왜 만들었나

JJY 전파시계는 일본 밖에서는 전파를 받지 못하고, 받더라도 무조건 일본 시각(JST)으로 해석합니다. 휴대폰 소리로 신호를 만들고, 고른 지역의 현지 시각을 JST 자리에 넣어 보내 이 문제를 풉니다.

주요 기능

  • 지도를 눌러 가장 가까운 도시의 시간대 선택 (기본값은 기기 시간대)
  • 40kHz / 60kHz 국 선택
  • 60초 타임코드 막대와 현재 초 표시
  • 송신 중 화면 꺼짐 방지(Wake Lock)
  • 한국어·영어·일본어 페이지

숫자로 보면

1분 프레임 = 기호 60개
지도에 미리 넣은 도시 62곳
언어별 페이지 3개(en·ko·ja)

어떻게 동작하나

  1. 시간대 → 시각 필드

    fields()가 Intl.DateTimeFormat으로 선택한 IANA 시간대의 연·연중 일수·시·분·요일을 구해, 서머타임까지 자동 반영합니다.

    jjy.js
  2. 1분 프레임 생성

    frame()이 분·시·연중 일수·연도·요일을 BCD로 바꾸고 마커와 패리티 비트를 넣어 0/1/M 기호 60개를 만듭니다.

    jjy.js
  3. 기호 → 펄스 길이

    HIGH 표가 기호마다 매초 앞부분에서 신호를 켜 둘 시간(0은 0.8초, 1은 0.5초, M은 0.2초)을 정합니다.

    jjy.js
  4. 오디오 예약

    schedule()이 50ms마다 돌며 앞으로 3초 분량의 펄스를 GainNode 값 변경으로 오디오 시계에 미리 예약하고, getOutputTimestamp로 출력 지연을 보정합니다.

    app.js
  5. 배음 송신

    13.333kHz(또는 20kHz) 사인파를 켜고 끄면 이어폰 케이블에서 새는 3배음 40kHz(60kHz)를 시계 안테나가 받습니다.

    app.js
  6. 화면 표시

    render()가 현지 시각, 60칸 비트 막대, 현재 초 램프를 매초 다시 그립니다.

    app.js

핵심 코드

export function frame({ y, doy, h, m, wd }) {
  const bcd = (v, ...w) => w.map(x => (v >= x ? (v -= x, 1) : 0));
  const par = a => a.reduce((s, x) => s ^ x, 0);
  const M = 'M';
  const mi = bcd(m, 40, 20, 10, 8, 4, 2, 1);
  const hr = bcd(h, 20, 10, 8, 4, 2, 1);
  const d = bcd(doy, 200, 100, 80, 40, 20, 10, 8, 4, 2, 1);
  return [
    M, ...mi.slice(0, 3), 0, ...mi.slice(3), M,                 // 0-9   minute
    0, 0, ...hr.slice(0, 2), 0, ...hr.slice(2), M,              // 10-19 hour
    0, 0, ...d.slice(0, 2), 0, ...d.slice(2, 6), M,             // 20-29 day of year
    ...d.slice(6), 0, 0, par(hr), par(mi), 0, M,                // 30-39 doy, PA1, PA2, SU1
    0, ...bcd(y % 100, 80, 40, 20, 10, 8, 4, 2, 1), M,          // 40-49 SU2, year
    ...bcd(wd, 4, 2, 1), 0, 0, 0, 0, 0, 0, M,                   // 50-59 weekday, LS1/2
  ];
}

시각 필드를 JJY 규격의 60개 기호(0·1·마커)로 바꾸는 부분으로, BCD 변환과 패리티 계산이 들어 있습니다.

어려웠던 점

setTimeout은 수십 ms씩 밀려서 펄스 경계가 흔들리기 때문에, 벽시계 시각을 오디오 컨텍스트 시각으로 바꿔 3초 앞까지 setValueAtTime으로 미리 예약합니다. 또 휴대폰은 40kHz를 낼 수 없어서, 그 1/3 주파수를 내보내고 3배음을 이용합니다.