調布祭プラレール展示のWebUIと配信の話

UEC koken Advent Calendar 21日目の記事となります。

調布祭プラレール企画関連のブログ記事は以下から



Virtual調布祭

電気通信大学では今年(2020年)の11/21~23の3日間「バーチャル調布祭」と呼ばれるオンラインイベントが開催されていました。経緯については言わずもがなですが、従来の調布祭とはまた違うオンラインならではの良さがありました。

工研でも鉄道研究会さんと合同でプロジェクトを進めようという話になり、私も少しだけですが参加することにしました。 担当することになったのはいわばユーザー側、遠隔操作を行うウェブアプリケーションの部分でした。

作ったもの

特設サイトはこちら↓

chofufes-plarail-2020.takoyaki3.com

調布祭期間中は駅周辺や列車の様子を配信していました。

ソースについてはこちらから↓

github.com

設計

WebUI

さて、ユーザー側の心情としては深いギミックや仕様に悩まされることなく気軽に使える感覚が欲しくなるものです。 そのためUIを作るにあたってもあまりごちゃごちゃさせすぎないようにしよう、というのは最初に考えていました。

ユーザー側が遠隔操作でできることはこの2点に集約されます。

  • 操作可能区間京王本線)内での駅のポイント制御と発車・停車制御
  • 一部列車の速度制御

これに加えて操作する駅の選択も必要になります。ひとまず様々な人が使うことを想定してできるだけ直観的に操作できるような設計方針としました。

京王本線の駅は一部の再現にとどめ、どちらかというとポイント切り替えや通過待ちなどの”疑似運輸指令”を体験できるような駅が選ばれました。

一部の駅に絞って再現した路線図

遠隔操作できる駅は

の4駅、明大前駅以外は分岐があり遠隔制御の楽しさがより得られると思います。

駅選択部

例えば京王線をあまり知らないような人でも、これらの駅を初見でパッと見てわかりやすく選ぶ方法を考える必要がありました。

駅選択部。後にカメラを追加したため新線や前面展望のボタンを追加しました。

そのため路線図にボタンを重ねて配置することで位置関係を把握しやすくさせることにしました。

画像の上に重ねての配置はCSSのパーセント指定により行いました。いろいろなウィンドウ幅で表示が崩れてはいなかったため問題はなさそう、とは思いましたが正直もっと良いやり方があったようにも思います。

index.html

...(省略)

        <div id="chofusta" class="station" onclick="loadChofu()">調布駅</div>
        <div id="meidaista" class="station" onclick="loadMeidaimae()">明大前駅</div>
        <div id="sasasta" class="station" onclick="loadSasazuka()">笹塚駅</div>
        <div id="kitanosta" class="station" onclick="loadKitano()">北野駅</div>
        <div id="kudansta" class="station" onclick="loadKudansta()">九段下駅</div>
        <div id="iwamotosta" class="station" onclick="loadiwamotosta()">岩本町駅</div>
        <div id="train" class="station" onclick="loadtrain()">列車前面展望</div>
        <div id="backtokeio" class="station" hidden="true" onclick="backToWholeImage()">戻る</div>

...(省略)

css/main.css

...(省略)

.station {
    background-color: #2779bd55;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: calc(80% + 0.2vw);
    font-weight: bold;
    color: #000000;
    border-radius: 10%;
    cursor: pointer;
    text-shadow: 2px 2px 3px #ffffff99, -2px 2px 3px #ffffff99,
                 2px -2px 3px #ffffff99, -2px -2px 3px #ffffff99;
}

...(省略)

#chofusta {
    width: 20%;
    height: 16%;
    position: absolute;
    top: 52%;
    left: 52%;
}

#meidaista {
    width: 19%;
    height: 16%;
    position: absolute;
    top: 52%;
    left: 30%;
}

#kitanosta {
    width: 19%;
    height: 16%;
    position: absolute;
    top: 52%;
    left: 74%;
}

#sasasta {
    width: 20%;
    height: 16%;
    position: absolute;
    top: 52%;
    left: 7%;
}

#kudansta {
    width: 20%;
    height: 16%;
    position: absolute;
    top: 34%;
    left: 7%;
}

#train {
    width: 20%;
    height: 16%;
    position: absolute;
    top: 34%;
    left: 74%;
}

#iwamotosta {
    width: 20%;
    height: 16%;
    position: absolute;
    top: 34%;
    left: 30%;
}

#backtokeio {
    width: 12%;
    height: 10%;
    position: absolute;
    top: 10%;
    left: 44%;
}

ポイント制御と発車・停車制御部

ポイント切り替えやホームの発車や停車のオンオフは画像に重ねるとさすがにごちゃつく感じでしたので別に分けることにしました。 それぞれで役割が異なるため色分けしたりオンオフでの表示を変えたりといった工夫をしました。Bootstrapは便利ですね。

index.html

...(省略)
        <button v-for="s,k in stations[selected_station].stops" 
                v-on:click="push_btn(selected_station,true,k)" 
                :class="s.class">{{s.text}}</button><br/>
        <button v-for="s,k in stations[selected_station].branchs" 
                v-on:click="push_btn(selected_station,false,k)" 
                :class="s.class">{{s.text}}</button><br/>

...(省略)

    <script src="js/main.js"></script>
</body>
</html>

初めはVanillaでやるつもりでしたがたこやき君からVue.jsを薦められました。 触るのは初めてだったものの、わりかし何をしているかは分かりやすかったです。HTML部ではv-forで変数内の各要素を、v-on:clickでイベント発生時の処理を指定します。

js/main.js

const stations = {
    "":{},
    chofu:{
        stops:{
            s1: { text: "1番線進行", status: false, 
                  on_text: "1番線停車", 
                  off_text: "1番線進行", 
                  image: "image/chofu_s1_off.png",
                  on_image: "image/chofu_s1_on.png", 
                  off_image:"image/chofu_s1_off.png", 
                  class:"btn btn-outline-info control-btn" },
            s2: { text: "2番線進行", status: false, 
                  on_text: "2番線停車", 
                  off_text: "2番線進行", 
                  image: "image/chofu_s2_off.png", 
                  on_image: "image/chofu_s2_on.png", 
                  off_image:"image/chofu_s2_off.png", 
                  class:"btn btn-outline-info control-btn" },
            s3: { text: "3番線進行", status: false, 
                  on_text: "3番線停車", 
                  off_text: "3番線進行", 
                  image: "image/chofu_s3_off.png", 
                  on_image: "image/chofu_s3_on.png", 
                  off_image:"image/chofu_s3_off.png", 
                  class:"btn btn-outline-info control-btn" },
            s4: { text: "4番線進行", status: false, 
                  on_text: "4番線停車", 
                  off_text: "4番線進行", 
                  image: "image/chofu_s4_off.png", 
                  on_image: "image/chofu_s4_on.png", 
                  off_image:"image/chofu_s4_off.png", 
                  class:"btn btn-outline-info control-btn" }
        },
        branchs:{
            b1: { text: "2番線入線", status: false, 
                  on_text: "1番線入線", 
                  off_text: "2番線入線", 
                  image: "image/chofu_b1_off.png", 
                  on_image: "image/chofu_b1_on.png", 
                  off_image: "image/chofu_b1_off.png", 
                  class:"btn btn-outline-dark control-btn" },
            b2: { text: "橋本方面", status: false, 
                  on_text: "京王八王子・高尾山口方面", 
                  off_text: "橋本方面", 
                  image: "image/chofu_b2_off.png", 
                  on_image: "image/chofu_b2_on.png", 
                  off_image:"image/chofu_b2_off.png", 
                  class:"btn btn-outline-dark control-btn" },
            b3: { text: "4番線入線", status: false, 
                  on_text: "3番線入線", 
                  off_text: "4番線入線", 
                  image: "image/chofu_b3_off.png", 
                  on_image: "image/chofu_b3_on.png", 
                  off_image:"image/chofu_b3_off.png", 
                  class:"btn btn-outline-dark control-btn" }
        }
    },
    meidaimae:{
        stops:{
            s1: { text: "1番線停車", status: false, 
                  on_text: "1番線停車", 
                  off_text: "1番線進行", 
                  image: "image/meidaimae_s1_off.png", 
                  on_image: "image/meidaimae_s1_on.png", 
                  off_image:"image/meidaimae_s1_off.png", 
                  class:"btn btn-outline-info control-btn" },
            s2: { text: "2番線停車", status: false, 
                  on_text: "2番線停車", 
                  off_text: "2番線進行", 
                  image: "image/meidaimae_s2_off.png", 
                  on_image: "image/meidaimae_s2_on.png", 
                  off_image:"image/meidaimae_s2_off.png", 
                  class:"btn btn-outline-info control-btn" }
        },
        branchs:{
        }
    },
    sasazuka:{
        stops:{
            s1: { text: "1番線進行", status: false, 
                  on_text: "1番線停車", 
                  off_text: "1番線進行", 
                  image: "image/sasazuka_s1_off.png", 
                  on_image: "image/sasazuka_s1_on.png", 
                  off_image: "image/sasazuka_s1_off.png", 
                  class:"btn btn-outline-info control-btn" },
            s2: { text: "2番線進行", status: false, 
                  on_text: "2番線停車", 
                  off_text: "2番線進行", 
                  image: "image/sasazuka_s2_off.png", 
                  on_image: "image/sasazuka_s2_on.png", 
                  off_image: "image/sasazuka_s2_off.png", 
                  class:"btn btn-outline-info control-btn" },
            s4: { text: "4番線進行", status: false, 
                  on_text: "4番線停車", 
                  off_text: "4番線進行", 
                  image: "image/sasazuka_s4_off.png", 
                  on_image: "image/sasazuka_s4_on.png", 
                  off_image: "image/sasazuka_s4_off.png", 
                  class:"btn btn-outline-info control-btn" }
        },
        branchs:{
            b1: { text: "新宿方面", status: false, 
                  on_text: "本八幡方面", 
                  off_text: "新宿方面", 
                  image: "image/sasazuka_b1_off.png", 
                  on_image: "image/sasazuka_b1_on.png", 
                  off_image: "image/sasazuka_b1_off.png", 
                  class:"btn btn-outline-dark control-btn" }
        }
    },
    kitano:{
        stops:{
            s2: { text: "2番線進行", status: false, 
                  on_text: "2番線停車", 
                  off_text: "2番線進行", 
                  image: "image/kitano_s2_off.png", 
                  on_image: "image/kitano_s2_on.png", 
                  off_image: "image/kitano_s2_off.png", 
                  class:"btn btn-outline-info control-btn" },
            s3: { text: "3番線進行", status: false, 
                  on_text: "3番線停車",
                  off_text: "3番線進行", 
                  image: "image/kitano_s3_off.png", 
                  on_image: "image/kitano_s3_on.png", 
                  off_image: "image/kitano_s3_off.png", 
                  class:"btn btn-outline-info control-btn" }
        },
        branchs:{
            b1: { text: "京王八王子方面", status: false, 
                  on_text: "高尾山口方面", 
                  off_text: "京王八王子方面", 
                  image: "image/kitano_b1_off.png", 
                  on_image: "image/kitano_b1_on.png", 
                  off_image: "image/kitano_b1_off.png", 
                  class:"btn btn-outline-dark control-btn" }
        }
    }
}

const vue = new Vue({
    el:'#app',
    data:{
        selected_station:"",
        stations:stations,
        camera_peerids:{},
        theirID:"all",
        is_all:true
    },
    methods:{
        push_btn:async function(station,is_stop,operable_id) {
            console.log(operable_id)
            if (is_stop) {
                stations[station].stops[operable_id].status 
                  = !stations[station].stops[operable_id].status;
                stations[station].stops[operable_id].image 
                  = (stations[station].stops[operable_id].status 
                   ? stations[station].stops[operable_id].on_image 
                   : stations[station].stops[operable_id].off_image);
                stations[station].stops[operable_id].text 
                  = (stations[station].stops[operable_id].status 
                   ? stations[station].stops[operable_id].on_text 
                   : stations[station].stops[operable_id].off_text);
                stations[station].stops[operable_id].class 
                  = (stations[station].stops[operable_id].status 
                   ? "btn btn-info control-btn" 
                   : "btn btn-outline-info control-btn");
                
                await sendOperate(station, 
                                  station + "_" + operable_id, 
                                  "switch", 
                                  (stations[station].stops[operable_id].status 
                                  ? "On" : "Off"));
            } 
            else {
                stations[station].branchs[operable_id].status 
                  = !stations[station].branchs[operable_id].status;
                stations[station].branchs[operable_id].image 
                  = (stations[station].branchs[operable_id].status 
                   ? stations[station].branchs[operable_id].on_image 
                   : stations[station].branchs[operable_id].off_image);
                stations[station].branchs[operable_id].text 
                  = (stations[station].branchs[operable_id].status 
                   ? stations[station].branchs[operable_id].on_text
                   : stations[station].branchs[operable_id].off_text);
                stations[station].branchs[operable_id].class 
                  = (stations[station].branchs[operable_id].status 
                   ? "btn btn-dark control-btn" 
                   : "btn btn-outline-dark control-btn");
                
                await sendOperate(station,
                                  station + "_" + operable_id, 
                                  "switch", 
                                  (stations[station].branchs[operable_id].status 
                                  ? "On" : "Off"));
            }
        }
    },
    
    ...(省略)

});

// functions
function setStationButtonHidden(value) {
    document.getElementById("chofusta").hidden = value;
    document.getElementById("meidaista").hidden = value;
    document.getElementById("kitanosta").hidden = value;
    document.getElementById("sasasta").hidden = value;
    document.getElementById("iwamotosta").hidden = value;
    document.getElementById("kudansta").hidden = value;
    document.getElementById("train").hidden = value;
    document.getElementById("backtokeio").hidden = !value;
    document.getElementById("describe-text").hidden = value;
}

js/api.js

async function GetHttp(url, queries){
    const targetURL = (()=>{
        if(queries){
            const queryStrings = Object.entries(queries).map(([key, value]) => `${key}=${value}`)
            const queryString = queryStrings.reduce((prev,cur)=>`${prev}&${cur}`)
            return `${url}?${queryString}`
        }
        return url
    })()

    console.log(targetURL)

    console.log(url);

    const res = await fetch(targetURL,{})

    const json = await res.json()

    return json



    // const getData = async () => {
    //     try {
    //       /*const response = await fetch(targetURL, { 
    //         mode: 'no-cors'
    //       });*/
    //       xhr = new XMLHttpRequest();
    //       //xhr.setRequestHeader('Content-Type', 'application/json');
    //       xhr.open("GET", targetURL, true);
    //       xhr.send();
    //       const response = xhr.responseText;
    //       xhr.abort();
    //       if (response.status == 200) {
    //         const jsonResponse = JSON.parse(response); //await response.json();
    //         return jsonResponse
    //       }else{
    //         console.log(response)
    //       }
    //       throw new Error('Request done!');
    //     } catch (error) {
    //       console.log(error);
    //     }
    //   }
    // return await getData();
}

...(省略)

async function sendOperate(stationname,operableName,cmd,arg) {
  const url = `${endpoint}/units/${stationname}/${operableName}`
    return await GetHttp(url,{cmd,arg,"token":Token})
}

...(省略)

上のコードではそれぞれの駅のボタンクリック時にステータスやCSSスタイルを切り替える処理を行った後、sendOperate関数からWebAPIを呼び出しています。 操作すると次図のようになります。本来はここにオンオフ状態の同期や使っているユーザーのトークンを発行することでの順番待ち処理を行う予定でしたが、実装が間に合いませんでした。

ボタンで操作した様子

オンオフの切り替えで表示が変化しています。

速度制御部

当日の展示では一台だけ速度制御を行える列車がありました。そのため、こちらではスクロールバーで操作できるようにしました。 初めはスクロールに滑らかに対応させていました*1がさすがに送るデータ量が多すぎるのでスクロール終了時のみにWebAPIの関数を呼び出すようにしました。

index.html

...(省略)

        <p>速度操作可能な列車からの前面展望です!</p>
        <iframe src="https://www.youtube.com/embed/CnVFRJQ6VqY" frameborder="0"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
            allowfullscreen></iframe>
        <p>列車速度:<output id="speedvalue">49</output> <input type="range" name="speed" id="speed" min="-50" max="49" step="1" value="49" onchange="displaySpeed(this)"></p>

...(省略)

js/main.js

...(省略)

async function displaySpeed(obj) {
    document.getElementById('speedvalue').value = obj.value;
    await sendOperate("train", "train", "speed", parseInt(obj.value) + 50);
}

WebRTC (Skyway) による配信

ユーザーが遠隔で制御できているか確認をするためには中継する映像が必要になります。 初めはYouTubeライブなどで良いかな、と考えていましたが少し遅延があるためリアルタイムで操作している感覚を出すためにも低遅延な配信が必要になりました。

困っていたところ、たこやき君からSkyWayというWebRTC(Web Real Time Communication)のAPIがあることを教えてもらい、組み込んでみることにしました。 とりあえずチュートリアル通りに実装しテストしてみたところ、自分の環境では1秒未満の遅延(ほぼ0に近い結果)となり、これは早い!ということで採用しました。

SkyWayではPeerIDと呼ばれる電話番号にあたるものを取得することで通話をすることができます。 とはいえ、今回は配信が目的であり双方向に受信するつもりはないのでサーバー上に用意したPeerIDのリストを取得し、それを各ユーザーのブラウザで発信処理を行うことで実装しました。

js/main.js

let localStream;

// make peer
const peer = new Peer({
    key: <API key>,
    debug: 3
});

// get peer id
peer.on('open', () => {
    // get server id here
    const theirID = /* server id */ peer.id;
    const mediaConnection = peer.call(theirID, localStream);
    setEventListener(mediaConnection);
});

// 発信処理
function makeCall(theirID) {
    const mediaConnection = peer.call(theirID, localStream);
    setEventListener(mediaConnection);
};

// イベントリスナを設置する関数
const setEventListener = mediaConnection => {
    mediaConnection.on('stream', stream => {
        // video要素にカメラ映像をセットして再生
        const videoElm = document.getElementById('video')
        videoElm.srcObject = stream;
        videoElm.play();
    });
}

// 着信処理
peer.on('call', mediaConnection => {
    mediaConnection.answer(localStream);
    setEventListener(mediaConnection);
});

peer.on('error', err => {
    alert(err.message);
});

peer.on('close', () => {
    alert('Connection closed.')
})

...(省略)

const vue = new Vue({

    ...(省略)

    mounted:function(){
        const url = 'https://us-central1-koken-key.cloudfunctions.net/referPeerid';

        fetch(url)
        .then(function (data) {
            return data.json(); // 読み込むデータをJSONに設定
        })
        .then(function (json) {
            this.camera_peerids = json
        });

        loadOperators();
    },
    watch:{
        selected_station:function(selected_station){
            makeCall(camera_peerids[selected_station].peer_id)
        }
    }
});

...(省略)

駅を選択するとサーバーからPeerIDを取得し、そのIDに対して発信処理を行うことで映像を取得できます。

小ネタ

  • 操作部の枠は京王カラーの二重枠線です。疑似要素のafterを用います。

main.css

#imagebox {
    padding-top: 17.1%;
    padding-bottom: 17.1%;
    border: 5px ridge #dd0076;
    background-color: white;
}

#imagebox::after {
    content: "";
    border: 5px ridge #000088;
    position: absolute;
    top: 5px;
    left: 5px;
    width: calc(100% - 10px);
    height: calc(100% - 10px);
}
  • ツイートしたときにサムネイルが出たりするとよさそう、みたいな意見を後輩からもらったので実装してみました。OGP(Open Graph Protocol)と呼ばれるものです。上の特設サイトへのリンクのように説明文やサムネイル画像が表示されています。

改善点とか反省とか

自動制御パートは完成していましたが遠隔操作部で引っかかってしまい初日は間に合わせられませんでした。 当日のYouTubeライブはやっていたのでデスマ中の部員が配信される事態に、、本当にすみませんでしたm(_ _)m

個人的なUIの設計についてだとやはり少し味気なさを感じるデザインだったかな、とは思いました。 ただあれ以上装飾したりしてもかえって見づらくなって微妙そうなので正直悩ましい感じでした。 それよりは操作の同期等はもちろん、速度調整バーを大きくしたり操作部の全景画像を見やすくしたりすべきといった改善点があったので、次にこのような機会があればよりフレンドリーなUIを設計出来るようになりたいと思いました。

おわりに

こうやって記事書いているとバーチャルでもそれを生かした展示ができたのですごく楽しかったなあって思い出してます。 ただやっぱり次回はいつもの調布祭がいいですね

明日はpof君のWebAPIまわりのお話になります。正直私とは桁違いにつよつよでWebUIのも半分くらいは彼(とたこやき君)のおかげだったりするので期待したいですね。

*1:リアルタイムの処理にする場合onchangeではなくoninputを用います

Hyper-V 仮想スイッチマネージャ―が開かないエラー

Hyper-Vを使って仮想化するぞ~と思ってごちゃごちゃしていたら仮想スイッチマネージャーが開かなくなってしまいました。操作しようとして表示されるエラーが

仮想スイッチの一覧の取得中にエラーが発生しました

仮想化におけるエラーらしくエラーがWSL2やDocker Desktopへ波及してしまい作業環境がまともに機能しない・・・

試したこと

  • ネットワーク設定のリセット。PowerShellから「netcfg -d」とするとネットワーク構成をクリア -> 再起動してもだめそう
  • Windowsの機能の有効化または無効化から「Hyper-V」のチェックを外し再起動 -> 再度チェックを入れ再起動でも変わらず
  • BIOSの設定も見直してみましたがそもそも「Intel(R) Virtualization Technology」の項目が見当たらず(CPU自体は仮想化可能なものなのでおそらくHyper-V仮想化の影響で項目が出てこない?)

英語のソースを一通り漁ってもめぼしい解決策は見当たらず、とはいえ作業で必要になってくるものなので最悪OSの再インストール等も考えましたが・・・

解決策

機能を無効化するべきところが足りなかったみたいです。 私の場合「Hyper-V」のほかに「LinuxWindowsサブシステム」、「Windowsサンドボックス」、「Windowsハイパーバイザープラットフォーム」、「仮想マシンプラットフォーム」にもチェックがついていたのでそれらも外して再起動 -> チェック入れなおして再起動したところ復旧できました。

参考にしたサイト

ameblo.jp

social.technet.microsoft.com

2年次の授業を振り返る

はじめに

個人の感想です。この情報を真に受けたことによって生じた不利益に対する責任は負いません。またこの記事は予告なく公開が停止されるかもしれません。

軽い自己紹介とか

おはこんばんちは、すてありん(@Stearinrin)です。UEC18でⅡ類のセキュに所属しています。書くネタがないので昨年度受けた授業を覚えている内に振り返ってみたいと思います。今年度はいろいろとイレギュラーな部分が多いのもあるのであまり参考にならないかもしれませんが、情報収集の一助になれば幸いです。

また、教員の名前は一応伏せておきます。知りたい方がいれば適宜連絡してください。

前期

月曜2限 - 基礎演習A … 専門・類共通・必修

その名の通り演習形式の授業でした。毎回の授業で後述の応用数学A・基礎電磁気学・基礎電気回路の演習問題が各回で配られ、それを解きます(3科目を5回ずつ)。成績もその結果で決まるので欠席するとなかなかしんどいことになるかもしれません。応用数学Aのときは昼休み終了までに解き切ればOK、とすこし緩めでした。

月曜3限 - 応用数学A … 専門・類共通・必修

スライドで講義が進みます。ただしそのスライドは公開されないので適宜ノートをとる必要がありました。 内容としてはフーリエ級数展開フーリエ変換ラプラス変換など。はじめは苦戦すると思いますが、回を重ねていくうちに少しずつ分かるようになるかもしれません。試験後、教員のサイトで成績優秀者を確認できます。

火曜1限 - 離散数学 ... 専門・類共通・選択

楽しい授業でした。初めの15分で前回の復習、最後の15分で講義の振り返り問題を解いて提出します。出席もその振り返り問題で取ります。サイトで振り返り問題の解答と宿題に当たる挑戦問題が公開されます。挑戦問題は出さなくても提出しなくても大丈夫(だったはず)ですが、毎回出せば良い成績が見込まれるかと思います。大人数のため試験はマーク式でした。

火曜2限 - Academic English for the Second Year Ⅰ … 総合・言語文化・応用Ⅰ

授業初回で教員ガチャを引きます。私が受けたのでは、テキストはなく毎回プリントが配られる形式でした。 内容としてはASEとAWEのミックスと形容できます。プレゼンは計三回あり、それぞれ数人のグループを作ってその内で発表する形式でした。作文も言われた形式を守ればおそらく問題ないはずです。

火曜4限 - 基礎電磁気学 … 専門・類共通・必修

板書をノートでとり、毎回の授業後確認テストをやる形式です。確認テストは基本時間が足りなくなります(解き切れるだけでも大分有利かも)。出席はごまかせません。今迄やってきた物理の電磁気に数学の概念を取り入れた話をします。微積分と線形代数の復習を多少でもやっておくと取り組みやすいかもしれません。正直かなり苦戦しました。

水曜3,4限 - 数値解析およびプログラミング演習 ... 専門・類共通・必修

C言語のプログラムにちょこっと書き加えて数値解析のアルゴリズムを実装する感じです。数値の精度へ重点を置くので人によってはつまらなく感じる人もいるかもしれません。不安があるなら基礎プロのC言語を復習しておくとよいでしょう。レポートはテキスト形式。

水曜5限 - 政治学A … 総合・人文

全15回の内5回出欠確認を兼ねた質問シートの提出をします。出席の点数配分は1割。残りは期末テスト一発勝負です。一か月前くらいに試験の例題が配られるので、それらを解けば単位取得に関しては問題ないと思います。Aの内容としては民主主義や自由主義、権力といった概念の理論的な部分を扱います。

金曜2限 - 基礎電気回路 … 専門・類共通・必修

回路の電圧値や電流値を微積分や行列の知識を駆使して計算していく授業です。中盤から複素数極座標が登場します。とにかく計算が多いのでひたすら解いて練習するのが吉です。

夏季集中

経済学A … 総合・人文

経済学というよりは経済の歴史を学んでいくような授業でした。受けたら株が読める、とかそういうものではないです。記述式(4題)のテストでした。結構成績の判定は渋いかもしれません。

法学A … 総合・人文

講義の内容をちゃんと聞いて必要に応じてメモをとっておくのがとにかく重要になると思います。最終日のテスト(穴埋め+記述)ではテキストの持ち込み可(だったはず)ですが、印刷されている内容をそのまま見返すだけではかなり単位は怪しいと思った方が良いです(私もかなり危うかったので…)。

後期

火曜1限 - UEC Academic Skills Ⅰ (Computer Literacy) … 総合・言語文化・演習(国際科目)

穴場科目。留学生に交じってコンリテの内容の授業を英語でやります。2年生までに取れれば英語演習と同じ扱いの単位となります。エディタはEmacs…ではなくViを推奨されます。最後に総合課題としてグループでウェブページを作成しますが、コンリテの単位を取っているならばどうにかなると思います。

火曜2限 - Academic English for the Second Year Ⅱ … 総合・言語文化・応用Ⅰ

形式としては前期とほぼ変わりません。ほかのクラスではアンケート調査を行って結果を分析したりするみたいでしたが、私が受けたクラスではありませんでした。作文を期限の1週間前に提出すれば良い成績が見込めるかもしれません。

火曜4限 - 計算機アーキテクチャ― … 専門・類専門・選択

2の補数から始まり、論理回路や命令セット、パイプライン処理、キャッシュ、アウトオブオーダ処理などを学びます。基本情報技術者試験の内容と被るところがまあまああります。試験はマーク式で計3回ありました(シラバスにはレポート2回+試験1回と書かれていましたが…)。

水曜5限 - 政治学B … 総合・人文

Aと同じ形式で今度は議会・内閣・官僚制・選挙といったより具体的な内容が中心になります。基本的にはリアリスト・保守派の視点で授業が進行していきます。プリントだけ回収しても単位はどうにかなるかもしれませんが、個人的には出席して講義を受けた方が良いと思います。

金曜1,2限 - アルゴリズムとデータ構造及びプログラミング演習 … 専門・類共通・必修

数値計算の分野を扱った前期と異なり、ソートや木構造といったアルゴリズムが登場します。成績は全14回のレポート(形式自由)+期末テスト(記述式)で決まります。私のレポートはLaTeXで作成していました。作図の課題がそれなりに出てきたのでdraw.ioで作成していました。

金曜3限 - 数理統計 … 専門・類専門・選択

1年後期の確率統計をまじめに取り組んでいなかったので結構苦労しました(念入りに復習しておく方が良いと思います)。毎回の授業前にテキストがサイト上で公開されるので印刷して準備しておきましょう。期末テスト一発勝負です。とりあえず過去問を何周か解いておくのが大事になると思います。

全体の感想

1年での内容がそれなりに関わってくるので、前もって準備しておくのが大切だな~という印象でした。特に微積と線形(+コンリテ・基礎プロ)は念入りに復習しておきましょう。セキュの2年次は1年のときより圧倒的にコマ数が少ないので気持ち楽に取り組めるはずです。