0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Unityで行動分析 ~その4:反応率分化強化スケジュール編~

Last updated at Posted at 2021-02-27

1. はじめに

  準備編 で作成した Operandum1 の Script を編集して、時間スケジュールを作成します。基本的なことは準備編で一通り解説しているので、本記事では Operandum1 の Script の解説のみとなります。また、今回も「オペランダムへの反応」→「得点上昇」と「強化オペランダムへの反応」→「得点上昇」の2つの場合を考慮して解説したいと思います。

2. 反応率分化強化スケジュールとは

 反応率分化強化スケジュールは、反応形成において反応を変容する手続きです。本記事では反応間時間 ( IRT ) を分化強化の対象とする反応型の分化強化スケジュールとして、低反応率分化強化スケジュール ( Differential reinforcement of low rate; DRL )と高反応率分化強化スケジュール ( Differential reinforcement of high rate; DRH )の2つを解説します。

2.1. DRLとは

 DRLとは、「IRTがある値を超えた後の最初の反応に強化子が随伴する(坂上・井上, 2018, pp175)」強化スケジュールです。もしその値以内で反応した場合は、再びその時点からIRTが計測されます。無反応での一定時間の経過が強化の必要条件となっています。
 Unityで作成する場合は、弁別刺激点灯時に限り反応はいつでも受けつけるけれど、スケジュール値 ( x sec ) を超過してから反応しなければ強化子を得られない ( あるいは Ramp が点灯しない ) ようにすれば良いです。また、スケジュール値 ( x sec ) 経過中に反応してしまうと時間を0にリセットするよう設定します。

2.2. DRHとは

 DRHとは、DRLの逆にあたる強化スケジュールで(坂上・井上, 2018)、スケジュール値よりも短い時間での反応に強化子が随伴する強化スケジュールです(Ono & Iwabuchi, 1997)。もしスケジュール値以上で反応した場合は、再びその時点からIRTが計測されます。
 Unityで作成する場合は、弁別刺激点灯時に限り反応はいつでも受けつけるけれど、反応がスケジュール値 ( x sec ) 未満でなければ強化子を得られない ( あるいは Ramp が点灯しない ) ようにすれば良いです。また、スケジュール値 ( x sec ) 以降に反応してしまうと時間を0にリセットするよう設定します。

3. DRL

3.1. 「オペランダムへの反応」→「得点上昇」

 Script の内容は下記のとおりです。ちなみに、「// New」の下に書かれてあるコードは、準備編の Operandum1 の Script にはなかったコードです。

Operandum1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Operandum1_Script : MonoBehaviour
{
    int Point = 1;
    public GameObject Sd1_off;
    public GameObject Sd1_on;
    public Text CountText;
    public AudioClip PointSE;
    AudioSource audioSource;

    //New
    float time;
    public float DRL;
    public AudioClip Operandum1SE;


    void Start()
    {
        audioSource = GetComponent<AudioSource>();
    }


    // New
    void Update()
    {
        if (Sd1_on.activeSelf)
        {
            time += Time.deltaTime;
            if (Input.GetKeyDown(KeyCode.F))
            {
                audioSource.PlayOneShot(Operandum1SE);
                if (time > DRL)
                {
                    audioSource.PlayOneShot(PointSE);
                    CountText.text = "Point : " + Point.ToString();
                    Point += 1;
                    time = 0;
                }
                else
                {
                    time = 0;
                }
            }
        }

        if (Sd1_off.activeSelf)
        {
            time = 0;
        }
    }
}

 このScriptの流れをざっくり書くと、変数の宣言 → Start() → Update()となります。解説は「// New」と書かれている箇所のみ行います。

変数の宣言

  • float time; ... float型の変数 time を宣言
  • public float DRL; ... public な float型の変数 DRL を宣言

    → Editor上ではDRLのスケジュール値を入れてください
  • public AudioClip Operandum1SE; ... public な AudioClip として Operandum1SE を宣言

    → Editor上では Operandum1 に反応したときに鳴るSEを入れてください

Update()

  • **「if (Sd1_on.activeSelf)」**の処理 ... Sd1_on がアクティブな時(弁別刺激点灯時)の処理
    • 弁別刺激が点灯したら制限時間をカウントアップ形式で作成
    • **「if (Input.GetKeyDown(KeyCode.F))」**の処理 ... キーボードのFキーが押されたときの処理
      • 効果音( Operandum1SE )が鳴る
      • **「if (time > DRL)」**の処理 ... timeがDRLのスケジュール値を超過したときの処理
        • 効果音( PointSE )が鳴る
        • 得点が1点上昇( Point += 1; )
        • time を0にリセット

          → 得点が上昇すると時間がリセットされ、もう一度時間を計測しはじめる

          → 弁別刺激が点灯している間、DRLが走り続ける
      • **「else」**の処理 ... timeがDRLのスケジュール値を超過したとき以外の処理
        • time を0にリセット

          → オペランダムに反応すると時間がリセットされ、もう一度時間を計測しはじめる

3.2. 「強化オペランダムへの反応」→「得点上昇」

 Script の内容は下記のとおりです。ちなみに、「// New」の下に書かれてあるコードは、準備編の Operandum1 の Script にはなかったコードです。

Operandum1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Operandum1_Script : MonoBehaviour
{
    public GameObject Sd1_off;
    public GameObject Sd1_on;
    public GameObject Ramp_off;
    public GameObject Ramp_on;
    public AudioClip Operandum1SE;
    AudioSource audioSource;
    GameObject Ramp;
    Ramp_Script Ramp_Script;

    //New
    float time;
    public float DRL;


    void ResetTime()
    {
        time = 0;
    }


    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        Ramp = GameObject.Find("Ramp");
        Ramp_Script = Ramp.GetComponent<Ramp_Script>();
    }

    
    void Update()
    {
        // New_1
        if (Sd1_on.activeSelf)
        {
            time += Time.deltaTime;
            if (Input.GetKeyDown(KeyCode.F))
            {
                audioSource.PlayOneShot(Operandum1SE);

                // New_2
                if (time > DRL)
                {
                    Ramp_off.SetActive(false);
                    Ramp_on.SetActive(true);
                    Invoke("ResetTime", Ramp_Script.ReinforceableTime);
                }

                else
                {
                    time = 0;
                }
            }
        }

        if (Sd1_off.activeSelf)
        {
            time = 0;
            Ramp_off.SetActive(true);
            Ramp_on.SetActive(false);
        }
    }
}

 このScriptの流れをざっくり書くと、変数の宣言 → Start() → Update()となります。解説は「// New」と書かれている箇所のみ行います。

変数の宣言

  • float time; ... float型の変数 time を宣言
  • public float DRL; ... public な float型の変数 DRL を宣言

    → Editor上ではDRLのスケジュール値を入れてください

Update()

  • New_1
    • **「if (Sd1_on.activeSelf)」**の処理 ... Sd1_on がアクティブな時(弁別刺激点灯時)の処理
      • 弁別刺激が点灯したら制限時間をカウントアップ形式で作成
      • **「if (Input.GetKeyDown(KeyCode.F))」**の処理 ... キーボードのFキーが押されたときの処理
        • 効果音( Operandum1SE )が鳴る
  • New_2
    • **「if (time > DRL)」**の処理 ... timeがDRLのスケジュール値を超過したときの処理
      • Ramp_off を非アクティブ化、Ramp_on をアクティブ化

        → 疑似的に強化可能ランプの点灯を表現
      • Invoke("ResetTime", Ramp_Script.ReinforceableTime)

        → 強化可能ランプ点灯時から強化可能時間が経過すると、time を0にリセット
      • **「else」**の処理 ... timeがDRLのスケジュール値を超過したとき以外の処理
        • time を0にリセット

          → オペランダムに反応すると時間がリセットされ、もう一度時間を計測しはじめる

4. DRH

4.1. 「オペランダムへの反応」→「得点上昇」

 Script の内容は下記のとおりです。ちなみに、「// New」の下に書かれてあるコードは、準備編の Operandum1 の Script にはなかったコードです。

Operandum1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Operandum1_Script : MonoBehaviour
{
    int Point = 1;
    public GameObject Sd1_off;
    public GameObject Sd1_on;
    public Text CountText;
    public AudioClip PointSE;
    AudioSource audioSource;

    //New
    float time;
    public float DRH;
    public AudioClip Operandum1SE;


    void Start()
    {
        audioSource = GetComponent<AudioSource>();
    }


    // New
    void Update()
    {
        if (Sd1_on.activeSelf)
        {
            time += Time.deltaTime;
            if (Input.GetKeyDown(KeyCode.F))
            {
                audioSource.PlayOneShot(Operandum1SE);
                if (time < DRH)
                {
                    audioSource.PlayOneShot(PointSE);
                    CountText.text = "Point : " + Point.ToString();
                    Point += 1;
                    time = 0;
                }
                else
                {
                    time = 0;
                }
            }
        }

        if (Sd1_off.activeSelf)
        {
            time = 0;
        }
    }
}

 このScriptの流れをざっくり書くと、変数の宣言 → Start() → Update()となります。解説は「// New」と書かれている箇所のみ行います。

変数の宣言

  • float time; ... float型の変数 time を宣言
  • public float DRH; ... public な float型の変数 DRH を宣言

    → Editor上ではDRHのスケジュール値を入れてください
  • public AudioClip Operandum1SE; ... public な AudioClip として Operandum1SE を宣言

    → Editor上では Operandum1 に反応したときに鳴るSEを入れてください

Update()

  • **「if (Sd1_on.activeSelf)」**の処理 ... Sd1_on がアクティブな時(弁別刺激点灯時)の処理
    • 弁別刺激が点灯したら制限時間をカウントアップ形式で作成
    • **「if (Input.GetKeyDown(KeyCode.F))」**の処理 ... キーボードのFキーが押されたときの処理
      • 効果音( Operandum1SE )が鳴る
      • **「if (time < DRH)」**の処理 ... timeがDRHのスケジュール値未満だったときの処理
        • 効果音( PointSE )が鳴る
        • 得点が1点上昇( Point += 1; )
        • time を0にリセット

          → 得点が上昇すると時間がリセットされ、もう一度時間を計測しはじめる

          → 弁別刺激が点灯している間、DRHが走り続ける
      • **「else」**の処理 ... timeがDRHのスケジュール値未満だったとき以外の処理
        • time を0にリセット

          → オペランダムに反応すると時間がリセットされ、もう一度時間を計測しはじめる

4.2. 「強化オペランダムへの反応」→「得点上昇」

 Script の内容は下記のとおりです。ちなみに、「// New」の下に書かれてあるコードは、準備編の Operandum1 の Script にはなかったコードです。

Operandum1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Operandum1_Script : MonoBehaviour
{
    public GameObject Sd1_off;
    public GameObject Sd1_on;
    public GameObject Ramp_off;
    public GameObject Ramp_on;
    public AudioClip Operandum1SE;
    AudioSource audioSource;
    GameObject Ramp;
    Ramp_Script Ramp_Script;

    //New
    float time;
    public float DRH;


    void ResetTime()
    {
        time = 0;
    }


    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        Ramp = GameObject.Find("Ramp");
        Ramp_Script = Ramp.GetComponent<Ramp_Script>();
    }

    
    void Update()
    {
        // New_1
        if (Sd1_on.activeSelf)
        {
            time += Time.deltaTime;
            if (Input.GetKeyDown(KeyCode.F))
            {
                audioSource.PlayOneShot(Operandum1SE);

                // New_2
                if (time < DRH)
                {
                    Ramp_off.SetActive(false);
                    Ramp_on.SetActive(true);
                    Invoke("ResetTime", Ramp_Script.ReinforceableTime);
                }

                else
                {
                    time = 0;
                }
            }
        }

        if (Sd1_off.activeSelf)
        {
            time = 0;
            Ramp_off.SetActive(true);
            Ramp_on.SetActive(false);
        }
    }
}

 このScriptの流れをざっくり書くと、変数の宣言 → Start() → Update()となります。解説は「// New」と書かれている箇所のみ行います。

変数の宣言

  • float time; ... float型の変数 time を宣言
  • public float DRH; ... public な float型の変数 DRH を宣言

    → Editor上ではDRHのスケジュール値を入れてください

Update()

  • New_1
    • **「if (Sd1_on.activeSelf)」**の処理 ... Sd1_on がアクティブな時(弁別刺激点灯時)の処理
      • 弁別刺激が点灯したら制限時間をカウントアップ形式で作成
      • **「if (Input.GetKeyDown(KeyCode.F))」**の処理 ... キーボードのFキーが押されたときの処理
        • 効果音( Operandum1SE )が鳴る
  • New_2
    • **「if (time < DRH)」**の処理 ... timeがDRHのスケジュール値未満だったときの処理
      • Ramp_off を非アクティブ化、Ramp_on をアクティブ化

        → 疑似的に強化可能ランプの点灯を表現
      • Invoke("ResetTime", Ramp_Script.ReinforceableTime)

        → 強化可能ランプ点灯時から強化可能時間が経過すると、time を0にリセット
      • **「else」**の処理 ... timeがDRHのスケジュール値未満だったとき以外の処理
        • time を0にリセット

          → オペランダムに反応すると時間がリセットされ、もう一度時間を計測しはじめる

4.3. x sec 間に n

 「2.2. DRHとは」では、DRHはスケジュール値よりも短い時間での反応に強化子が随伴する強化スケジュールと書きましたが、x sec 間に n 回反応すると強化子が随伴する場合もあるようです(e.g., 小野, 1994)。
 Unityで作成する場合は、弁別刺激点灯時に限り反応はいつでも受けつけるけれど、スケジュール値 ( x sec ) 未満かつ n 回反応しなければ強化子を得られない ( あるいは Ramp が点灯しない ) ようにすれば良いです。また、スケジュール値 ( x sec ) 以降に反応したり n 回に到達していない場合は、時間を0にリセットするよう設定します。

4.3.1. 「オペランダムへの反応」→「得点上昇」

Operandum1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Operandum1_Script : MonoBehaviour
{
    int Point = 1;
    public GameObject Sd1_off;
    public GameObject Sd1_on;
    public Text CountText;
    public AudioClip PointSE;
    AudioSource audioSource;

    //New
    float time;
    int Counter = 0;
    public float DRHTime;
    public float DRHTimes;
    public AudioClip Operandum1SE;


    void Start()
    {
        audioSource = GetComponent<AudioSource>();
    }


    // New
    void Update()
    {
        if (Sd1_on.activeSelf)
        {
            time += Time.deltaTime;
            if (Input.GetKeyDown(KeyCode.F))
            {
                audioSource.PlayOneShot(Operandum1SE);
                if (time < DRHTime)
                {
                    if (Counter == DRHTimes)
                    {
                        audioSource.PlayOneShot(PointSE);
                        CountText.text = "Point : " + Point.ToString();
                        Point += 1;
                        time = 0;
                        Counter = 0;
                    } 

                }

                else
                {
                    time = 0;
                    Counter = 0;
                }
            }
        }

        if (Sd1_off.activeSelf)
        {
            time = 0;
            Counter = 0;
        }
    }
}

4.3.2. 「強化オペランダムへの反応」→「得点上昇」

Operandum1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Operandum1_Script : MonoBehaviour
{
    public GameObject Sd1_off;
    public GameObject Sd1_on;
    public GameObject Ramp_off;
    public GameObject Ramp_on;
    public AudioClip Operandum1SE;
    AudioSource audioSource;
    GameObject Ramp;
    Ramp_Script Ramp_Script;

    //New
    float time;
    public float DRHTime;
    public float DRHTimes;
    int Counter = 0;


    void ResetTime()
    {
        time = 0;
        Counter = 0;
    }


    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        Ramp = GameObject.Find("Ramp");
        Ramp_Script = Ramp.GetComponent<Ramp_Script>();
    }


    void Update()
    {
        // New_1
        if (Sd1_on.activeSelf)
        {
            time += Time.deltaTime;
            Debug.Log(time);
            if (Input.GetKeyDown(KeyCode.X))
            {
                audioSource.PlayOneShot(Operandum1SE);
                Counter += 1;

                // New_2
                if (time < DRHTime)
                {
                    if (Counter == DRHTimes)
                    {
                        Ramp_off.SetActive(false);
                        Ramp_on.SetActive(true);
                        Invoke("ResetTime", Ramp_Script.ReinforceableTime);
                    } 
                }
                else
                {
                    time = 0;
                    Counter = 0;
                }
            }
        }

        if (Sd1_off.activeSelf)
        {
            time = 0;
            Counter = 0;
            Ramp_off.SetActive(true);
            Ramp_on.SetActive(false);
        }
    }
}

5. 最後に

 「反応率分化強化スケジュール」の中の、「低反応率分化強化(Differential Reinforcement of Low rates)」と「低反応率分化強化(Differential Reinforcement of High rates)」をUnityで作る方法の解説を行いました。コードや用語等で間違っている点があれば、ご指摘いただけると幸いです。

参考URL

・NumPy, randomで様々な種類の乱数の配列を生成
https://note.nkmk.me/python-numpy-random/

・Unity で CSV ファイルを読み込む方法
https://note.com/macgyverthink/n/n83943f3bad60

・【Unity】C#の基本構文『for』
http://kimama-up.net/unity-for/

引用文献

小野 浩一 (1994). 迷信行動と言語. 駒澤社会学研究, 26, 59-84.

Ono K, & Iwabuchi K. (1997). Effects of histories of differential reinforcement of response rate on variable-interval responding. Journal of the Experimental Analysis of Behavior. 67(3), 311–322.

坂上 貴之・井上 雅彦 (2018). 行動分析学──行動の科学的理解をめざして── 有斐閣

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?