c++11 python 对比

https://segmentfault.com/a/1190000002499989

3d 重构suan

essential matrix 本质矩阵
https://www.youtube.com/watch?v=Opy8xMGCDrE&list=PL4B3F8D4A5CAD8DA3&index=48


ubuntu 增加删除虚拟内存

交换文件

As an alternative to creating an entire partition, a swap file offers the ability to vary its size on-the-fly, and is more easily removed altogether. This may be especially desirable if disk space is at a premium (e.g. a modestly-sized SSD).
注意: BTRFS 文件系统暂时不支持交换文件。

建立交换文件

As root use fallocate to create a swap file the size of your choosing (M = Megabytes, G = Gigabytes) (dd can also be used but will take longer). For example, creating a 512 MB swap file:
# fallocate -l 512M /swapfile
或
# dd if=/dev/zero of=/swapfile bs=1M count=512
Set the right permissions (a world-readable swap file is a huge local vulnerability)
# chmod 600 /swapfile
After creating the correctly-sized file, format it to swap:
# mkswap /swapfile
Activate the swapfile:
# swapon /swapfile
Edit /etc/fstab and add an entry for the swap file:
/swapfile none swap defaults 0 0

删除交换文件

To remove a swap file, the current swap file must be turned off.
As root:
# swapoff -a
Remove swapfile:
# rm -rf /swapfile

Checks current swap space by running free command (It must be around 10GB.).

Checks the swap partition
sudo fdisk -l /dev/hda8 none swap sw 0 0 Make swap space and enable it.
sudo swapoff -a
sudo /sbin/mkswap /dev/hda8 sudo swapon -a

If your swap disk size is not enough you would like to create swap file and use it. Create swap file.
sudo fallocate -l 10g /mnt/10GB.swap
sudo chmod 600 /mnt/10GB.swap

Mount swap file. sudo mkswap /mnt/10GB.swap
Enable swap file. sudo swapon /mnt/10GB.swap

gdb常用命令

gdb -tui exe

调用gdb编译需要在cc后面加 -g参数再加-o;
[root@redhat home]#gdb 调试文件:启动gdb
(gdb) l :(字母l)从第一行开始列出源码
(gdb) break n :在第n行处设置断点
(gdb) break func:在函数func()的入口处设置断点
(gdb) info break: 查看断点信息
(gdb) r:运行程序
(gdb) n:单步执行
(gdb) c:继续运行
(gdb) p 变量 :打印变量的值
(gdb) bt:查看函数堆栈
(gdb) finish:退出函数
(gdb) shell 命令行:执行shell命令行
(gdb) set args 参数:指定运行时的参数
(gdb) show args:查看设置好的参数
(gdb) show paths:查看程序运行路径;
           set environment varname [=value] 设置环境变量。如:set env USER=hchen;
            show environment [varname] 查看环境变量;
(gdb) cd 相当于shell的cd;
(gdb)pwd :显示当前所在目录
(gdb)info program: 来查看程序的是否在运行,进程号,被暂停的原因。
(gdb)clear 行号n:清除第n行的断点
(gdb)delete 断点号n:删除第n个断点
(gdb)disable 断点号n:暂停第n个断点
(gdb)enable 断点号n:开启第n个断点
(gdb)step:单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的

  • list :简记为 l ,其作用就是列出程序的源代码,默认每次显示10行。
  • list 行号:将显示当前文件以“行号”为中心的前后10行代码,如:list 12
  • list 函数名:将显示“函数名”所在函数的源代码,如:list main
  • list :不带参数,将接着上一次 list 命令的,输出下边的内容。
注意 :如果运行list 命令得到类似如下的打印,那是因为在编译程序时没有加入 -g 选项:
(gdb) list
1       ../sysdeps/i386/elf/start.S: No such file or directory.
        in ../sysdeps/i386/elf/start.S

  • run:简记为 r ,其作用是运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令。
  • 回车:重复上一条命令。
  • set args:设置运行程序时的命令行参数,如:set args 33 55
  • show args:显示命令行参数
  • continue:简讯为 c ,其作用是继续运行被断点中断的程序。
  • break:为程序设置断点。
  • break 行号:在当前文件的“行号”处设置断点,如:break  33
  • break 函数名:在用户定义的函数“函数名”处设置断点,如:break cb_button
  • info breakpoints:显示当前程序的断点设置情况
  • disable breakpoints Num:关闭断点“Num”,使其无效,其中“Num”为 info breakpoints 中显示的对应值
  • enable breakpoints Num:打开断点“Num”,使其重新生效
  • step:简记为 s ,单步跟踪程序,当遇到函数调用时,则进入此函数体(一般只进入用户自定义函数)。
  • next:简记为 n,单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同 step 的主要区别是,step 遇到用户自定义的函数,将步进到函数中去运行,而 next 则直接调用函数,不会进入到函数体内。
  • until:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
  • finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
  • stepi或nexti:单步跟踪一些机器指令。
  • print 表达式:简记为 p ,其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。
  • print a:将显示整数 a 的值
  • print ++a:将把 a 中的值加1,并显示出来
  • print name:将显示字符串 name 的值
  • print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
  • print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数
  • bt:显示当前程序的函数调用堆栈。
  • display 表达式:在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。如: display a
  • watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a
  • kill:将强行终止当前正在调试的程序
  • help 命令:help 命令将显示“命令”的常用帮助信息
  • call 函数(参数):调用“函数”,并传递“参数”,如:call  gdb_test(55)
  • layout:用于分割窗口,可以一边查看代码,一边测试:
  • layout src:显示源代码窗口
  • layout asm:显示反汇编窗口
  • layout regs:显示源代码/反汇编和CPU寄存器窗口
  • layout split:显示源代码和反汇编窗口
  • Ctrl + L:刷新窗口
  • quit:简记为 q ,退出gdb
当然,gdb的功能远不止这些,包括多进程/多线程/信号/远程调试等功能在这里均没有提及,有需要的读者可以参考其它信息。

/usr/local/lib

将动态库目录/usr/local/lib 添加到文件/etc/ld.so.conf,并使用sudo ldconfig使得添加即使生效

或者 临时添加:

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

stm32 读取 ID

void setup() {
  Serial.begin(115200);
}

void loop() {
  uint16 *flashSize = (uint16 *) (0x1FFFF7E0);
  uint16 *idBase0 =  (uint16 *) (0x1FFFF7E8);
  uint16 *idBase1 =  (uint16 *) (0x1FFFF7E8+0x02);
  uint32 *idBase2 =  (uint32 *) (0x1FFFF7E8+0x04);
  uint32 *idBase3 =  (uint32 *) (0x1FFFF7E8+0x08);
  
  Serial.print("Flash size is ");
  Serial.print(*flashSize );
  Serial.println("k");
  
  Serial.print("Unique ID is ");
  Serial.print(*(idBase0),HEX);
  Serial.print(*(idBase1),HEX);
  Serial.print(*(idBase2),HEX);
  Serial.println(*(idBase3),HEX);  

  delay(500);
}

vitrualDub plugin

http://codecpack.co/download/FFInputDriver.html

安装到已有的virtualdub文件夹就行了,无配置,支持各种格式,包括苹果MOV。

怎样教育孩子

“千万不要给你的孩子只塑造一个世俗的、眼下的、渺小的世界。要从小给她看星空、海洋、恐龙、神话、圣贤。这样,等她长大的时候,她就有足够的胸怀容忍各种无趣的生活。”——路金波

PID code

http://robotsforroboticists.com/pid-control/

树莓派3 uart 大坑

树莓派3的uart默认连接蓝牙了。
解决方法:1.关闭蓝牙,
                    2.重新配置回uart G14 G15,
                    3.清楚蓝牙service,
                    4.重启

Fix is included on manual updates since April 20, and involves adding the following line to /boot/config.txt:
dtoverlay=pi3-miniuart-bt
Reboot and the serial connection over GPIO to /dev/ttyAMA0 will be usable.

https://openenergymonitor.org/emon/node/12311


Raspberry Pi 默认有个login程序使用了uart,要关掉。

http://www.hobbytronics.co.uk/raspberry-pi-serial-port


Disable Serial Port Login
To enable the serial port for your own use you need to disable login on the port. There are two files that need to be edited
The first and main one is /etc/inittab
This file has the command to enable the login prompt and this needs to be disabled. Edit the file and move to the end of the file. You will see a line similar to
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
Disable it by adding a # character to the beginning. Save the file.
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Disable Bootup Info
When the Raspberry Pi boots up, all the bootup information is sent to the serial port. Disabling this bootup information is optional and you may want to leave this enabled as it is sometimes useful to see what is happening at bootup. If you have a device connected (i.e. Arduino) at bootup, it will receive this information over the serial port, so it is up to you to decide whether this is a problem or not.
You can disable it by editing the file /boot/cmdline.txt
The contents of the file look like this
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
Remove all references to ttyAMA0 (which is the name of the serial port). The file will now look like this
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
Reboot
In order you enable the changes you have made, you will need to reboot the Raspberry Pi
sudo shutdown -r now

傅里叶变换,调制与解调

作者:FOU

前言

本文在 http://blog.csdn.net/dznlong/article/details/2261150 的基础上,重新整理,并添加了具体的Matlab例子。最后进一步扩充到调制与解调。

(一)时域-频域变换的本质

我们知道,一个单波,由频率w,振幅A,相位b组成,在时域上(横轴表示时间,数轴表示振幅),可以用余弦(正弦)表示为:y=A*cos(2*pi*w*t+b)。

来看一个简单的例子。频率为50Hz的余弦波:

Fs = 1000;  %采样频率,每秒采样1000点              
T = 1/Fs;   %每一点就代表1/1000秒              
L = 1000;   %一共采样1000个点(就是采样一整秒啦)              
t = (0:L-1)*T; %每一点对应的时刻(从最开始的0秒,到最后的1秒)          
x1 = cos(2*pi*50*t) ; %50Hz信号及采样
figure;plot(t,x1);title('x1 50Hz');



反过来,已知时域上的信号样子,怎样知道它是由哪(几)个频率的波组成的呢?

凭什么说一个任意信号一定能拆分几个波呢?因为傅里叶在1807年给出了证明,一个信号,无论多么复杂,都可以表示成几个余弦波的叠加(求和)。具体证明请维基百科。反正就是能拆分成各种(频率,振幅,相位)的波

对上面这个图,一眼看上去,它就是一个单波,振幅是1,频率是。。。至少可以数一下,50个峰所以是50Hz。可是如果是50000Hz,难道我们要数到天亮吗?或者图形复杂一点,说不上来究竟是不是波峰,又如何计数呢?

从数学或者程序的角度,我们有一个很笨但是管用的方法,就是我构造各种频率,各种相位的余弦波,与信号点积求和,波形一致的得到的和最大(正值最大峰),不相关的接近0(0),相反的最小(负值最大峰)。

(a)确定频率w
先不考虑相位。

1.  把一个30Hz的余弦波,和原始50Hz余弦波各点相乘,结果在[-1 1]区间,直观的感觉,每出现一个1,就会有一个对应的-1和它抵消掉,最终求和为(接近)0。

aCos = cos(2*pi*30*t);
vCos = aCos.*x1;
sum(vCos)
figure;subplot(3,1,1);plot(x1);subplot(3,1,2);plot(aCos);subplot(3,1,3);plot(vCos);title('check 30Hz');

>> 1.8519e-13
2.  把一个50Hz的余弦波,和原始50Hz余弦波各点相乘,结果在[0 1]区间。每个点的积都大于0,最终求和为大值 500。

aCos = cos(2*pi*50*t);
vCos = aCos.*x1;
sum(vCos)
figure;subplot(3,1,1);plot(x1);subplot(3,1,2);plot(aCos);subplot(3,1,3);plot(vCos);title('check 50Hz');

>> 500
3.  极端情况,如果匹配波频率是0呢?那它就是一条直线,振幅为1。结果就是原始波的各点简单相加。

aCos = cos(2*pi*0*t);
vCos = aCos.*x1;
sum(vCos)
figure;subplot(3,1,1);plot(x1);subplot(3,1,2);plot(aCos);subplot(3,1,3);plot(vCos);title('check 0Hz');

>> 1.7808e-13


来做一个全范围测试,写个循环。我们来构建从0Hz到500Hz的501个波(以1Hz为单位逐渐增加)。为什么只到500Hz呢?因为原始信号采样频率是1000Hz(每秒采1000个点),所以我们新构建的波,为了点积求和,必须保持长度一致,一秒也是1000个点;一个周期至少要有一正一负,1000个点最多只能表示到500Hz,再往上就不具有周期性,没意义了。

cs = []; %贮存结果
for i =0:500 %创建不同501个频率的cos波
    aCos = cos(2*pi*i*t); %创建当前频率的波
    vCos = aCos.*x1; %点积
    cs = [cs sum(vCos)]; %求和
end
figure;plot(0:1:500,cs);title('cos 0Hz-500Hz');

我们看到,只有50Hz的余弦波,与原始的50Hz余弦波点积求和,有显著的大值,表现为正相关;其它Hz的余弦波,点积求和接近于0,不能得到有意义的结果,表现为不相关。为什么只有同样频率的波点积求和有响应呢?

cos(2*pi*w1*t).*cos(2*pi*w2*t) = (cos(2*pi*(w1+w2)*t)+cos(2*pi*(w1-w2)*t))/2;第一部分始终是周期波,具有对称性,正负各点互相抵消,点积求和为0。第二部分呢,绝大部分情况下,也是一个周期波,点积求和为0。当且仅当w1==w2时,频率为0,值为1,才可以积累出一个大值。

(b)确定振幅A
正相关显示求和结果为500,为什么是500呢?这个500又怎样对应到原始振幅上呢?

50Hz与50Hz点积相乘,得到的结果为50Hz波的平方:y = cos(2*pi*50*t).*cos(2*pi*50*t)=cos(2*pi*50*t).^2; 其中t=0:0.001:1。
sum(y) = sum(cos(2*pi*50*0/1000)^2+cos(2*pi*50*1/1000)^2+cos(2*pi*50*2/1000)^2+...+cos(2*pi*50*1000/1000)^2;
又因为sin(a)^2+cos(a)^2 = 1  => cos(pi/2-a)^2+cos(a)^2=1;所以对上面的式子中的每一项,总能找到另一项和它相加等于1。一共有1000个项,正好凑出500个对子,每个对子为1,所有求和为500。只要是在整周期上均匀分布的点,总能互相找到配对求和为0。不是均匀分布就悬了。

直接看上面推导公式,每个采样点供应了1/2,一共N=1000个采样点,所以最终求和为500。

更一般化,求和得到的值,在最理想(原始波和测试波频率、振幅都一致)的状况下,得到的求和结果就为 A*N/2,A为原始波的振幅,N为采样点。并且推出,采样点频率越高,或者采样时间越长,都会增加样点数从而增高最终的和。

从最终的和反推出原始振幅就很简单了,s=A*N/2 => A=s*2/N;

我们可以试一下,求和值只和样点数与原始振幅相关,和具体的频率无关。
比如30Hz点乘30Hz,点积求和为500:
x1 = cos(2*pi*30*t) ;
aCos = cos(2*pi*30*t);
vCos = aCos.*x1;
sum(vCos)

>> 500

比如300Hz点乘300Hz,点积求和还是500:
x1 = cos(2*pi*300*t) ;
aCos = cos(2*pi*300*t);
vCos = aCos.*x1;
sum(vCos)

>> 500

但是,但是,在两个极端情况,频率为极小值0Hz,或者频率为极大值500Hz时,点积求和却为1000,这又是为什么呢?

x1 = cos(2*pi*0*t) ;
aCos = cos(2*pi*0*t);
vCos = aCos.*x1;
sum(vCos)

>> 1000

x1 = cos(2*pi*500*t) ;
aCos = cos(2*pi*500*t);
vCos = aCos.*x1;
sum(vCos)

>> 1000

这是因为,当极小或极大时,点积之后的波形都变成了水平波,每个样点自己就都是1,不用再凑对子了。多少个样点就是多少和。0Hz的情况下,cos(0)^2 = 1^2 = 1,始终等于1;500Hz的情况下,因为这是当前采样频率下(1000个采样点/秒)能表示的最高频率波,波形就是[1,-1,1,-1....,1,-1],它的平方也始终是1。在这两个极端情况下,s=A*N => A = s/N;

还有一个小问题,我们的测试波是从0Hz到500Hz,每次增加1Hz。聪明的读者会问,为什么每次增加1Hz呢?可不可以只增加0.1Hz,0.01Hz,这样会测的更准确些吗?我们来试试看。

cs = [];
for i =0:0.1:500 %步长为0.1
    aCos = cos(2*pi*i*t);
    vCos = aCos.*x1;
    cs = [cs sum(vCos)];
end
figure;plot(0:0.1:500,cs);title('cos 0Hz-500Hz');



我们发现,在整数频率上不相关,但是再细分到小数频率上,表现出了各种不可忽略的相关性,这是怎么回事呢?

这是因为,如果测试波的频率不为整数的话,最后总会有个尾巴不是完整周期,其对称性被破坏,无法求和为0。所以测试波必须要有完整的周期。

那么怎么样能把测试精度提升到小数位置呢?我们的例子里,测试的是整一秒的采样,如果我们继续多采样几秒,比如采样2秒钟,那就是2000个采样点,那么所有0.5Hz(例如0.5,1.5,2.5)在一个周期有尾巴,在两个周期正好凑成一个整尾巴,又是一个整周期啦。所以2秒采样时,我们就精确到0.5Hz;3秒采样时,精确到1/3Hz。依此类推,精度=1/采样秒数。

上面的例子,我们想精确到0.1Hz,就要采样10整秒。

Fs = 1000;  %采样频率,每秒采样1000点              
T = 1/Fs;   %每一点就代表1/1000秒              
L = 10000;   %一共采样10000个点(就是采样10整秒啦)              
t = (0:L-1)*T; %每一点对应的时刻(从最开始的0秒,到最后的10秒)          
x1 = cos(2*pi*50*t) ; %50Hz信号及采样
figure;plot(t,x1);title('x1 50Hz');
cs = [];
for i =0:0.1:500
    aCos = cos(2*pi*i*t);
    vCos = aCos.*x1;
    cs = [cs sum(vCos)];
end
figure;plot(0:0.1:500,cs);title('cos 0Hz-500Hz 10 seconds');

看,所有的0.1Hz确实都正确表现出了不相关性。而且说明,频率的测试可以精确到任何精度,50Hz和50.1Hz,在1Hz精度下可能相差不大,但是采样时间一长,到0.1Hz下,它们就是彻底两个不同的波了。(注意,因为采样点多了10倍,50Hz正相关的求和值也相应增大了10倍。)

(c)确定相位b
最后,我们来给原始信号加上相位,然后看看怎样测出这个相位。

Fs = 1000;  %采样频率,每秒采样1000点              
T = 1/Fs;   %每一点就代表1/1000秒              
L = 1000;   %一共采样1000个点(就是采样一整秒啦)              
t = (0:L-1)*T; %每一点对应的时刻(从最开始的0秒,到最后的1秒)          
x1 = cos(2*pi*50*t+pi/3) ; %50Hz信号及采样,由于相位关系,整体向左位移pi/3
figure;plot(t,x1);title('x1 50Hz pi/3');


可以看到,由于相位关系,整体向左位移pi/3。

此时再把这个偏移了的信号与50Hz的测试信号点积求和,会得到什么结果呢?

aCos = cos(2*pi*50*t);
vCos = aCos.*x1;
sum(vCos)
figure;subplot(3,1,1);plot(t,x1);subplot(3,1,2);plot(t,aCos);subplot(3,1,3);plot(t,vCos);title('check 50Hz 0pi <-> pi/3');

>> 250.0000

可以看到,波形和之前没位移的时候差不多,只是整体下降了1/4。最终求和结果从500减少到了250。

这是因为,cos(2*pi*50*t+b).*cos(2*pi*50*t) = (cos(2*pi*100*t+b)+cos(b))/2;第一部分是周期波,求和之后,各部分互相抵消,和值为0;第二部分是常数,求和之后值为N*cos(b)/2;只有当b=0时,cos(b)取最大值1,和值为500;现在b=pi/3,cos(b)=1/2,和值就只能是250了。

理论上,我们可以找个相位为0的标准波,测一下最大相关和值是多少,以此为参照,通过反余弦,我们就可以得到相位b。但实际上,我们往往无法得到这么个相位为0的标准波(都能控制相位了,还要求什么相位,直接想要什么相位就上什么相位好了)。那怎么办呢?

有两个办法。
方法一:把所有的相位遍历一遍,看看那个相位响应最大。
cs = [];
for c =-1:0.01:1
    aCos = cos(2*pi*50*t+c*pi);
    vCos = aCos.*x1;
    cs = [cs,sum(vCos)];
end
figure;plot(-1:0.01:1,cs);title('cos 50Hz -pi:pi');

我们清楚的看到,在0.33pi相位上,表现出了最大的正相关性,所以相位为0.33*pi。

但是遍历的方法,不仅耗时,精度也不高。

方法二:求正弦sin响应值,与余弦cos响应值求比,得出tan,再反推b。
还是这个例子,cos(2*pi*50*t+b).*sin(2*pi*50*t) = (sin(2*pi*100*t+b)+sin(-b))/2;第一部分还是周期波,求和为0;第二部分为常数-sin(b)/2,求和为-N*sin(b)/2;

假设之前那个余弦波测得的响应值为N*cos(b)/2 = v1,现在正弦波测得的响应和值为-N*sin(b)/2=v2;那么有v2/v1 = -sin(b)/cos(b) = -tan(b) => b = atan(-v2/v1)。

并且因为sqrt(cos(b)^2+sin(b)^2) = 1,所以sqrt(v1^2+v2^2)就是0相位时的完全相关求和值。

aCos = cos(2*pi*50*t);
vCos = aCos.*x1;
v1 = sum(vCos)
aSin = sin(2*pi*50*t);
vSin = aSin.*x1;
v2 = sum(vSin)
b = atan(-v2/v1)
b/pi

>> v1 =
  250.0000

v2 =
 -433.0127

b =
  1.0472

b/pi =
  0.3333

(d)信号叠加
最后我们再来研究一下,如果原始信号是多(频率)波叠加在一起,还可以用这个相关性方法正确求出各A,w,b吗?比如一个50Hz,一个20Hz的信号加在一起,会不会变成30Hz或者80Hz什么的?相位也互不影响吗?振幅还可以顺利分开来吗?

Fs = 1000;  %采样频率,每秒采样1000点              
T = 1/Fs;   %每一点就代表1/1000秒              
L = 1000;   %一共采样1000个点(就是采样一整秒啦)              
t = (0:L-1)*T; %每一点对应的时刻(从最开始的0秒,到最后的1秒)          
x1 = cos(2*pi*50*t) ; %50Hz信号及采样
x2 = 2*cos(2*pi*20*t) ; %20Hz信号及采样,主意它的振幅是2
y = x1+x2;
figure;
subplot(4,1,1);plot(t,x1);title('x1 50Hz');
subplot(4,1,2);plot(t,x2);title('x1 20Hz');
subplot(4,1,3);plot(t,y);title('x1+x2');
cs = [];
for i =0:500
    aCos = cos(2*pi*(i)*t);
    vCos = aCos.*y;
    cs = [cs,sum(vCos)];
end
subplot(4,1,4);plot(0:1:500,cs);title('cos 0Hz-500Hz');

可以看到,它们确实是互不影响的。直接套用之前的公式:
(A1*cos(2*pi*w1+b1)+A2*cos(2*pi*w2+b2)).*cos(2*pi*w3+b3) = A1*cos(2*pi*w1+b1).*cos(2*pi*w3+b3)+A2*cos(2*pi*w2+b2).*cos(2*pi*w3+b3);
所以求叠加信号的相关性,和分别求相关性再叠加是一样的,各个信号的计算互不影响。


快速傅里叶变换fft,本质上也是求cos sin相关性,只是它把cos放到实数域,sin放到复数域。通过复数的一些对称性加快了计算。将计算复杂度从O(N*N)降低到O(N*log(N))。但是fft必须要输入的样点数为2的次方(2,4,。。。512,1024),不足补零。所以取样时要小心。

(二)调制与解调
有了上面的基础,我们再看调制解调就很简单了。
(a)调制
调制就是把低频波与高频波点乘之后再传输。

Te = 0.01; %每个采样点代表0.01秒
N = 1024; %一共采样1024点,也就是10.24秒
B = 10/(N*Te); %参考频率为10.24秒传输10个周期,也就是0.9766Hz
f1 = B/2; %原始信号为0.4883Hz(当然你可以自己定义)
f0 = 10*B; %载波信号为9.766Hz(当然你可以自己定义)
m = 0.8; %原始信号的振幅为0.8
phi = 0; %载波相位
indice = (0:1:N-1); %各采样点的下标
t = Te*indice; %各采样点的时刻

At = (1+m*cos(2*pi*f1*t+phi)); %原始信号

f = fft(At); %快速傅里叶变换,产生实数部分与虚数部分,分别对应cos,sin
f = abs(f); %求和值
figure;
subplot(2,1,1);plot(indice,At);
subplot(2,1,2);plot(indice,f);

我们可以通过fft观察到,原始信号At,有一个频率为0/10.24 = 0Hz,振幅为1024/1024 = 1的信号;还有一个频率为5/10.24=0.4883Hz,振幅为409.6*2/1024 = 0.8的波。

再来看载波。

C = cos(2*pi*f0*t);
f = fft(C);
f = abs(f);
figure;
subplot(2,1,1);plot(indice,C);title('transport signal');
subplot(2,1,2);plot(indice,f);title('fft of transport signal');

我们看到,载波频率为100/10.24=9.7656Hz。

接着把原始信号与载波信号点乘。

Z = At.*C;
figure;
subplot(2,1,1);plot(indice,Z);title('modulated signal');
f = fft(Z);
f = abs(f);
subplot(2,1,2);plot(indice,f);title('fft of modulated signal');


我们看到,相乘之后波形发生了变换,进一步用fft进行分析,我们发现调制后的信号由3个频率组成,
95/10.24=9.2773Hz,振幅为204.8*2/1024=0.4,相位不明;
105/10.24=10.2539Hz,振幅为204.8*2/1024=0.4,相位不明;
最大的一个:100/10.24=9.7656Hz,振幅为512*2/1024=1,相位不明。

这三个频率都是从哪里来的呢?又有什么关系呢?
At.*C =  (1+m*cos(2*pi*f1*t)).*cos(2*pi*f0*t) = cos(2*pi*f0*t)+m.*cos(2*pi*f1*t).*cos(2*pi*f0*t) = cos(2*pi*f0*t)+m*(cos(2*pi*(f0+f1)*t)+cos(2*pi*(f0-f1)*t)/2;

可以从上式发现,包括三个频率f0,f0+f1,f0-f1,以及它们的振幅。

同时可以发现一个规律,除了0Hz信号之外,其它频率f1的信号,载波f0之后,都会分成两个信号f0+f1,f0-f1的叠加。

以上是理想情况,我们再来加噪声看看。

v = 0.08;
N1 = sqrt(v)*randn(1,N)*5;
N2 = sqrt(v)*randn(1,N)*5;

f = fft(N1);
f = abs(f);
figure;
subplot(2,1,1);plot(indice,N1);title('noise N1');
subplot(2,1,2);plot(indice,f);title('fft noise N1');
我们通过噪声的fft看到,噪声没有什么特别突出的频率,所以叫噪声。


依葫芦画瓢,对被噪声污染了的信号,我们也看看fft:

Z = At.*C+N1.*cos(2*pi*f0*t)+N2.*sin(2*pi*f0*t);
% Z = At+N1.*cos(2*pi*f0*t)+N2.*sin(2*pi*f0*t);
figure;
subplot(2,1,1);plot(indice,Z);title('noised modulated signal');

f = fft(Z);
fAbs = abs(f);
subplot(2,1,2);plot(indice,fAbs);


我们看到,即便受到了噪声影响,三个峰值频率位置还是准确的,虽然幅度由于噪声影响发生了变化。


(b)解调
解调就是从高频波里提取原始低频波。

假设我们接收到了受到噪声污染的信号,如上图,我们可以先做下频域上的滤波。因为我知道载波是9.7656Hz(手册,打电话问同事,或者由对称性看出来的。。。),我们就在fft频谱图上,以9.7656Hz为中心(上图中即x=100),左右各保留10个单位,这样既能把原始信号的频率保留下来,由能把噪声的频率尽可能的去除。

filtre = zeros(1, N); %filtre dans le domaine fr¨¦quentiel
filtre(1,100-10:100+10) = 1;
filtre(1,N-100-10:N-100+10) = 1;
fAbsFilter = filtre.*fAbs;
figure;plot(indice,fAbsFilter);


看,是不是清爽多了?

怎样能从调频之后的频率,恢复到原始的低频率信号呢(解调)?再看一下上面的公式:

At.*C =  (1+m*cos(2*pi*f1*t)).*cos(2*pi*f0*t) = cos(2*pi*f0*t)+m.*cos(2*pi*f1*t).*cos(2*pi*f0*t) = cos(2*pi*f0*t)+m*(cos(2*pi*(f0+f1)*t)+cos(2*pi*(f0-f1)*t)/2;

我们现在从调频后的高频fft,可以轻松恢复最后一项蓝字部分。把每一部分的频率,减去载波频率f0:
cos(2*pi*(f0-f0)*t)+m*(cos(2*pi*(f0+f1-f0)*t)+cos(2*pi*(f0-f1-f0)*t)/2
= cos(2*pi*0*t)+m*(cos(2*pi*f1*t)+cos(2*pi*f1*t)/2
=1+m*cos(2*pi*f1*t) = At;

以上是phi等于0,原始信号没有相位的情况。给phi赋值pi/3,又会怎样呢?先从理论上看一下相位的影响:

At.*C =  (1+m*cos(2*pi*f1*t+b)).*cos(2*pi*f0*t) = cos(2*pi*f0*t)+m.*cos(2*pi*f1*t+b).*cos(2*pi*f0*t) = cos(2*pi*f0*t)+m*(cos(2*pi*(f0+f1)*t+b)+cos(2*pi*(f0-f1)*t-b)/2;

收到蓝字部分的信号后,同样各部分频率减去f0:
cos(2*pi*(f0-f0)*t)+m*(cos(2*pi*(f0+f1-f0)*t+b)+cos(2*pi*(f0-f1-f0)*t-b)/2 = cos(0)+m*(cos(2*pi*f1*t+b)+cos(2*pi*(-f1)*t-b))/2 = cos(0)+m*(cos(2*pi*f1*t+b)+cos(2*pi*f1*t+b))/2 = 1+m*cos(2*pi*ft*t+b)=At;

可以看出,即使有相位,依旧可以通过直接减去载波频率f0,完全恢复。我们在第一部分已经知道,求各个频率的相位是用sin波和cos波本别点积求和,再用atan求出的相位。如果直接用fft呢,其实cos和sin的结果分别保存在实部和虚部,直接用就行了。

下面以有相位的具体例子,结束本教程。本教程力求解释透彻,多有啰嗦,希望对各位看官能有略微帮助。


% modulation

Te = 0.01;
N = 1024;
B = 10/(N*Te);
f1 = B/2;
f0 = 10*B;
m = 0.8;
phi = pi/3;
indice = (0:1:N-1);
t = Te*indice;

At = (1+m*cos(2*pi*f1*t+phi));

f = fft(At);
f = abs(f);
figure;
subplot(2,1,1);plot(indice,At);
subplot(2,1,2);plot(indice,f);

C = cos(2*pi*f0*t);
figure;plot(C);
Z = At.*C;
figure;plot(Z);

f = fft(Z);
f = abs(f);
figure;plot(f);

v = 0.09;
N1 = sqrt(v)*randn(1,N);
N2 = sqrt(v)*randn(1,N);

figure;plot(N1);

f = fft(N1);
f = abs(f);
figure;plot(f);

Z = At.*C+N1.*cos(2*pi*f0*t)+N2.*sin(2*pi*f0*t);
figure;plot(Z);

f = fft(Z);
fAbs = abs(f);
figure;plot(fAbs);

% demodulation

filtre = zeros(1, N); %filtre dans le domaine fréquentiel
filtre(1,100-10:100+10) = 1;
filtre(1,N-100-10:N-100+10) = 1;
figure;plot(filtre);

fFilter = filtre.*fAbs;
figure;plot(fFilter);

ff0 = 101;
ff1 = 96;
ff2 = 106;

rec0 = fAbs(ff0)*cos(2*pi*(ff0-ff0)*100*t/1024-atan2(imag(f(ff0)),real(f(ff0))));
rec1 = fAbs(ff1)*cos(2*pi*(ff0-ff1)*100*t/1024-atan2(imag(f(ff1)),real(f(ff1))));
rec2 = fAbs(ff2)*cos(2*pi*(ff0-ff2)*100*t/1024-atan2(imag(f(ff2)),real(f(ff2))));
figure(1);
subplot(2,1,2);plot((rec0+rec1+rec2)*2/N);title('demodulated signal');

atan2(imag(f(ff0)),real(f(ff0)))/pi %输出3个相位
atan2(imag(f(ff1)),real(f(ff1)))/pi
atan2(imag(f(ff2)),real(f(ff2)))/pi

>> (以pi为单位)
ans =

    0.0231


ans =

   -0.2749


ans =

    0.3055
我们看到,噪声对频率没什么影响,对振幅和相位产生了略微影响,还能接受。


后补:

解调的时候,如果已知原始波的频率,和载波的频率,我们自然可以手动找出调制后的相关频率,然后再手动减去载波频率来解调。

但有的时候,原始波的频率是一段范围,并不固定在某一个点上(干扰什么的,或者像人声,本来就不固定),我们可以直接把收到的信号,重新点乘载波,再做fft。

重新与载波相乘,本质上还是降低信号的频率。我们之前已经看到了,载波可以改变原始信号的频率w1.*wt ->(wt+w1)  & (wt-w1),那么,w1.*wt.*wt -> [(wt+w1) & (wt-w1)].*wt = (2wt+w1) & -w1 & 2wt-w1 & w1。虽然因为对称性,产生了一些原来没有的频率,但原始频率确实能还原回来。比如1Hz的原始波,被10Hz的载波相载,得到调制波9Hz和11Hz,再重新乘以载波,9Hz和11Hz分别还原成1Hz,19Hz,-1Hz,21Hz。(推导公式与之前一样。)

因为我们已经知道波段大概范围,我们只提取出那一小段fft(滤波),再做ifft,x2(因为有一半能量被滤掉了)即可。

dm = Z.*C;
figure;plot(dm);
f = fft(dm);
figure;plot(abs(f));
title('fft after re-multiply tranporter');

filtre = zeros(1,N);
filtre(1,1:10) = 1;
filtre(1,end-10+1:end) = 1;
ff = filtre.*f;
dmm = real(ifft(ff))*2;
figure;plot(dmm);
title('Demodulation first by *T then by ifft');


另外的问题,如果因为传输的延迟,载波的相位也许不为0了。在无法确知载波相位的情况下,又如何恢复原始信号A呢?
原始信号cos(w0*t),载波cos(w1*t+phi).
调制信号m = cos(w0*t).*cos(w1*t+phi) = 0.5*(cos((w0+w1)*t+phi) + cos((w0-w1)*t-phi));
m.*cos(w1)  = 0.5*cos(w0*t)*cos(phi) = 0.5*A*cos(phi);
m.*sin(w1) = 0.5*cos(w0*t)*sin(phi) = 0.5*A*sin(phi);
所以2*sqrt((m.*cos(w1))^2+(m.*sin(w1))^2) = 2*0.5*A = A, 即原始信号。

(全文完 Fou)



rgbd 数据库

http://www0.cs.ucl.ac.uk/staff/M.Firman/RGBDdatasets/

http://m.blog.csdn.net/article/details?id=50081713

http://vslam.inf.tu-dresden.de/

ubuntu 彻底关闭x

今天又拿到同事一台電腦來搞 Web Server,原先安裝 Ubuntu Desktop 要把它關閉,避免佔用太多資源,12.04 採用 LightDM 來管理 X Display,輕量級及高效能管理工具,直接停止 LightDM 可以直接用底下 command line。

$ service lightdm stop

重新打开:
$ service lightdm start

也可以在当前终端只启动文件UI(不启动display-manager):
$ startx


如果開機直接不執行 X Display,可以透過底下步驟,

編輯 /etc/default/grub

用您個人喜歡的編輯器打開 /etc/default/grub 並且找到底下字串

GRUB_CMDLINE_LINUX_DEFAULT="<no matter what's you find here>"
改成

GRUB_CMDLINE_LINUX_DEFAULT="text"

重新產生 Grub

只要有修改 /etc/default/grub,請務必重執行

$ sudo update-grub
接著重新開機即可。

ubuntu gdb insight 快速安装

insight 是 gdb 的UI前端。

安装:
echo "deb http://ppa.launchpad.net/sevenmachines/dev/ubuntu natty main" | sudo tee -a /etc/apt/sources.list > /dev/null
echo "deb-src http://ppa.launchpad.net/sevenmachines/dev/ubuntu natty main" | sudo tee -a /etc/apt/sources.list > /dev/null
sudo apt-get update
sudo apt-get install insight
 
使用:
cmake -DCMAKE_BUILD_TYPE:STRING=Debug ../src 可以link到源代码,这样在insight里就可以看到了。 
 
注意:由于insight用的是老版本gdb,而ubuntu14.04自带新版本g++,在insight里无法查看local variables.所以要让g++生成老版本调试信息。
DWARF4 is now the default when generating DWARF debug information. When -g is used on a platform that uses DWARF debugging information, GCC will now default to -gdwarf-4 -fno-debug-types-section. GDB 7.5, Valgrind 3.8.0 and elfutils 0.154 debug information consumers support DWARF4 by default. Before GCC 4.8 the default version used was DWARF2. To make GCC 4.8 generate an older DWARF version use -g together with -gdwarf-2 or -gdwarf-3. The default for Darwin and VxWorks is still -gdwarf-2 -gstrict-dwarf.
So you need to use GDB 7.5 or compile with -g -gdwarf-2
 

ubuntu 最简单安装 opencv

sudo apt-get install libcv-dev libcvaux-dev libhighgui-dev libopencv-dev

搞定!

测试程序 main.cpp:

#include <opencv2/opencv.hpp>
using namespace cv;
int main(){
    Mat img = imread("test.jpg");
    imshow("1",img);
    waitKey(0);
    return 0;
}


以下是makefile:

CC=g++
CFLAGS = `pkg-config --cflags opencv`
LIBS = `pkg-config --libs opencv`

executable: main.cpp
    $(CC) main.cpp -o executable $(LIBS) $(CFLAGS)

vlc opencv

Finally the solution was to set a Linker Flag to /OPT:NOREF which is not optimizing your references. You could find this in the Visual Studio Settings by:
Configuration Properties->Linker->Optimization->References





#include "opencv2\highgui\highgui.hpp"
#include "opencv2\imgproc\imgproc.hpp"
#include <iostream>
#include <windows.h>
#include "vlc\libvlc.h"
#include "vlc\vlc.h"

#define WIDTH 800
#define HEIGHT 600

using namespace cv;

struct ctx
{
   Mat* image;
   HANDLE mutex;
   uchar *pixels;
};


void *lock( void *data, void**p_pixels )
{
   struct ctx *ctx = (struct ctx*)data;
   WaitForSingleObject( ctx->mutex, INFINITE );
   *p_pixels = ctx->pixels;
   return NULL;
}

void display( void *data, void *id )
{
   (void) data;
   assert( id == NULL );
}

void unlock( void *data, void *id, void *const *p_pixels )
{
   struct ctx *ctx = (struct ctx*)data;
   ReleaseMutex( ctx->mutex );
}

int main()
{
   libvlc_instance_t  *vlcInstance;
   libvlc_media_player_t *mp;
   libvlc_media_t   *media;
   
   const char *const vlc_args[] = {
  "--no-audio", /* skip any audio track */
        "--no-xlib", /* tell VLC to not use Xlib
      "-I",
       "dummy", 
      "--ignore-config", 
      "--extraintf=logger", 
      "--verbose=2",  */
   };

   int vlc_argc = sizeof(vlc_args)/sizeof(vlc_args[0]);

   //libvlc_instance_t* libvlc_new ( int argc, const char *const *argv )  
   //用於初始化一個libvlc的實例,argc表示參數的個數,argv表示參數,返回創建的實例若當發生錯誤時返回NULL
   vlcInstance = libvlc_new( vlc_argc, vlc_args );
   if( vlcInstance == NULL ){
    std::cout<<"Create Media Stream Error"<<std::endl;
    return 0;
   }

   //LIBVLC_API libvlc_media_t* libvlc_media_new_location( libvlc_instance_t *p_instance, const char *psz_mrl )  
   //使用一個給定的媒體資源路徑來建立一個libvlc_media對象,參數psz_mrl為要讀取的MRL(Media Resource Location),此函數返回新建的對像或NULL.
   const char *psz_mrl = "rtsp://192.168.1.150/media/video1";
   media = libvlc_media_new_location( vlcInstance, psz_mrl );
   if( media == NULL ){
    std::cout<<"Media Stream is Null"<<std::endl;
    return 0;
   }
   
   //LIBVLC_API libvlc_media_player_t* libvlc_media_player_new_from_media( libvlc_media_t *p_md )  
   //根據給定的媒體對象創建一個播放器對象
   mp = libvlc_media_player_new_from_media( media );

   // LIBVLC_API void libvlc_media_release( libvlc_media_t *p_md )  
   //減少一個libvlc_media_t的引用計數,如果減少到0時,此函數將釋放此對象(銷毀).它將發送一個libvlc_MediaFreed事件到所有的監聽者那裡。如果一個libvlc_media_t被釋放了,它就再也不能使用了。
   libvlc_media_release(media);


   struct ctx* context = (struct ctx*)malloc( sizeof(*context) );
   context->mutex      = CreateMutex( NULL, false, NULL );
   context->image      = new Mat( HEIGHT, WIDTH, CV_8UC3 );
   context->pixels     = (unsigned char *)context->image->data;   

   //設定Callback Function複製影像資訊,可藉由libvlc_video_set_format和libvlc_video_set_format_callbacks設定解碼資訊
   libvlc_video_set_callbacks( mp, lock, unlock, display, context );

   //設定影像解碼資訊
   const char *chroma = "RV24";
   unsigned width     = WIDTH;
   unsigned height    = HEIGHT;
   unsigned pitch     = WIDTH*24/8;
   libvlc_video_set_format( mp, chroma, width, height, pitch); 


   // LIBVLC_API int libvlc_media_player_play( libvlc_media_player_t *p_mi )  
   //開始播放串流影片
   libvlc_media_player_play(mp);

   Mat img;
   while( true ){    
  WaitForSingleObject( context->mutex, INFINITE );
  img = context->image->clone();
  ReleaseMutex( context->mutex );

  cv::imshow("test",img);
  std::cout<<"Image "<<img.cols<<std::endl;
  // cv::imwrite("cam.jpg", img);
      cv::waitKey( 40); 
   }

   libvlc_media_player_stop( mp );
   libvlc_media_player_release( mp );
   libvlc_release( vlcInstance );

   return 0;
}