基本代码已经完成

有一说一,使用VScode写c++是真的难受,以后估计再也不会用了,还是Visual studio好用,方便调试和修改错误,长记性了。我建了如下的一个网络

现在我们来看看代码首先时main函数如下

#include <iostream>
#include <vector>
#include <random>


#include "Neuron.h"
#include "Synapse.h"
#include "Params.h"
#include "Manager.h"


int main()
{
    //设置网络  定义邻接表
    std::vector<std::vector<int>> adjList = { {1,2},{} };

    //实例化神经元


    // 创建随机数生成器
    std::random_device rd;
    std::mt19937 gen(rd());
    // 生成随机浮点数
    std::uniform_real_distribution<double> realDist(-65.0, -50.0);  // 生成范围为-65.0到-55.0的浮点数

    // 实例化神经元
    std::vector<Neuron> localNeuron;
    double v_init = realDist(gen);
    Neuron neuron1 = Neuron(v_init, 0);
    neuron1.set_I_offset(1.0);
    localNeuron.push_back(neuron1);

    Neuron neuron2 = Neuron(-65.0, 1);
    neuron2.set_I_offset(0.0);
    localNeuron.push_back(neuron2);

    Neuron neuron3 = Neuron(-65.0, 2);
    neuron3.set_I_offset(0.0);
    localNeuron.push_back(neuron3);

    //实例化突触
    int max_delay = 10;
    int min_delay = 15;

    std::vector<int> delays(2);
    delays[0] = min_delay;
    delays[1] = max_delay;

    std::vector<std::vector<Synapse>> localSynapse(adjList.size());

    for (int i = 0; i < adjList.size(); i++)
    {
        for (int j = 0; j < adjList[i].size(); j++)
        {
            localSynapse[i].push_back(Synapse(delays[j], 0.2, &localNeuron[adjList[i][j]]));
        }

    }
    
    //初始化 环形缓冲区
    Manager::kernel()->init_moduli(min_delay, max_delay);



    //设置仿真的参数
    double dt = 0.1; //时间戳

    double sim_time = 300; //仿真时间
    int slice = static_cast<int>(sim_time / min_delay);//总共要执行循环数
    int timespan = min_delay / dt;
    double current_time = 0;


    std::vector<SpikeEvent> spike_event;

    //开始仿真
    for (int timestep = 0; timestep < slice; timestep++)
    {
        Manager::kernel()->Print();

        //更新神经元
        for (auto node = localNeuron.begin(); node != localNeuron.end(); node++)
        {
            (*node).update(0, 10, spike_event);
        }

        // 传递脉冲
        for (int i = 0; i < spike_event.size(); i++)
        {
            int pre_gid = spike_event[i].source; // 前神经元脉冲的gid

            for (int j = 0; j < localSynapse[i].size(); j++)
            {
                localSynapse[i][j].send(spike_event[i]);//找到对应的突触将脉冲发送给后神经元
            }

        }

        spike_event.clear();  //清楚本回合的脉冲

        Manager::kernel()->update_moduli(min_delay, max_delay);

    }


    Manager::kernel()->delete_manager();
}

我重新设计了神经元

#ifndef NEURON_H
#define NEURON_H

#include<iostream>

#include "Params.h"
#include "Ringbuffer.h"

class Neuron
{
private:
    double v;               //膜电压
    double last_fired;      //上次发放脉冲的的时间
    int gid;                //神经元全局id
    double i_e;             //累加电流
    double dt;              //时间精度


    int ref_counter;        //不应期计时
    int RefractoryCounts;   //不应期的相对时常

    RingBuffer buffer;

    struct NeuronParams
    {
        // LIF神经元的参数
        float v_rest;			// 静息电位
        float v_reset;			// 重置电位
        float tau_m;			// 膜时间常数
        float refractory;       //不应期时间
        float c_m;				//膜电容
        float r_m;              //膜电阻
        float v_thresh;		   // 脉冲发放阈值
        float i_offset;	    // 注入电流
        float dt;

        /// @brief 初始化参数
        NeuronParams();
    };

    NeuronParams params;

    /// @brief 神经元的初始化操作
    /// @param v_init 初始电压
    void init(double v_init, int gid_);

public:

    /// @brief 有参构造函数
    /// @param gid_ 神经元的全局id
    Neuron(double v_init, int gid_);
    ~Neuron() = default;

    /// @brief 神经元更新的主要函数
    /// @param current_t 当前的时间
    /// @param spike_evnet 用来收集脉冲时间的,主要是发射脉冲的神经元和发射的时间
    void update(int from, int to, std::vector<SpikeEvent>& spike_evnet);

    /// @brief 处理脉冲事件
    /// @param se 脉冲事件
    void handle(SpikeEvent se);

    /// @brief 设置输入电流
    /// @param i_offset_ 
    void set_I_offset(double i_offset_);

    double getVoltage();

};


Neuron::NeuronParams::NeuronParams()
    :tau_m(10.0f),
    refractory(2.0f),
    v_rest(-45.0f),
    v_thresh(-50.0f),
    v_reset(-65.0f),
    i_offset(0.95f),
    c_m(0.250f),
    r_m(40.0f),
    dt(0.1)
{
}


Neuron::Neuron(double v_init, int gid_)
{
    init(v_init, gid_);
}

void Neuron::init(double v_init, int gid_)
{

    v = v_init;
    i_e = params.i_offset;
    last_fired = -params.refractory;
    gid = gid_;
    dt = params.dt;
    buffer.resize(15);
    RefractoryCounts = params.refractory / dt;
    ref_counter = 0;

}

void Neuron::update(int from, int to, std::vector<SpikeEvent>& spike_evnet)
{
    for (int lag = 0; lag < to; ++lag)
    {

        if (ref_counter == 0)
        {
            //神经元不在不应期
            //v += dt * ((params.v_rest - v + i_e * params.r_m)/params.tau_m);
            double v_inf = params.v_rest + i_e * params.r_m;
            v = v_inf + (v - v_inf) * expf(-dt / params.tau_m);
        }
        else
        {
            ref_counter--;
        }
        //计算突触的电流
        double i_syn = buffer.get_value(0);
        i_e = i_syn + params.i_offset;


        if (v > params.v_thresh)
        {
            SpikeEvent se;
            se.source = gid;
            se.stamp = lag;
            spike_evnet.push_back(se);
            printf("%d spike happenned in %d\n", gid, lag);
            ref_counter = RefractoryCounts;
            v = params.v_reset;
        }


    }
}

void Neuron::handle(SpikeEvent se)
{
    buffer.add_value(se.index, se.weight);
}

void Neuron::set_I_offset(double i_offset_)
{
    params.i_offset = i_offset_;
}

double Neuron::getVoltage()
{
    return v;
}
#endif

运行结果如下

如今实现之前双缓冲机制了,但是缺乏相关工作的验证,我是这样计划的。我需要设计一个全局的时间类,以用来验证脉冲是否在指定的延迟传送到了后神经元。还有就是我对,整体的有些参数感觉不太好,比如最大和最小延迟啊,他其实需要在全局能够访问的。还有就是设计的这个单例模式是线程不安全的,因为暂时没有设计到多进程,所以暂时不需要更改。理一下思路就是需要做一个时间的类。要做的东西好多啊,但是一步一步来吧,加油。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值