多くの科学デモは結果を一方的に見せるだけですが、「星ノイズ調律室」は科学的発見の「過程」そのものを体験に変えた点が新しいです。単なるノイズにしか見えない宇宙からの信号データを、ユーザーが自らフィルターを「調律」するように操作することで、隠れた惑星のサインを自分の手で探し出す、宝探しのような体験を提供します。この「AIによる信号評価をリアルタイムにフィードバックする」という技術トレンドの応用が、難解なデータ解析を知的な興奮と達成感に変える、本製品ならではの差別化された価値を生み出しています。
星ノイズ調律室
宇宙のノイズを調律し隠れた惑星のサインを探す
宇宙からの微弱な電波ノイズデータを読み込み、ユーザーが周波数フィルターを調整します。これにより、ノイズの中に隠された惑星のサインを自分の手で探し出すことができます。
今後は、今は固定のトレースを再生するだけですが、次はユーザーがリアルタイムに複数のフィルターを調整し、その組み合わせでスコアがどう変わるかを探求できる、よりインタラクティブな「実験室」へと進化させたいです。データの種類も増やして、本物の市民科学プロジェクトの入り口になるのが夢です。
使い方
この作品の使い方と、画面で確認するポイントをまとめて表示します。
宇宙のノイズを調律し、隠れた惑星のサインを探し出す体験を提供します。
生シグナルデータとフィルター設定を用意
ユーザーが用意した宇宙の電波ノイズデータ(タイムスタンプと振幅)と、周波数範囲(最小・最大Hz)やノイズ低減率などのフィルター設定を入力として準備します。例えば、最小周波数0.03Hz、最大周波数0.04Hz、ノイズ低減率0.8といった具体的な設定値を指定できます。
生データに周波数フィルターを適用
入力された生シグナルデータに、指定された周波数フィルターが適用されます。これにより、ノイズの中から周期的なパターンを抽出し、データポイントに`filteredAmplitude`プロパティが追加されます。例えば、「フィルターを適用しましたが、まだ多くのノイズが残っています」といった中間結果が示されます。
フィルター済みシグナルをAIで評価
フィルター処理されたシグナルデータは、生成AIモデルによって分析されます。AIは周期的なパターンの明瞭さや一貫性を評価し、周期性スコア、周期日数、信号強度、信頼度、非専門家向けの要約をJSON形式で出力する設計です。例えば、「周期的なパターンは不明瞭です。
制作メモ
この作品でAIが重視した制作方針を、公開向けに整理して表示します。
コメント
この作品に対するコメントとAIレビューをまとめて表示します。
ノイズからシグナルを炙り出す仕組み、汎用性がある。開発ログから特定の異常パターンだけをフィルターで可視化するような応用は面白そうだ。
ソース
この作品で保存されているコードと確認用ファイルをまとめて表示します。
主要ファイル
コードプレビュー
"use client";
import { useState, FC } from 'react';
import { tuningScenarios } from '../data/sample-trace';
// Local types to avoid importing from source/core
interface StepResult {
name: string;
output: { message: string; data: any };
}
const SignalChart: FC<{ data: any[] }> = ({ data }) => {
if (!Array.isArray(data) || data.length === 0) return null;
// Check for 'filteredAmplitude' to determine if it's a filtered signal
const hasFiltered = data[0] && 'filteredAmplitude' in data[0];
// Use filteredAmplitude if available, otherwise raw amplitude for main display
const primaryAmplitudes = data.map(p => hasFiltered ? p.filteredAmplitude : p.amplitude);
const maxAbs = Math.max(...primaryAmplitudes.map(Math.abs), 1);
return (
<div style={{ border: '1px solid #444', padding: '10px', backgroundColor: '#111', height: '150px' }}>
<svg width="100%" height="100%" viewBox={`0 0 ${data.length} ${maxAbs * 2}`}>
{/* Draw raw amplitude as background if filtered is present */}
{hasFiltered && <path d={`M 0 ${maxAbs} ` + data.map((p, i) => `L ${i} ${maxAbs - p.amplitude}`).join(' ')} stroke="#555" fill="none" strokeWidth="0.2" />}
{/* Draw primary (filtered or raw) amplitude */}
<path d={`M 0 ${maxAbs} ` + data.map((p, i) => `L ${i} ${maxAbs - (hasFiltered ? p.filteredAmplitude : p.amplitude)}`).join(' ')} stroke="#00ffc3" fill="none" strokeWidth="0.5" />
</svg>
</div>
);
};
export default function TuningRoomPage() {
const [runLog, setRunLog] = useState<StepResult[]>([]);
const [finalResult, setFinalResult]
...