算法学习笔记1:面向对象的数组

算法学习的笔记1,关于对象数组的一个工具类
该工具类可实现以下功能

获取数组的长度

在数组的末尾添加一个元素

打印所有元素到控制台

删除数组中的某个元素

获取某个元素

在指定位置插入一个元素

替换指定位置的元素

github工程地址

工具类代码如下

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package class3_array.utils;

import java.util.Arrays;

public class MyArray {
/*
用于存储数据的数组
*/
private int[] elements;

public MyArray(){
elements = new int[0];
}

/**
* 获取数组的长度
* @return
*/
public int size(){
return elements.length;
}

/**
* 往数组的末尾添加一个数
*/
public void add(int element){
//创建一个新的数组
int[] newArr = new int[elements.length + 1];

//把原数组中的元素复制到新数组中
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}

//把添加的元素放入新的数组中
newArr[newArr.length-1] = element;

//新数组替换旧数组
elements = newArr;
}

/**
* 打印所有元素到控制台
*/

public void show(){
System.out.println(Arrays.toString(elements));
}

/**
* 删除数组中的某个元素
*/
public void delete(int index){
//判断传入的下标
if (index < 0 || index > elements.length - 1){
throw new RuntimeException("下标越界");
}
//创建一个新的数组
int[] newArr = new int[elements.length -1];

//把原来数组删除之后的元素赋值给新的数组
for (int i = 0; i < newArr.length; i++) {
//想要删除元素前面的元素
if (i < index){
newArr[i] = elements[i];
//想要删除元素后面的元素
}else {
newArr[i] = elements[i + 1];
}
}

//把新数组替换旧数组
elements = newArr;
}

/**
* 获取某个元素
*
*/
public int get(int index){
//判断是否下标越界
if (index < 0 || index > elements.length - 1){
throw new RuntimeException("下标越界");
}
return elements[index];
}

/**
* 插入一个元素到指定位置
*/
public void insert(int index,int element){
//判断是否下标越界
if (index < 0 || index > elements.length){
throw new RuntimeException("下标越界");
}

//新建一个数组
int[] newArr = new int[elements.length + 1];

//把原有数组中的值复制到新数组中
for (int i = 0; i < elements.length; i++) {
//插入元素之前的元素
if (i < index){
newArr[i] = elements[i];
//插入位置之后的元素
}else {

newArr[i + 1] = elements[i];
}

}
//把要插入的元素方到指定位置
newArr[index] = element;

//新数组替换旧数组
elements = newArr;
}

/**
* 替换指定位置的元素
*/
public void set(int index,int element){
//判断是否下标越界
if (index < 0 || index > elements.length - 1){
throw new RuntimeException("下标越界");
}
elements[index] = element;
}
}

测试类代码如下

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
package class3_array;

import class3_array.utils.MyArray;

public class TestMyArray {
public static void main(String[] args) {
//创建一个可变的数组
MyArray myArray = new MyArray();

//获取长度
int size = myArray.size();
myArray.show();

//往可变数组中添加一个元素
myArray.add(99);
myArray.add(98);
myArray.add(97);
//显示所有元素到控制台
myArray.show();

//删除某个元素
myArray.delete(1);
myArray.show();

//取出指定位置的元素
int element = myArray.get(1);
System.out.println(element);
System.out.println("=============");

//在指定位置插入元素
myArray.insert(2,96);
myArray.show();
System.out.println("============");

//替换指定位置的元素
myArray.set(0,100);
myArray.show();
System.out.println(myArray.size());
}
}

希望能对您有所帮助。

欢迎大家访问我的个人博客

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)

本篇文章对应的GitHub工程地址如下:内含函数文件+测试文件,下载即可直接运行。

工程地址

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

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学习

Veirlog学习记录(2)--十(多)进制可加可减计数器的实现

上一篇实现的是,十(多)进制的加计数。

这次是要加上减计数,也就是实现可加可减的操作,并且在板子上验证,这次设计没有加分频模块,时钟脉冲是用按键控制的,加分频也可以。

如果要加上一个减的功能,就是要在加计数的基础上加一个使能端up_down,使能端为1的时候,自加。为0的时候自减。同时从0减到9的时候要有一个借位。

代码如下:

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
module M10_updown( 
input EN,CP,Rd,up_down, //up_down=1时加计数,up_down=0时减计数
output reg Cout,
output reg [3:0] Q
);
always @ (posedge CP,negedge Rd)

if( ~Rd ) Q<=4'b0000;
else if(EN&&up_down) //当使能端为1,且选择加计数时,开始加计数
begin
if(Q<4'b1001) Q<=Q+1'b1; //判断是否加到了9
else Q<=4'b0000;
end
else if ( EN && ~up_down )//当使能端为1,且选择加计数时,开始减计数
begin
if ( Q>4'b0000) Q<=Q-1'b1;//判断是否减到了0
else Q<= 4'b1001;
end
else Q<= Q;
always @ (Q)

if(Q==4'b1001 && up_down) Cout = 1;//当加计数时 加到了9,进位
else if(Q==4'b0000 && ~up_down) Cout = 1;//当减计数时 减到了9,借位
else Cout=0;

endmodule

测试文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module M10_updown_tb();
reg EN,CP,Rd,up_down; //输入端口说明
wire Cout; //进位信号
wire [3:0] Q; //数据输出端口及变量的数据类型生命
M10_updown test( .EN(EN), //M10_updown这的名称要和design的文件名一致
.CP(CP),
.Rd(Rd),
.up_down(up_down),
.Cout(Cout),
.Q(Q) );
initial fork
CP=0;
EN=1; #20 EN=0;#50 EN=1;
Rd=0; #30 Rd=1;
up_down=0; #300 up_down=1;
join
always #8 CP=~CP;

endmodule

仿真图如下:

然后就是布局布线,添加约束文件。接上板子就ok了。

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

算法图解第四章笔记:快速排序1(java版)

分而治之(D&C)一种著名的递归式问题的解决方法。

案例:农场主分地问题:

要求:要将这块地均匀分成方块,且分出的方块尽可能大。

步骤:(1)找出基线条件,这种条件必须尽可能的简单

​ (2)不断将问题分解(或者说是缩小规模),直到符合基线条件

这个案例很有意思,而且后面的顿悟时刻:为何不对余下的那一块小块地使用相同的算法呢?这正是递归的核心思想啊。

另一个小例子:

​ 给定一个数组:2,4,6

​ 需要将这些数字相加,并返回结果。使用循环很容易。

1
2
3
4
5
6
7
public static int sum(int[] arr){
int total = 0;
for(int i = 0;i < arr.length ; i++){
total += arr[i];
}
return total;
}

如何用递归完成这种任务呢?

第一步:找出基线条件。最简单的数组:不包含任何元素或只包含元素,这样计算总和非常容易。

第二步:每次递归调用都必须离空数组更进一步。

那么如何缩小问题的规模呢?给sum传递的数组更短。

练习:

4.1:实现前述sum函数

分析:这个问题基线条件比较清晰,不太清晰的点其实是递归条件,如何让数组离空数组更近一步呢?一开始我想的是,把数组截取,让数组长度每次调用都减一。其实这样想就有点偏差了,因为让数组变成空数组,其实并不是真的让数组逐渐的变为空数组,其实一直都是原来的数组,只不过每次调用的元素都是数组中的不同元素。下面的代码可能会更加帮助理解递归条件:

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
* 练习4.1:利用递归求和:
* 基线条件: 最简单的数组:不包含任何元素或者只包含一个元素
* 递归条件: 给函数传递的数组越来越短
*
*/
public static int sum_1(int[] arr,int n){
//基线条件
if( n == 0 ){
return arr[n];
}else{
return arr[n] + sum_1(arr,n-1);
}

}

4.2:编写一个递归函数来计算列表包含的元素数

分析:乍一看这个问题和4.1不太一样,但是如果数组中每个元素的值都是1的话,是不是这时候求数组的和,得到的就是列表中所包含的元素数。所以只需要把上述的代码稍做修改即可。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* 练习4.2:编写函数来计算列表所包含的元素数
*
*/
public static int countNumbers(int[] arr,int n){
//判断数组是否为空
if(arr.length == 0){
return 0;
}
//基线条件
else if(n == 0){
return 1;
}else{
return 1 + countNumbers(arr, n-1);
}

}

4.3:找出列表中最大的数字

分析:这个问题就比前两个深化一些了,要找出列表中的最大值,其实有很多方法。如果用递归去做,其实还是要考虑基线条件和递归条件。和前两个问题类似,递归条件还是想让传入的数组的长度原来越短,换句话说就是,想要比较的元素数越来越少。这里可以把一个数组分割成为两个,通过数组的下标做判断。左数组找出一个最大值,右数组找一个最大值,再进行比较,返回大的那个。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static int findMax(int[] arr,int leftIndex,int rightIndex){
//基线条件
if(leftIndex == rightIndex){
return arr[leftIndex];
}
//这种方式求得mid不会溢出
int mid = leftIndex + (rightIndex -leftIndex)/2;
int maxLeft = findMax(arr,leftIndex,mid);
int maxRight = findMax(arr,mid+1,rightIndex);

return Math.max(maxLeft, maxRight);
}
}

我的测试数组为2,4,6,8

所得到的输出为:

© 2025 XuXing's blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero