如何对复杂网络建模所需要的数据进行预处理

上一篇文章介绍了如何构建Space L实体网络的模型,这一篇是对上一篇文章的一个补充优化。

以下部分摘自上一篇文章:如何建立复杂网络实体网络的Space L模型

地铁网络,一般都有三四百个节点,线路十几条左右,看地铁图的是一个眼花缭乱。若是人工统计出来数据也是一项大工程。看着就想放弃,但其实掌握一定的方法并没有那么的费劲。

  1. 按线路进行节点的统计,先编号,然后去除掉重合的节点
  2. 统计连接关系时有一定的规则:比如从左往右统计、从上往下统计,这样可以避免重复统计
  3. 不要直接列出邻接矩阵,先统计出连接关系生成邻接表,然后再转成邻接矩阵
  4. 关于邻接表,最好再检查一遍
  5. 以上工作最好分成数天进行,否则负荷工作效率低且出错率较高

可以看到,建模时候最头疼的就是数据的处理问题,运用以上的经验可以提升我们的效率,但是治标不治本,依旧会浪费掉我们大量的时间。其实,如果不考虑换乘站(重复节点),连接关系还是比较好统计的,比如一条线路有10个站点,按顺序分别为a、b、c….j,那么连接关系可以表示为下图的1-9列:

线路转化邻接表

最近有一个需求,要统计某市的公交网络,有300多条线路,大概有3000多节点。如果此时还按之前的办法:人工统计线路中的站点,然后进行编号的话,那整个工程量不仅巨大,并且在统计过程中也很容易出错。

所以可以让程序帮助我们去识别站点名称,然后依次给它们编号,这样就可以生成直接使用邻接表。

具体处理方式,可以大概分为以下几个步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
% 1.从xls文件中,读取数据(或者直接新建数据)
% rawDataNum是读取到的数值,可以是权重,数据类型:double
% rawDataStr是读取到的字符串,是邻接表,数据类型:cell

% 2.用b接收rawDataStr中的所有不重复的字符串,数据类型 cell

% 3.因为cell类型矩阵中存储的是字符串数据,不好处理
% 所以需要把b和rawDataStr转换为string数组b_str和raw_str
% 注意这里可以检查一下b_str中的字符串

%4.进行数据处理
test = [];

for i = 1:length(b_str)
for j = 1:length(raw_str)
%判断条件
if(raw_str(j,1) == b_str(i,1))
test(j,1) = i;
end


%判断条件
if(raw_str(j,2) == b_str(i,1))
test(j,2) = i;
end

end
end
%这时就可以得到邻接表test

%判断是否为无权网络,判断标准rawDataNum是否为空,这与你的初始数据有关
if(length(rawDataNum) ~= 0)
test = [test rawDataNum];
else
disp('无权网络')
end

%这一步就是把邻接表test直接转换为邻接矩阵A,
%可以参照:如何建立复杂网络实体网络的Space L模型中的函数
A = ainc2adj( test );
% 判断是否有孤立节点
if(length(find(~sum(A))))
disp('存在孤立节点')
end

测试邻接表:

结果:

邻接表

节点编号与名称对应关系:

可以看到效果还是不错的,而且不仅限于交通网络。对于一些较大型的实体网络,比如作者合作网络、社交网络,应该也会有不错的效果。欢迎大家与我进行交流,

该文章首发于:XuXing’s blog

复杂网络相关内容可以访问:复杂网络

如何建立复杂网络实体网络的Space L模型

复杂网络是一个非常庞大的研究领域,有众多研究方法与研究对象,社交网络、科学家网络、生物网络、交通网络、生物网络等等。在进行仿真时候,有的网络过于庞大无法用实际的数据进行仿真,例如社交网络。而有一些网络规模较小,就需要用实际的数据进行仿真了,例如交通网络。

那么无论网络规模大小,对这些网络进行研究的时候,第一步往往是建模,只有模型建好了后续的研究、仿真才好进行下去。建模后,可以对网络指标进行分析,可以分析网络的抗毁性等等。总之,建模总是第一步的。

下面我就分享一下,自己对于复杂网络中实体网络建模的一些经验,以地铁网络为例:

建模方法,一般有Space L、Space P、Space B、Space C法,比较常用的建模规则是Space L法。

地铁网络,一般都有三四百个节点,线路十几条左右,看地铁图的是一个眼花缭乱。若是人工统计出来数据也是一项大工程。看着就想放弃,但其实掌握一定的方法并没有那么的费劲。

  1. 按线路进行节点的统计,先编号,然后去除掉重合的节点
  2. 统计连接关系时有一定的规则:比如从左往右统计、从上往下统计,这样可以避免重复统计
  3. 不要直接列出邻接矩阵,先统计出连接关系生成邻接表,然后再转成邻接矩阵
  4. 关于邻接表,最好再检查一遍
  5. 以上工作最好分成数天进行,否则负荷工作效率低且出错率较高

下面给出 邻接表 转成 邻接矩阵的matlab函数代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function b  = ainc2adj( x )
% x为邻接表(可在工作区中新建数据),输出的b为邻接矩阵
% 此函数是通过邻接表生成临接矩阵的
if min(x(:))==0;
x=x+1;
end
d=length(x);
a=max(max(x));
b=zeros(a,a);

for i=1:d
if x(i,1)==x(i,2);
b(x(i,1),x(i,2))=0;
else
b(x(i,1),x(i,2))=1;
b(x(i,2),x(i,1))=1;
end
end

一般来讲生成邻接矩阵,我们就得到了实体网络的节点连接情况。但我们都知道,人工统计的难免会有一些错漏,而这个时候需要用Gephi软件帮助我们进行进一步的检验。关于Gephi如何导入数据,可以参考这一篇文章。导入之后,你会得到一张拓扑图,如下图所示:

但是这样的图,我们没有办法看出网络可能存有什么问题,需要进一步的操作。

点击布局中的,选择一个布局。选择Force Atlas,选择运行,图会发生变化:

我们会发现红圈部分的点与整体网络没有任何联系,而交通网络是一个整体,那就说明这几个节点的连接关系一定都有问题。那么如何查看这几个点是哪几个点呢?点击预览,然后打开显示标签,最后点下方的刷新,就显示出来了节点标号。

然后可以用鼠标滚轮放大,调节左侧的节点编号显示的颜色,就可以大概看出来是那些节点出现问题了。然后回去对着连接图和节点编号去找就可以了

这个软件生成的图也是非常漂亮的,大家可以试一试,节点颜色、大小,边的颜色、大小,都可以自己调节,还有很多计算网络指标的功能。那么这次的分享就到这里,感谢大家的时间。

欢迎大家与我交流。

matlab实现随机攻击网络边+蓄意攻击网络连边(3)

其实在前面已经介绍过随机进攻节点和蓄意进攻节点的原理,今天和大家说一下边攻击。其实原理都是类似的,只要改动之前的一些代码就可以完成这个操作的。如果没有看过前两篇文章,那么建议你先看一下,有助于理解原理。

前两篇地址:

matlab实现随机攻击网络节点+蓄意攻击网络节点(1)附github完整工程地址

matlab实现随机攻击网络节点+蓄意攻击网络节点(2)

我们首先应该了解删除连边和删除的节点的区别:

删除节点:删除该节点及与该节点所有相连的边。

删除连边:只删除该连边,而不改变节点的状态。

如果结合维度为N*N邻接矩阵A来说:

删除节点a:要删除A(a,:)和A(:,a)这一列一行,矩阵A变为(N-1)*(N-1)维度

删除节点a和节点b的连边:A(a,b) = 0;A(b,a) = 0;(邻接矩阵的对称性),矩阵A还是N*N维度。

知道了具体逻辑,那么下面就是代码实现了:

之前我们删除节点的代码片段为:

1
2
3
4
5
6
7
8
9
10
for i = 1:numDelete
A( Name_Struct.Node_Key_Degree(i),: ) = 0; %% 删除节点 Node_Key_Degree(i),用 0 占位,不能置空
A( :,Name_Struct.Node_Key_Degree(i) ) = 0;
AA = A;
AA( sum(A)==0,: ) = [];
AA( :,sum(A)==0 ) = [];
Con_Index_NetEff = testEglob( AA );

Eglob(i) = Con_Index_NetEff.Net_Eff_Mymod;
end

边攻击需要的数据准备:

邻接表:也就是网络中的所有连边关系 也就是下面的代码片段中的 biao(2*edge_number的矩阵)
边的排序关系:(可以是随机排序,可以是按某种参数进行的排序)下面的代码片段中的Node_edge_bet(1*edge_number的矩阵),就是根据边介数参数得到的边的排序

那么改动后的边攻击代码片段为:

1
2
3
4
5
6
7
8
9
10
11
A = A_Init;          %% 网络邻接矩阵 A
% numDelete:删除连边的数量
for i = 1:numDelete
%把要删除的边置为0
A( biao(1,Node_edge_bet(i)),biao(2,Node_edge_bet(i)) ) = 0;
%把对称位置的边也置为0
A( biao(2,Node_edge_bet(i)),biao(1,Node_edge_bet(i)) ) = 0;
AA = A;
Con_Index_NetEff = testEglob( AA );
Eglob_edge_bet(i) = Con_Index_NetEff.Net_Eff;
end

经过分析之后,我们可以得到一个推测或者说是结论:那就是边攻击每次只攻击一个边,对网络的影响较小(相对于节点攻击来说)。

感谢大家的时间,并希望以上的内容会对大家有所帮助。

Veirlog学习记录-6-数字频率计的设计与实现(附完整工程)

FPGA的课程的大作业,我们选的是数字频率计设计。下面分享一下代码,还有工程文件,还有自己写的论文(里面会有更加详细的介绍),希望可以对你有所启发。

工程文件github地址

开发环境:Vivado 2015.4+Modelsim(仅用于仿真波形)
开发板:赛灵思公司 xc7a100tcsg324-1

总体设计要求:

  • 可测量脉冲信号的频率
  • 被测信号由100MHz的系统时钟分频获得,频率为学号*1000 Hz
  • 测量结果在6位数码管上显示,高位若是零则不显示该位
  • 采用连续测量方式,每4秒为1个周期,其中1秒用于测量,3秒用于显示

总体设计框图:

子模块设计:

- 分频模块:

结构图:
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
module div(
input clk_100mhz, //系统给定的时钟频率
output clk_190hz, //数码管的动态扫描频率
output reg clk_1Hz, //控制模块的驱动频率
output reg fin //输出待测试信号的频率
);
reg [9:0] cnt0;
reg [30:0] cnt;
reg [18:0] cnt1;

always @(posedge clk_100mhz)
cnt1 = cnt1 + 1;
assign clk_190hz = cnt1[18];
always @(posedge clk_100mhz)
if(cnt == 50000000) begin
cnt = 0;
clk_1Hz = ~clk_1Hz;
end
else
cnt = cnt + 1;
always @(posedge clk_100mhz)
if(cnt0 == 499) begin //生成的测试信号的频率为100KHz
cnt0 = 0;
fin = ~fin;
end
else
cnt0 = cnt0 + 1;

endmodule

被测频率本来要求是学号*1000Hz,但是我的学号无法被整除,所以无法度量频率计的的精度,更无法进行误差分析。所以才选取了100KHz作为测试频率。

- 控制模块

结构图:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
module control(clk_1Hz, rst, count_en, latch_en, clear);  
input clk_1Hz;
input rst; //复位信号
output count_en; //计数使能
output latch_en; //锁存使能
output clear; //清零信号
reg [2:0] state; //状态信号,用于控制各种使能信号
reg count_en;
reg latch_en;
reg clear;

always @(posedge clk_1Hz or negedge rst)
if(!rst) //复位信号有效
begin //各种使能信号清零
state <= 3'b000;
count_en <= 1'b0;
latch_en <=1'b0;
clear <= 1'b0;
end
else //遇到基准信号的下一个上升沿,状态变化一次,每次变化后状态持续1s
begin
case(state)
3'b000:
begin //第一个上升沿到达,开始计数,计数1个基准信号周期内待测信号的上升沿个数,此个数即为待测信号的频率
count_en <= 1'b1; //计数使能信号有效
latch_en <= 1'b0;
clear <= 1'b0;
state <= 3'b001;
end
3'b001:
begin //第二个上升沿到达,计数完成,锁存使能信号有效,测得频率锁存至锁存器中
count_en <= 1'b0;
latch_en <=1'b1;
clear <= 1'b0;
state <= 3'b010;
end
3'b010:
begin //第三个上升沿到达,计数完成,锁存使能信号有效,测得频率锁存至锁存器中
count_en <= 1'b0;
latch_en <=1'b1;
clear <= 1'b0;
state <= 3'b011;
end
3'b011:
begin //第四个上升沿到达,计数完成,锁存使能信号有效,测得频率锁存至锁存器中
count_en <= 1'b0;
latch_en <=1'b1;
clear <= 1'b0;
state <= 3'b100;
end
3'b100:
begin //第五个上升沿到达,清零使能信号有效,计数器清零,为下一次计数做准备
count_en <= 1'b0;
clear <= 1'b1;
latch_en <=1'b1;
state <= 3'b000; //状态清零,进入下一次测量
end
default:
begin
count_en <= 1'b0;
latch_en <=1'b0;
clear <= 1'b0;
state <= 3'b000;
end
endcase
end

1
endmodule

- 计数模块

结构图:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
module counter_10(en_in, rst, clear, fin, en_out, q);  
input en_in; //输入使能信号
input rst; //复位信号
input clear; //清零信号
input fin; //待测信号
output en_out; //输出使能,用于控制下一个计数器的状态,当输出使能有效时,下一个模10计数器计数加1
output [3:0] q; //计数器的输出,4位BCD码输出

reg en_out;
reg [3:0] q;

always@ (posedge fin or negedge rst) //输入待测信号的上升沿作为敏感信号
if(!rst) //复位信号有效,计数器输出清零
begin
en_out <= 1'b0;
q <= 4'b0;
end
else if(en_in) //进位输入使能信号有效
begin
if(q == 4'b1001) //若q = 4'b1001的话,q清零,同时进位输出使能有效,即en_out 赋值为1'b1
begin
q <= 4'b0;
en_out <= 1'b1;
end
else //若q未达到4'b1001时,每到达待测信号的一个上升沿,q加1,同时输出进位清零
begin
q <= q + 1'b1;
en_out <=1'b0;
end
end
else if(clear) //若清零信号有效,计数器清零,用于为下一次测量准备
begin
q <= 4'b0;
en_out <= 1'b0;
end
else
begin
q <= q;
en_out <=1'b0;
end

endmodule

锁存模块

结构图:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module latch(clk_1Hz, latch_en, rst, q0, q1, q2, q3, q4, q5, q6, q7,  
d0, d1, d2, d3, d4, d5, d6, d7);
input clk_1Hz, latch_en, rst;
input[3:0] q0, q1, q2, q3, q4, q5, q6, q7;
output[3:0] d0, d1, d2, d3, d4, d5, d6, d7;
reg[3:0] d0, d1, d2, d3, d4, d5, d6, d7;
always@ (posedge clk_1Hz or negedge rst)
if(!rst) //复位信号有效时输出清零
begin
d0 <= 4'b0; d1 <= 4'b0; d2 <= 4'b0; d3 <= 4'b0; d4 <= 4'b0;
d5 <= 4'b0; d6 <= 4'b0; d7 <= 4'b0;
end
else if(latch_en) //锁存信号有效时,将计数器的输出信号锁存至锁存器
begin
d0 <= q0; d1 <= q1; d2 <= q2; d3 <= q3; d4 <= q4;
d5 <= q5; d6 <= q6; d7 <= q7;
end
else //上面两种情况均未发生时,输入不变
begin
d0 <= d0; d1 <= d1; d2 <= d2; d3 <= d3; d4 <= d4;
d5 <= d5; d6 <= d6; d7 <= d7;
end

endmodule

显示模块

结构图:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
module IP_seg_disp(
input clk_190hz,
input [3:0] d0,d1,d2,d3,d4,d5,d6,d7
output reg [7:0] duan,
output reg [7:0] wei
);

reg [3:0] disp;
reg [2:0] smg_ctl;

always @ ( posedge clk_190hz)
smg_ctl = smg_ctl + 1'b1;
always @ (*)
case ( smg_ctl )
3'b000:begin
wei = 8'b11111110;
disp = d0 [3:0];
end
3'b001:begin
wei = 8'b11111101;
disp = d1 [3:0];
end
3'b010:begin
wei = 8'b11111011;
disp = d2 [3:0];
end
3'b011:begin
wei = 8'b11110111;
disp = d3 [3:0];
end
3'b100:begin
wei = 8'b11101111;
disp = d4 [3:0];
end
3'b101:begin
wei = 8'b11011111;
disp = d5 [3:0];
end
3'b110:begin
wei = 8'b10111111;
disp = d6 [3:0];
if( disp==0 ) //如果高位数值为0,则不显示该位
disp <=4'b1111;
end
3'b111:begin
wei = 8'b01111111;
disp = d7 [3:0];
if( disp==0 )
disp <=4'b1111
end
default:;
endcase

always @ ( * )
case (disp)
4'b0000:duan = 8'b11000000;
4'b0001:duan = 8'b11111001;
4'b0010:duan = 8'b10100100;
4'b0011:duan = 8'b10110000;
4'b0100:duan = 8'b10011001;
4'b0101:duan = 8'b10010010;
4'b0110:duan = 8'b10000010;
4'b0111:duan = 8'b11111000;
4'b1000:duan = 8'b10000000;
4'b1001:duan = 8'b10010000;
4'b1010:duan = 8'b10001000;
4'b1011:duan = 8'b10000011;
4'b1100:duan = 8'b11000110;
4'b1101:duan = 8'b10100001;
4'b1110:duan = 8'b10000110;
4'b1111:duan = 8'b11111111;
default:duan = 8'b11000000;
endcase
endmodule

顶层模块

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
module freDetect(clk_100mhz,rst,duan,wei);  
input clk_100mhz;
input rst; //复位信号
output [7:0] duan;
output [7:0] wei;
wire[3:0] q0, q1, q2, q3, q4, q5, q6, q7; //中间数据
wire[3:0] d0, d1, d2, d3, d4, d5, d6, d7;
wire fin;
wire clk_1Hz;
wire clk_190hz;
//分频模块实例
div u_div(
.clk_1Hz(clk_1Hz),
.clk_190hz(clk_190hz),
.clk_100mhz(clk_100mhz),
.fin(fin)
);
//显示模块实例
IP_seg_disp u_IP_seg_disp( .clk_190hz(clk_190hz), .d0(d0),
.d1(d1), .d2(d2), .d3(d3), .d4(d4),
.d5(d5), .d6(d6), .d7(d7),
.duan(duan), .wei(wei)
);
//控制模块实例
control u_control(.clk_1Hz(clk_1Hz), .rst(rst), .count_en(count_en),
.latch_en(latch_en), .clear(clear));

//计数器模块实例
counter_10 counter0(.en_in(count_en), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out0), .q(q0));
counter_10 counter1(.en_in(en_out0), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out1), .q(q1));
counter_10 counter2(.en_in(en_out1), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out2), .q(q2));
counter_10 counter3(.en_in(en_out2), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out3), .q(q3));
counter_10 counter4(.en_in(en_out3), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out4), .q(q4));
counter_10 counter5(.en_in(en_out4), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out5), .q(q5));
counter_10 counter6(.en_in(en_out5), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out6), .q(q6));
counter_10 counter7(.en_in(en_out6), .clear(clear), .rst(rst),
.fin(fin), .en_out(en_out7), .q(q7));

//锁存器模块实例
latch u_latch(.clk_1Hz(clk_1Hz), .rst(rst), .latch_en(latch_en),
.q0(q0), .q1(q1), .q2(q2), .q3(q3), .q4(q4), .q5(q5),
.q6(q6), .q7(q7), .d0(d0), .d1(d1), .d2(d2), .d3(d3),
.d4(d4), .d5(d5), .d6(d6), .d7(d7));

endmodule

测试文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
module freDetect_tb;  
parameter CLK_1HZ_DELAY = 50000000; //用于生成1Hz基准信号
parameter FIN_DELAY = 500; //用于生成100KHz待测信号
reg clk_1Hz;
reg fin;
reg rst; //复位
wire[3:0] d0, d1, d2, d3, d4, d5, d6, d7;
initial
begin
rst =1'b0;
#1 rst = 1'b1;
end
initial
begin
fin = 1'b0;
forever
#FIN_DELAY fin = ~fin;
end
initial
begin
clk_1Hz = 1'b0;
forever
#CLK_1HZ_DELAY clk_1Hz = ~clk_1Hz;
end
freDetect freDetect1(.clk_1Hz(clk_1Hz), .rst(rst), .fin(fin),
.d0(d0), .d1(d1), .d2(d2), .d3(d3), .d4(d4), .d5(d5), .d6(d6), .d7(d7));
endmodule

波形仿真结果如图所示:
结果显示
实验结果:

两张图片分别为 测量计数时和复位时和显示计数时:
测量计数时和复位时的显示显示计数时

我也写了几篇关于Veirlog的文章,感兴趣的同学可以去看看。该模块链接如下:
Verilog学习

Veirlog学习记录-5-循环移位数码管的设计与实现

实现功能:在开发板的数码管上显示特定数字,并且让这些数字循环移位。

总体框图如下:
总体框图

代码如下:

分频模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module div(
input clk, //输入自带的系统时钟(100Mhz)
input rst, //复位
output scan_clk //输出时钟,用于驱动数码管,让其动态扫描用
);
reg [19:0] clkdiv;

always @(posedge clk or posedge rst)
begin
if( rst == 1) clkdiv <=0;
else clkdiv <= clkdiv + 1;
end
assign scan_clk = clkdiv[15]; //使得san_clk = 190Hz
endmodule

其他模块(显示模块):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
module otherModel(
input rst,
input scan_clk,

output reg [7:0] an,
output reg [6:0] seg
);
reg [3:0] digit; //选择位上显示的数字
reg [2:0] cnt; //选择哪一位显示

always @(posedge scan_clk or posedge rst)
begin
if ( rst == 1) cnt <=0;
else cnt <=cnt + 1;
end

always @ (*)
begin
case ( cnt )
3'b000:begin digit = 4'b0000; an = 8'b01111111; end
3'b001:begin digit = 4'b0001; an = 8'b10111111; end
3'b010:begin digit = 4'b0010; an = 8'b11011111; end
3'b011:begin digit = 4'b0011; an = 8'b11101111; end
3'b100:begin digit = 4'b0100; an = 8'b11110111; end
3'b101:begin digit = 4'b0101; an = 8'b11111011; end
3'b110:begin digit = 4'b0110; an = 8'b11111101; end
3'b111:begin digit = 4'b0111; an = 8'b11111110; end
default:begin digit= 4'b0000; an = 8'b01111111; end
endcase
end

always @ (*)
begin
case ( digit )
4'b0000:seg = 7'b0100100;
4'b0001:seg = 7'b1000000;
4'b0010:seg = 7'b1111001;
4'b0011:seg= 7'b0000000;
4'b0100:seg =7'b0100100;
4'b0101:seg =7'b1000000;
4'b0110:seg =7'b1111000;
4'b0111:seg =7'b0000000;
default: seg = 7'b0000001;
endcase
end



endmodule

顶层模块:

1
2
3
4
5
6
7
8
9
10
module top(
input clk,
input rst,
output [7:0] an,
output [6:0] seg
);

div u1(clk,rst,scan_clk); //例化模块
otherModel u2(rst,scan_clk,an,seg);
endmodule

测试文件:
注意:测试文件是针对otherModel文件的。在写测试文件之前,最好不要添加顶层模块,否则测试时会找不到想要测试的那个文件。如果,已经编写完了顶层模块,可以在design列表中,右键要测试的文件,然后点击 设置为顶层文件,这样就会测试到指定的文件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module otherModel_tb();
reg rst,scan_clk; //输入信号要用 reg型
wire [7:0] an; //输出信号要用 wire型
wire [6:0] seg; //输出信号

otherModel test(
.rst(rst),
.scan_clk(scan_clk),
.an(an),
.seg(seg)

);
initial fork
scan_clk = 0;
rst = 1; #50 rst = 0;
join

always #10 scan_clk = ~scan_clk; //定义没过10毫秒,信号就会进行翻转

endmodule

仿真波形如下:
仿真结果
我也写了几篇关于Veirlog的文章,感兴趣的同学可以去看看。该模块链接如下:
Verilog学习

matlab实现随机攻击网络节点+蓄意攻击网络节点(2)

更新:

有同学反馈说:网络效率的函数可能有点问题。可以试试这个网络效率函数,对应的部分改一下就可以了。

还有最大连通子图比例函数:最大连通子图比例函数




上一篇介绍了随机攻击网络节点与蓄意攻击节点的基本方法。上一篇文章地址:matlab实现随机攻击网络节点+蓄意攻击网络节点(1)

其中随机攻击的部分还有一些瑕疵,就是在实际的研究中,需要对网络进行多次(数十次甚至上百次)攻击后取指标变化平均值,这样的实验数据才具有一定的说服力。

其实这个问题乍一听起来,原理也比较简单:就是让一个程序运行指定的次数然后,累加程序中某一个变量后取平均值

实现起来也并不费劲,首先就是把这个程序定义为一个函数,然后把所需要累加的变量作为函数的返回值。然后在另一个文件中创建循环,在循环中调用该函数,用一个变量接收该函数的返回值,以达到累加的效果,最后在循环外部取一个平均值即可。

代码如下所示:

定义函数文件名称(该名称需要与函数名称相同)

函数的参数介绍:

输入值str:意为数据文件的路径;numDelete:删除节点的个数(这里的命名只是为了方便并不是必选项)
返回值Eglob,即网络效率值的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function Eglob = ATestAver(str,numDelete)
%输入 :
% str:意为数据文件的路径
% numDelete:删除节点的个数

%返回值:Eglob,即网络效率值的数组

%加载数据文件
load(str);

Name_Struct = Node_Key_Sort_Descend; % Name_Struct 数据集名称,更换网络数据集时,需要更改此处结构体名称
A_Init = Name_Struct.Adjacent_Matrix; %% 网络邻接矩阵
N_Init = size(A_Init,1); %% 节点个数

NetEff_Init = zeros(1,numDelete);
Struct_Init = struct('Deg',NetEff_Init);

% 初始网络性能
%生成随机数,以此进行随机攻
Name_Struct.Node_Key_Degree = randperm(440);

%%
% 按照 Degree 算法排序,删除节点
A = A_Init; %% 网络邻接矩阵 A
for i = 1:numDelete
% 按照 Degree 算法排序,删除节点
end

定义测试文件:

文件中需要定义随机攻击的次数和随机攻击节点的个数,具体参数设置应视具体网络而定。
在调用函数时,要传入文件路径,和删除节点的个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
%定义随机攻击节点的个数,具体数值根据网络规模拟定
numDelete = 22;

%定义网络效率初始矩阵
netSum = zeros(1,numDelete);

%定义随机攻击的次数,也就是函数循环的次数
numRandom = 50;
for i=1:numRandom

%把得到的网络效率数组赋给netI
netI = ATestAver('Data\12_15jiaQuanData.mat',numDelete);
%累加
netSum = netSum + netI;
end

%求出平均值
netAver = netSum/numRandom;

我的测试数据具有小世界特性与无标度特性。并得到了以下的结果:
例子
大家可以看出,经过多次随机攻击取指标平均值之后,曲线近似于一条直线,下降速率较小且符合实际的网络情况。验证了无标度网络对于随机攻击拥有较好的鲁棒性。

希望本文对大家有所帮助,有任何问题或者是建议,欢迎大家与我交流。

matlab实现随机攻击网络节点+蓄意攻击网络节点(1)附github完整工程地址

更新:

有同学反馈说:网络效率的函数可能有点问题。可以试试这个网络效率函数,对应的部分改一下就可以了。

还有最大连通子图比例函数:最大连通子图比例函数


在研究网络的鲁棒性的时候,我们往往会通过随机与蓄意攻击网络节点,观察网络效率的下降比例来进行网络特性的研究。

常见的指标有:最大连通子图比例、网络效率、平均距离等等。
这三个指标是不同的,但是实现随机攻击与蓄意攻击的原理是相同的,这里以按照节点度攻击的网络效率变化为例(其他两个指标就是函数不同,想按照其他节点重要度排序指标,也是类似的,只需要按照想要的排序方法得出节点的排序即可)。

就是按照节点的重要性排序,通过循环来删除节点。把临界矩阵中节点对应的行和列先置0,然后再删除。每删除一次节点,就生成了一个新的邻接矩阵,然后每一次都通过testEglob函数计算出当前的网络效率值。

首先需要准备的数据如下:

网络的邻接矩阵,节点度的排序(从大到小排名,度大的排名靠前)。

节点度的排名要按照节点的编号排序,下图是一个简单的例子,建议先在Excel中排列好了,然后再复制到Matlab中转置一下保存为mat文件就可以了。

度排序示例

明白了蓄意攻击的原理,那么随机攻击的原理也比较好理解了,蓄意攻击是按照节点重要度排序进行的攻击,那么随机攻击可以理解为给所有节点随机赋排名,所以攻击的时候就等效于随机攻击了。也就是说,在随机攻击时,你只需要在蓄意攻击的基础上添加一行代码,把度排序的数组赋值上长度相同的一个随机数组,即:

1
Name_Struct.Node_Key_Degree = randperm(440);

具体代码如下:

主函数: testRandom(命名随意。。。)
作用:原理挺简单的,就是通过循环来删除节点。把临界矩阵中节点对应的行和列先置0,然后再删除。每删除一次节点,就生成了一个新的邻接矩阵,然后每一次都通过testEglob函数计算出当前的网络效率值。

部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
% 蓄意攻击:按照节点重要性顺序,一次攻击一个节点

clc;
clear;


% 初始网络性能
%生成随机数,以此进行随机攻击(注释掉即为蓄意攻击),随机数值改为你自己网络的节点数
Name_Struct.Node_Key_Degree = randperm(440);

%%
% 按照 Degree 算法排序,删除节点
A = A_Init; %% 网络邻接矩阵 A
B=[]; %%定义空数组,接收被删除的节点序号

for i = 1:NumDelete
%% 删除节点 Node_Key_Degree(i),用 0 占位,不能置空
B(i) = Name_Struct.Node_Key_Degree(i);
Con_Index_NetEff = testEglob( AA );
Eglob(i) = Con_Index_NetEff.Net_Eff_Mymod;
end

%接下来就是生成网络连通效率图
%Eglob存储了相应的网络效率的数值

正常情况下,一次随机攻击并不能说明什么,一次随机攻击的数据也并不可靠,所以需要多次随机攻击之后取平均值,这样得出的数据才更具有说服力,下一篇将介绍如何实现,matlab实现随机攻击网络节点+蓄意攻击网络节点(2)

希望对大家有所帮助,有任何疑问欢迎与我交流,谢谢你的时间。

Veirlog学习记录(4)分频模块+层次化的模块设计

 前三篇文章都是单一模块的设计,然后测试是否来完成特定的功能,不过这种方法只能解决一些简单的问题,所以实际中需要层次花的设计。

​ 这次给大家分享的就是一个层次化的设计,移位寄存器模块+分频模块,然后再用顶层文件把它们组合在一起。

​ 寄存器模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module shift1(clk,D,MD,QB);

input clk; //时钟信号
input [7:0] D; //预置数,可以在测试文件中预置,或者在板子上选取
input [1:0] MD; //模式选择数值
output [7:0] QB; //输出的数值
reg [7:0] REG; //定义寄存器类型

always @ ( posedge clk ) begin //对时钟信号上升沿敏感
case (MD) //根据MD的数值,选择模式
2'b01: begin REG[0] <= REG[7] ; REG[7:1] <= REG[6:0]; end //循环左移
2'b10: begin REG[7] <= REG[0] ; REG[6:0] <= REG[7:1]; end //循环右移
2'b00: begin REG <= D; end //加载预置的数值

endcase
end
assign QB[7:0] = REG[7:0]; //把REG中的数值赋给QB

endmodule

​ 分频模块:

​ 记得一开始的十进制可加可减计数器设计中,我们没有用分频模块,而是把时钟模块绑到了一个按键上,然后按一次表示一个时钟,这样很麻烦,引入分频模块就很有必要了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module div(
input div_rst,
input div_clk, //输出的时钟是100M的
output clk_out
);
reg [30:0] div_q;
reg temp;
always @ (posedge div_clk or posedge div_rst)
begin
if ( div_rst == 0 ) div_q <= 0;
else if( div_q == 50000000) //保证输出的时钟是1s一次的
begin
div_q <= 0; temp <= ~temp;
end
else div_q <= div_q + 1;
end
assign clk_out = temp;
endmodule

​ 顶层文件:

1
2
3
4
5
6
7
8
9
10
11
12
module top(
input clk,
input rst,
input [7:0] D,
input [1:0] MD,
output [7:0] QB);

wire a; //这个a就是把分频模块输出的时钟信号接入到寄存器模块中
div u1 (rst,clk,a); //把模块和顶层连接起来,子模块名字要和之前起的一致
shift1 u2 (a,D,MD,QB);//要注意:这里输入输出端的排布顺序要和在子模块写的顺序一致,否则就会报错。

endmodule

注意:
测试子模块时,比如寄存器模块,那么写完这个模块时,就应该编译,然后写测试文件直接就测试,不要先等写完顶层模块再测试,否则系统会默认测试的是顶层文件,可能会导致没有任何输出产生的情况。

​ 如果没有什么问题,你写顶层文件,然后保存,会出现如下的样子:

​ 表明顶层文件和子模块联系成功,编译没有错误之后,就可以进行下一步了。顶层模块也可以不用测试,如果不写测试文件的话,可以选择 综合下面的:

​ 然后就可以看形成的逻辑图,再比对是否哪里有问题,按照以上程序设计会生成以下的图:

移位寄存器模块如何编写测试文件,可以参考如下链接:
https://blog.csdn.net/weixin_43877139/article/details/88851235

我也写了几篇关于Veirlog的文章,感兴趣的同学可以去看看。该模块链接如下:
Verilog学习

阿里云Ubuntu18.04服务器安装Mono_C#开发环境

重要:安装Mono一定要参照官方文档

一开始安装的时候走了很多的弯路,就是没看官方帮助文档。实际上当你想安装什么东西,首选就是官方文档,其次才是别人的经验把。

官方帮助文档:https://www.mono-project.com/download/stable/#download-lin

这里面介绍的很清楚:对于不同的系统也有自己的安装方法。

第一种方法:直接安装

第一步:

1
sudo apt-get update

第二步:

1
2
3
4
5
6
7
sudo apt install gnupg ca-certificates

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF

echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list

sudo apt update

第三步:

根据自己的需要,可以根据官方文档中的提示,选择安装不同的类库。这种方式可能会出现下载速度过慢的情况,可以把安装源换为国内的,然后使用,具体请Goole或者百度。

第二种:解压缩方式或者直接从网站安装

我这里选择的是5.20.1.19版本,你可以自行选择下载安装的版本。
下载地址:http://download.mono-project.com/sources/mono/

第一步:

1
sudo apt-get update

第二步:

1
2
3
4
5
6
7
8
9
10
11
12
13
cd /usr/local/src/

sudo wget http://download.mono-project.com/sources/mono/mono-5.20.1.19.tar.bz2

tar -jxvf mono-5.20.1.19.tar.bz2

cd mono-5.20.1.19

sudo ./configure --prefix=/usr

sudo make

sudo make install

sudo make这一步执行之后,可能提示你缺少 cmake 这个依赖。执行

1
sudo apt install cmake

之后继续步骤就可以了。

这些步骤执行之后,可以输入 mono -V 查看版本信息。如下图一样便是成功了。

实际上感觉在ubuntu系统的服务器发布C#写的网页还是比较费劲的,推荐还是用Windows server系统安装IIS来发布Asp.net网站。最近我也在弄这个,有兴趣的朋友可以去看我发的相关内容。

Veirlog学习记录(3)--移位寄存器(左循环,右循环)的实现

移位寄存器的设计:
有三个模式:

  • 左循环

  • 右循环

  • 加载预置的数

  • 具体功能可以根据需要对程序做出一些修改即可

    代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module shift1(clk,D,MD,QB);

input clk; //时钟信号
input [7:0] D; //预置数,可以在测试文件中预置,或者在板子上选取
input [1:0] MD; //模式选择数值
output [7:0] QB; //输出的数值
reg [7:0] REG; //定义寄存器类型

always @ ( posedge clk ) begin //对时钟信号上升沿敏感
case (MD) //根据MD的数值,选择模式
2'b01: begin REG[0] <= REG[7] ; REG[7:1] <= REG[6:0]; end //循环左移
2'b10: begin REG[7] <= REG[0] ; REG[6:0] <= REG[7:1]; end //循环右移
2'b00: begin REG <= D; end //加载预置的数值

endcase
end
assign QB[7:0] = REG[7:0]; //把REG中的数值赋给QB

endmodule

测试文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module shift1_tb();
reg clk;
reg [7:0] D;
reg [1:0] MD;
wire [7:0] QB; //输出

initial
begin //初始化
clk = 0;
D = 8'b11110000; //初始化待移数值(这样赋值只是为了最后好观察波形)
MD = 2'b00; //以置数模式开始
end

always #10 clk = ~clk; //时钟信号
always #100 MD = MD+1;//循环改变模式,

shift1 test( .clk(clk),
.D(D),
.MD(MD),
.QB(QB)
);

endmodule

这里图形没有从一开始截取,而是选择能看到三个模式效果的时间段,MD=0时,一直在加载预置数,输出等于D 11110000.MD=1时,开始循环左移。MD=2时,开始循环右移。

基本的设计就是这样子,可以在它的基础上进行改进,以达到大家需要的功能,比如在shift1中的case加几个模式。D的值也可以随便赋值。

我也写了几篇关于Veirlog的文章,感兴趣的同学可以去看看。该模块链接如下:
Verilog学习

© 2025 Three purple's blog All Rights Reserved. 本站总访客数 加载中... 人 | 本站总访问量 加载中...
Theme by hiero