标签:
kernellinux |
分类: 软件 |
转载自 http://blog.csdn.net/stone_kingnet/article/details/3196225
在头文件 中定义了 【8种可用的日志级别字符串】
KERN_EMERG
用于紧急事件消息,它们一般是系统崩溃之前提示的消息。
KERN_ALERT
用于需要立即采取动作的情况。
KERN_CRIT
临界状态,通常涉及严重的硬件或软件操作失败。
KERN_ERR
用于报告错误状态;设备驱动程序会经常使用KERN_ERR来报告来自硬件的问题。
KERN_WARNING
对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重问题。
KERN_NOTICE
有必要进行提示的正常情形。许多与安全相关的状况用这个级别进行汇报。
KERN_INFO
提示性信息。很多驱动程序在启动的时候,以这个级别打印出它们找到的硬件信息。
KERN_DEBUG
用于调试信息。
dmesg是从kernel的ring buffer(环缓冲区)中读取信息的.
那什么是ring buffer呢?
在LINUX中,所有的系统信息(包内核信息)都会传送到ring
buffer中.而内核产生的信息由printk()打印出来。系统启动时所看到的信息都是由该函数打印到屏幕中。
printk()打出的信息往往以 <0>...<2>...
这的数字表明消息的重要级别。高于一定的优先级别会打印到屏幕上,否则只会保留在系统的缓冲区中(ring buffer)。
至于dmesg具体是如何从ring buffer中读取的,大家可以看dmesg.c源代码.很短,比较容易读懂.
是syslogd这个守护进程根据/etc/syslog.conf,将不同的服务产生的Log记录到不同的文件中.
LINUX系统启动后,由/etc/init.d/sysklogd先后启动klogd,syslogd两个守护进程。
其中klogd会通过syslog()系统调用或者读取proc文件系统来从系统缓冲区(ring
buffer)中得到由内核printk()发出的信息.而syslogd是通过klogd来读取系统内核信息.
1>
所有系统信息是输出到ring buffer中去的.dmesg所显示的内容也是从ring buffer中读取的.
2>
LINUX系统中/etc/init.d/sysklogd会启动2个守护进程:Klogd, Syslogd
3>
klogd是负责读取内核信息的,有2种方式:
syslog()系统调用(这个函数用法比较全,大家去MAN一下看看)直接的对/proc/kmsg进行读取(再这提一下,/proc/kmsg是专门输出内核信息的地方)
4>
Klogd的输出结果会传送给syslogd进行处理,syslogd会根据/etc/syslog.conf的配置把log信息输出到/var/log/下的不同文件中.
注意将printk与syslog接合使用,
用在内核开发方面很不错.
内核用的打印函数printk完全是和stdin或stdout无关的,因为一开始到start_kernel函数刚开始进入内核就可以用printk 函数了,而建立stdin和stdout是在init函数中实现的。有个问题,这里的代码中,建立stdin和stdout如下
if (open("/dev/null", O_RDWR, 0) < 0)
printk("Warning: unable to open an initial console./n");
(void) dup(0);
(void) dup(0);
问题在于它打开的是/dev/null,而一般pc机上的linux打开的都是/dev/console,而且我把这几行代码删除也没有问题,所以我猜想这里建立stdin和stdout并没什么用,肯定在shell中建立了定位到串口的stdin和stdout。所以接下来还需要看看busybox的代码吧。
在这里还是主要分析一下printk实现的原理。
static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED; //定义logbuf_lock,并初始化为unlock状态
static char log_buf[LOG_BUF_LEN]; //保存日志数据的缓冲区
#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
static DECLARE_MUTEX(console_sem); //定义全局互斥信号量console_sem并初始化为1
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
unsigned long flags;
int printed_len;
char *p;
static char printk_buf[1024];
static int log_level_unknown = 1;
if (oops_in_progress) // default : oops_in_progress = 0
{ //oops_in_progress指示进程发生错误,只有在panic()函数中才等于1
//所以一般情况下下两句都不运行
spin_lock_init(&logbuf_lock); //初始化logbuf_lock
init_MUTEX(&console_sem); //初始化console_sem为互斥的信号量,初值为1
}
spin_lock_irqsave(&logbuf_lock, flags);
//一般spin_lock在单cpu中无效的,所以spin_lock_irqsave真正的作用是关中断 和保存状态寄存器。
va_start(args, fmt);
printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
//先把数据格式化到printk_buf中去
va_end(args);
//emit_log_char 把字符存入log_buf中等待被发送,具体的参见下面的分析
for (p = printk_buf; *p; p++) {
if (log_level_unknown) {
if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
emit_log_char('<');
emit_log_char(default_message_loglevel + '0');
emit_log_char('>');
}
//如果没有提供<1>类似的日志级别,则在此加上<4>
//我这里的default_message_loglevel=4
log_level_unknown = 0;
}
emit_log_char(*p);
if (*p == '/n') //每一行前面都需要加<4>之类的日志级别
log_level_unknown = 1;
}
if (!arch_consoles_callable()) // unexecute
{
spin_unlock_irqrestore(&logbuf_lock, flags);
goto out;
}
if (!down_trylock(&console_sem)) //lock ok
{
spin_unlock_irqrestore(&logbuf_lock, flags);
console_may_schedule = 0;
release_console_sem(); //在这个函数中把数据发送到串口并释放console_sem
} else {
spin_unlock_irqrestore(&logbuf_lock, flags);
}
out:
return printed_len;
}
static unsigned long log_start;
static unsigned long con_start;
static unsigned long log_end;
static unsigned long logged_chars;
static void emit_log_char(char c)
{
LOG_BUF(log_end) = c; //把字符c存到log_buf缓冲区中,缓冲区满了就会覆盖开始的数据
log_end++; //
if (log_end - log_start > LOG_BUF_LEN) //log_start指示syslog读取的开始
log_start = log_end - LOG_BUF_LEN;//缓冲区满了会把开始的指针向前推
if (log_end - con_start > LOG_BUF_LEN) //con_start指示控制台读取的开始
con_start = log_end - LOG_BUF_LEN;
if (logged_chars < LOG_BUF_LEN)
logged_chars++;
}
void release_console_sem(void)
{
unsigned long flags;
unsigned long _con_start, _log_end;
unsigned long must_wake_klogd = 0;
for ( ; ; ) {
spin_lock_irqsave(&logbuf_lock, flags);//关中断和保存flag
must_wake_klogd |= log_start - log_end; //唤醒klogd标志
if (con_start == log_end)
break;
_con_start = con_start;
_log_end = log_end;
con_start = log_end;
spin_unlock_irqrestore(&logbuf_lock, flags);
call_console_drivers(_con_start, _log_end);//在这个函数中发送数据,见下面的分析
}
console_may_schedule = 0; //指示数据发送时是否能进行任务调度,在使用串口控制台时没用
up(&console_sem); //释放信号量
spin_unlock_irqrestore(&logbuf_lock, flags);
if (must_wake_klogd && !oops_in_progress)
wake_up_interruptible(&log_wait);
}
static void call_console_drivers(unsigned long start, unsigned long end)
{
unsigned long cur_index, start_print;
static int msg_level = -1;
if (((long)(start - end)) > 0)
BUG();
cur_index = start;
start_print = start;
while (cur_index != end) {
if ( msg_level < 0 &&
((end - cur_index) > 2) &&
LOG_BUF(cur_index + 0) == '<' &&
LOG_BUF(cur_index + 1) >= '0' &&
LOG_BUF(cur_index + 1) <= '7' &&
LOG_BUF(cur_index + 2) == '>')
{
msg_level = LOG_BUF(cur_index + 1) - '0';
cur_index += 3;
start_print = cur_index;
} //去除每行开头的类似<4>的日志级别,把它赋给msg_level
while (cur_index != end) {
char c = LOG_BUF(cur_index);
cur_index++;
if (c == '/n') {
if (msg_level < 0) {
msg_level = default_message_loglevel;
}
_call_console_drivers(start_print, cur_index, msg_level);
//发送一行数据
msg_level = -1;
start_print = cur_index;
break;
}
}
}
_call_console_drivers(start_print, end, msg_level); //发送剩余的数据
}
struct console *console_drivers; //全局的console类型的结构体
static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level)
{
//如果msg_log_level < console_loglevel 并且 console_drivers存在 并且 start != end
if (msg_log_level < console_loglevel && console_drivers && start != end) {
if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
//缓冲区循环使用就会出现(start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)
//的清况,于是就分两部分来发送.
//__call_console_drivers才是真正的发送函数
__call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN);
__call_console_drivers(0, end & LOG_BUF_MASK);
} else {
__call_console_drivers(start, end);
}
}
}
static void __call_console_drivers(unsigned long start, unsigned long end)
{
struct console *con;
for (con = console_drivers; con; con = con->next) {
if ((con->flags & CON_ENABLED) && con->write)
con->write(con, &LOG_BUF(start), end - start);
} //调用console_drivers->write来把数据发送出去
}
接下来理解一下console_drivers这个结构体指针
struct console
{
char name[8];
void (*write)(struct console *, const char *, unsigned);
int (*read)(struct console *, const char *, unsigned);
kdev_t (*device)(struct console *);
int (*wait_key)(struct console *);
void (*unblank)(void);
int (*setup)(struct console *, char *);
short flags;
short index;
int cflag;
struct console *next;
};
而开始console_drivers这个指针是NULL的,在什么时候被赋值的呢,原本以为应该在用printk以前就被初始化了,其实不然,它是在start_kernel函数中调用的console_init()函数中被初始化的.最好的办法还是看看代码.
void __init console_init(void)
{
memset(ldiscs, 0, sizeof(ldiscs));
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
memset(&tty_std_termios, 0, sizeof(struct termios));
memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
tty_std_termios.c_iflag = ICRNL | IXON;
tty_std_termios.c_oflag = OPOST | ONLCR;
#ifdef CONFIG_MIZI //CONFIG_MIZI=1
tty_std_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL;
#else
tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
#endif
tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN;
#ifdef CONFIG_VT //如果不是串口控制台就定义这个虚拟控制台
con_init(); //于是输入是键盘输出是显示器
#endif
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
au1000_serial_console_init();
#endif
#ifdef CONFIG_SERIAL_CONSOLE
#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
console_8xx_init();
#elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL)
if (_machine == _MACH_Pmac)
mac_scc_console_init();
else
serial_console_init();
#elif defined(CONFIG_MAC_SERIAL)
mac_scc_console_init();
#elif defined(CONFIG_PARISC)
pdc_console_init();
#elif defined(CONFIG_SERIAL)
serial_console_init();
#endif
#ifdef CONFIG_SGI_SERIAL
sgi_serial_console_init();
#endif
#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
vme_scc_console_init();
#endif
#if defined(CONFIG_SERIAL167)
serial167_console_init();
#endif
#if defined(CONFIG_SH_SCI)
sci_console_init();
#endif
#endif
#ifdef CONFIG_TN3270_CONSOLE
tub3270_con_init();
#endif
#ifdef CONFIG_TN3215
con3215_init();
#endif
#ifdef CONFIG_HWC
hwc_console_init();
#endif
#ifdef CONFIG_STDIO_CONSOLE
stdio_console_init();
#endif
#ifdef CONFIG_SERIAL_CORE_CONSOLE // CONFIG_SERIAL_CORE_CONSOLE=1
uart_console_init(); //这里唯一一个被运行的函数
#endif
#ifdef CONFIG_ARC_CONSOLE
arc_console_init();
#endif
#ifdef CONFIG_SERIAL_TX3912_CONSOLE
tx3912_console_init();
#endif
}
void __init uart_console_init(void)
{
#ifdef CONFIG_SERIAL_AMBA_CONSOLE
ambauart_console_init();
#endif
#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE
anakin_console_init();
#endif
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
clps711xuart_console_init();
#endif
#ifdef CONFIG_SERIAL_21285_CONSOLE
rs285_console_init();
#endif
#ifdef CONFIG_SERIAL_SA1100_CONSOLE
sa1100_rs_console_init();
#endif
#ifdef CONFIG_SERIAL_8250_CONSOLE
serial8250_console_init();
#endif
#ifdef CONFIG_SERIAL_UART00_CONSOLE
uart00_console_init();
#endif
#ifdef CONFIG_SERIAL_S 3C2400_CONSOLE
s3c2400_console_init();
#endif
#ifdef CONFIG_SERIAL_S3C2410_CONSOLE
s3c2410_console_init(); //这个函数被运行
#endif
}
void __init s3c2410_console_init(void)
{
register_console(&s3c2410_cons); //调用注册控制台的函数
}
static struct console s3c2410_cons = {
name: "ttyS",
write: s3c2410_console_write,
device: s3c2410_console_device,
wait_key: s3c2410_console_wait_key,
setup: s3c2410_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
}; //这个就是console_drivers所指向的结构了
void register_console(struct console * console)
{ //该函数就是把console_drivers这个全局指针指向console结构体了,而且在注册完后
//会把存在缓冲区中的都发送出去,所以在注册console以前调用的printk并不发送数据
//而只是把数据存到缓冲区里,注册了以后才能被马上发送.多个控制台被注册的话就会
//形成一个链表结构,都能发送数据.
int i;
unsigned long flags;
if (preferred_console < 0) {
if (console->index < 0)
console->index = 0;
if (console->setup == NULL ||
console->setup(console, NULL) == 0) {
console->flags |= CON_ENABLED | CON_CONSDEV;
preferred_console = 0;
}
}
for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
if (strcmp(console_cmdline[i].name, console->name) != 0)
continue;
if (console->index >= 0 &&
console->index != console_cmdline[i].index)
continue;
if (console->index < 0)
console->index = console_cmdline[i].index;
if (console->setup &&
console->setup(console, console_cmdline[i].options) != 0)
break;
console->flags |= CON_ENABLED;
console->index = console_cmdline[i].index;
if (i == preferred_console)
console->flags |= CON_CONSDEV;
break;
}
if (!(console->flags & CON_ENABLED))
return;
acquire_console_sem();
if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
console->next = console_drivers;
console_drivers = console;
} else {
console->next = console_drivers->next;
console_drivers->next = console;
}
if (console->flags & CON_PRINTBUFFER) {
spin_lock_irqsave(&logbuf_lock, flags);
con_start = log_start;
spin_unlock_irqrestore(&logbuf_lock, flags);
}
release_console_sem();
}
| 分类: 装修 |
|
m |
metres |
| g | gram |
| mg | milligrams (10-3 grams) |
| µg | microgram (10-6 grams) |
| ppm | parts per million (volume/volume) |
| ppb | parts per billion (volume/volume) |
| mg/m3 | milligrams per cubic metres |
| µg/m3 | micrograms per cubic meter |
| Formaldehyde HCHO |
1 ppm = 1.2mg/m3 1mg/m3 = 0.833ppm |
标签:
shear-warpc代码 |
分类: 算法 |
根据硬件计算的架构,用C++建立了一个软件模型,证明硬件计算的可行性。
Shear之后的图像,C++结果:
http://s1/middle/679f93564bc33ebdb6710&690
MatLab Shear结果:
http://s1/middle/679f93564bc33ebdb9110&690
Warp结果,C++:
http://s10/middle/679f93564bc33ebea3429&690
MatLab Warp结果:
http://s14/middle/679f93564bc33ebf1533d&690
//shear-warp sw model
//zf2266#mail.ustc.edu.cn, Zhanxiang Zhao
#include <iostream>
#include <fstream>
#include "windows.h"
#include "math.h"
using std::endl;
using std::cout;
using std::cin;
#define LINE_LENGTH 81
#define LINE_SHEAR_LENGTH int(LINE_LENGTH*1.7321+2)
#define ALPHA_TABLE_SIZE 1000
#define DIM 4
#define IMAGE_SIZE 400
double volume[LINE_LENGTH][LINE_LENGTH][LINE_LENGTH];
double lineBuf[5][LINE_LENGTH];
double shearedBuf[LINE_SHEAR_LENGTH];
double interImgBuf[LINE_SHEAR_LENGTH*LINE_SHEAR_LENGTH];
double renderImage[IMAGE_SIZE*IMAGE_SIZE];
double alphaTable[ALPHA_TABLE_SIZE];
double Mview[DIM*DIM];
double Mshear[DIM*DIM];
double Mwarp[(DIM-1)*(DIM-1)];
double MshearInv[DIM*DIM];
double MwarpInv[(DIM-1)*(DIM-1)];
struct LUPMat
{
double* L, *U, *P; //dim*dim
int* pai; //dim
int dim; //dimension of LUP, size is d*d
};
void DelLUPMat( LUPMat lm)
{
delete [] lm.L;
delete [] lm.U;
delete [] lm.P;
delete [] lm.pai;
}
void printMatrix(double* mat, int dim)
{
for(int i=0; i<dim; i++)
{
for(int j=0; j<dim; j++)
printf("%2.5f ", mat[i*dim+j]);
printf("\n");
}
}
void printVector(double* vec, int dim)
{
for(int i=0; i<dim; i++)
{
printf("%2.2f ", vec[i]);
}
printf("\n");
}
//LUP decomposition of dim*dim matrix
LUPMat LUPDecomp(double *A, int dim)
{
double* mat = new double[dim*dim];
for(int i=0; i<dim; i++)
for(int j=0; j<dim; j++)
mat[i*dim+j] = A[i*dim+j];
double* l = new double[dim*dim];
double* u = new double[dim*dim];
double* p = new double[dim*dim];
int* pai = new int[dim]; //pai[i]=k, then p[i][k]=1
for(int i=0; i<dim; i++)
pai[i] = i;
double cmax; //max value of column
int maxLineNo; //line of cmax
for(int k=0; k<dim; k++)
{
//find max value of the k-th column
cmax=0;
for(int i=k; i<dim; i++)
{
if(abs(mat[i*dim+k])>abs(cmax))
{
cmax = mat[i*dim+k];
maxLineNo = i;
}
}
if(cmax==0)
{
printf("singular matrix!\n");
exit(1);
}
int tmpk = pai[k];
pai[k] = pai[maxLineNo];
pai[maxLineNo] = tmpk;
double tmpLn;
//exchange line
for(int li=0; li<dim; li++)
{
tmpLn = mat[k*dim+li];
mat[k*dim+li] = mat[maxLineNo*dim+li];
mat[maxLineNo*dim+li] = tmpLn;
}
//LU decomposition
for(int i=k+1; i<dim; i++)
{
mat[i*dim+k] = mat[i*dim+k]/mat[k*dim+k];
for(int j=k+1; j<dim; j++)
mat[i*dim+j] = mat[i*dim+j] - mat[i*dim+k]*mat[k*dim+j];
}
}
for(int i=0; i<dim; i++)
{
for(int j=0; j<dim; j++)
{
if(i>j)
{
l[i*dim+j] = mat[i*dim+j];
u[i*dim+j] = 0;
}
else if(i==j)
{
u[i*dim+j] = mat[i*dim+j];
l[i*dim+j] = 1;
}
else
{
u[i*dim+j] = mat[i*dim+j];
l[i*dim+j] = 0;
}
}
}
for(int i=0; i<dim; i++)
{
for(int j=0; j<dim; j++)
p[i*dim+j] = 0;
p[i*dim+pai[i]] = 1;
}
LUPMat ret;
ret.L = l;
ret.U = u;
ret.P = p;
ret.pai = pai;
ret.dim = dim;
delete [] mat;
return ret;
}
//testbench
void LUPDecomp_tb()
{
double mat[DIM*DIM] = {
2, 0, 2, 0.6,
3, 3, 4, -2,
5, 5, 4, 2,
-1, -2, 3.4, -1};
printMatrix(mat, DIM);
LUPMat lm = LUPDecomp(mat, DIM);
cout<<"P = "<<endl;
printMatrix(lm.P, DIM);
cout<<"L = "<<endl;
printMatrix(lm.L, DIM);
cout<<"U = "<<endl;
printMatrix(lm.U, DIM);
DelLUPMat(lm);
}
double *SolveLinearEq(double* A, double* b, int dim)
{
LUPMat lm = LUPDecomp(A, dim);
double* x = new double[dim];
double* y = new double[dim];
for(int i=0; i<dim; i++)
{
y[i] = b[lm.pai[i]];
for(int j=0; j<i; j++)
y[i] -= y[j]*lm.L[i*dim+j];
}
//cout<<"y:"<<endl;
// printVector(y, dim);
for(int i=dim-1; i>=0; i--)
{
for(int j=dim-1; j>i; j--)
y[i] -= lm.U[i*dim+j]*x[j];
x[i] = y[i]/lm.U[i*dim+i];
}
//cout<<"y:"<<endl;
// printVector(y, dim);
delete [] y;
DelLUPMat(lm);
return x;
}
void SolveLinearEq_tb()
{
const int dim=3;
double A[dim*dim] =
{1, 2, 0,
3, 4, 4,
5, 6, 3};
cout<<"A: "<<endl;
printMatrix(A, dim);
double b[dim] ={3, 7, 8};
double* x = SolveLinearEq(A, b, dim);
cout<<"x: "<<endl;
printVector(x, dim);
delete [] x;
}
double* InverseMatrix(double *A, int dim)
{
double *invA = new double[dim*dim];
double *e = new double[dim];
double *x;
for(int i=0; i<dim; i++)
e[i] = 0;
for(int i=0; i<dim; i++)
{
e[i] = 1;
if(i>0) e[i-1]=0;
x = SolveLinearEq(A, e, dim);
// cout<<"No. "<<i<<" x: ";
// printVector(x, dim);
// cout<<"e: ";
// printVector(e, dim);
for(int j=0; j<dim; j++)
invA[j*dim+i] = x[j];
}
delete [] x;
return invA;
}
//matrix multiply
double* MatMult(double* A, double* invA, int dim)
{
double* aij = new double[dim*dim];
for(int i=0; i<dim; i++)
for(int j=0; j<dim; j++)
{
aij[i*dim+j]=0;
for(int k=0; k<dim; k++)
aij[i*dim+j] += A[i*dim+k]*invA[k*dim+j];
}
return aij;
}
void InverseMatrix_tb()
{
const int dim=3;
double A[dim*dim] =
{1, 2, 0,
3, 4, 4,
5, 6, 3};
cout<<"A: "<<endl;
printMatrix(A, dim);
double* invA = InverseMatrix(A, dim);
cout<<"inverse of A: "<<endl;
printMatrix(invA, dim);
double* aij = MatMult(A, invA, dim);
cout<<"A*invA:"<<endl;
printMatrix(aij, dim);
delete [] invA;
delete [] aij;
}
void copyMatrix2D(double* src, double* des, int dim)
{
for(int i=0; i<dim; i++)
for(int j=0; j<dim; j++)
des[i*dim+j] = src[i*dim+j];
}
//compute shear warp matrix
//return principle viewing axis: c
int MakeShearWarpMat()
{
//Find the principal viewing axis
double Vo[DIM-1] ={
Mview[0*DIM+1]*Mview[1*DIM+2] - Mview[1*DIM+1]*Mview[0*DIM+2],
Mview[1*DIM+0]*Mview[0*DIM+2] - Mview[0*DIM+0]*Mview[1*DIM+2],
Mview[0*DIM+0]*Mview[1*DIM+1] - Mview[1*DIM+0]*Mview[0*DIM+1]
};
double maxv=Vo[0];
int c=0;
for(int i=1; i<DIM-1; i++)
{
if(Vo[i]>maxv)
{
maxv=Vo[i];
c=i;
}
}
// Choose the corresponding Permutation matrix P
double pyzx[DIM*DIM] = {0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1};
double pzxy[DIM*DIM] = {0,0,1,0, 1,0,0,0, 0,1,0,0, 0,0,0,1};
double pxyz[DIM*DIM] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
double* p;
double P[DIM*DIM];
if(c==0)
p = pyzx;
else if(c==1)
p = pzxy;
else //2
p = pxyz;
copyMatrix2D(p, P, DIM);
//Compute the permuted view matrix from Mview and P
double* invP = InverseMatrix(P, DIM);
//xiangge
cout<<"inv P:"<<endl;
printMatrix(invP, DIM);
double* Mview_p = MatMult(Mview, invP, DIM);
//xiangge
cout<<"inv(Mview_p):"<<endl;
printMatrix(Mview_p, DIM);
delete [] invP;
//180 degrees rotate detection
if(Mview_p[2*DIM+2]<0) c=c+3;
//Compute the shear coeficients from the permuted view matrix
double Si = (Mview_p[1*DIM+1]* Mview_p[0*DIM+2] - Mview_p[0*DIM+1]* Mview_p[1*DIM+2]) / (Mview_p[0*DIM+0]* Mview_p[1*DIM+1] - Mview_p[1*DIM+0]* Mview_p[0*DIM+1]);
double Sj = (Mview_p[0*DIM+0]* Mview_p[1*DIM+2] - Mview_p[1*DIM+0]* Mview_p[0*DIM+2]) / (Mview_p[0*DIM+0]* Mview_p[1*DIM+1] - Mview_p[1*DIM+0]* Mview_p[0*DIM+1]);
double Ti, Tj;
// Compute the translation between the orgins of standard object coordinates
// and intermdiate image coordinates
double kmax = LINE_LENGTH-1;
if ((Si>=0)&&(Sj>=0)){ Ti = 0; Tj = 0; }
if ((Si>=0)&&(Sj<0)){ Ti = 0; Tj = -Sj*kmax; }
if ((Si<0)&&(Sj>=0)){ Ti = -Si*kmax; Tj = 0; }
if ((Si<0)&&(Sj<0)){ Ti = -Si*kmax; Tj = -Sj*kmax; }
// Compute the shear matrix
double mshear[DIM*DIM]=
{
1, 0, Si, Ti,
0, 1, Sj, Tj,
0, 0, 1 ,0 ,
0, 0, 0 ,1
};
copyMatrix2D(mshear, Mshear, DIM);
// Compute the 2Dwarp matrix
double mwarp[(DIM-1)*(DIM-1)]={
Mview_p[0*DIM+0], Mview_p[0*DIM+1], (Mview_p[0*DIM+3]-Ti*Mview_p[0*DIM+0]-Tj*Mview_p[0*DIM+1]),
Mview_p[1*DIM+0], Mview_p[1*DIM+1], (Mview_p[1*DIM+3]-Ti*Mview_p[1*DIM+0]-Tj*Mview_p[1*DIM+1]),
0, 0, 1
};
copyMatrix2D(mwarp, Mwarp, DIM-1);
return c;
}
//bilinear interpolation of 4 points
double Interp(double* intensity, double* perc)
{
double result=0.0f;
for(int i=0; i<4; i++)
result += intensity[i] * perc[i];
//Attention: should not use: *intensity++ * *perc++,
//for system can delete array normally without the change of pointer
return result;
}
//
void Shear()
{
cout<<"Start Shear"<<endl;
double* invshear = InverseMatrix(Mshear, DIM);
copyMatrix2D(invshear, MshearInv, DIM);
double* invwarp = InverseMatrix(Mwarp, DIM-1);
copyMatrix2D(invwarp, MwarpInv, DIM-1);
cout<<"MshearInv:"<<endl;
printMatrix(MshearInv, DIM);
cout<<"MwarpInv:"<<endl;
printMatrix(MwarpInv, DIM-1);
delete [] invshear;
delete [] invwarp;
//c=0
int py[LINE_LENGTH-1];
int px[LINE_LENGTH-1];
for(int z=0; z<(LINE_LENGTH-1); z++)
{
cout<<"Shear Slice "<<z+1<<endl;
//Offset calculation
double xd=(0-(double)LINE_SHEAR_LENGTH/2)+MshearInv[0*DIM+2]*((double)z-(double)LINE_LENGTH/2)+(double)LINE_LENGTH/2;
double yd=(0-(double)LINE_SHEAR_LENGTH/2)+MshearInv[1*DIM+2]*((double)z-(double)LINE_LENGTH/2)+(double)LINE_LENGTH/2;
double xdfloor=floor(xd);
double ydfloor=floor(yd);
//calculate the coordinates on which a image slice starts and
//ends in the temporary shear image (buffer)
double pystart=-ydfloor;
if(pystart<0) pystart=0;
double pyend = LINE_LENGTH-ydfloor;
if(pyend>LINE_SHEAR_LENGTH) pyend=LINE_SHEAR_LENGTH;
double pxstart=-xdfloor;
if(pxstart<0) pxstart=0;
double pxend = LINE_LENGTH-xdfloor;
if(pxend>LINE_SHEAR_LENGTH) pxend=LINE_SHEAR_LENGTH;
int npy = pyend-pystart-1;
int npx = pxend-pxstart-1;
py[0] = pystart;
for(int i=1; i<npy; i++)
py[i] = py[i-1]+1;
px[0] = pxstart;
for(int i=1; i<npx; i++)
px[i] = px[i-1]+1;
//Linear interpolation constants (percentages)
double xCom=xd-floor(xd);
double yCom=yd-floor(yd);
double perc[4]={(1-xCom)*(1-yCom), (1-xCom)*yCom, xCom*(1-yCom), xCom*yCom};
double intensity_loc;
double intensityInterp[4];
double alphaimage;
double alphaimage_inv;
double shearedimage;
int indexAlpha;
//Determine x and y coordinates of pixel(s) which will be come current pixel
//bilinear
for(int iy=0; iy<npy-1; iy++)
{
for(int ix=0; ix<npx-1; ix++)
{
intensityInterp[0] = volume[z][int(px[ix])+int(xdfloor)][int(py[iy])+int(ydfloor)];
intensityInterp[1] = volume[z][int(px[ix])+int(xdfloor)][int(py[iy])+int(ydfloor)+1];
intensityInterp[2] = volume[z][int(px[ix])+int(xdfloor)+1][int(py[iy])+int(ydfloor)];
intensityInterp[3] = volume[z][int(px[ix])+int(xdfloor)+1][int(py[iy])+int(ydfloor)+1];
intensity_loc = Interp(intensityInterp, perc);
//calculate current alphaimage
indexAlpha = floor(intensity_loc*(ALPHA_TABLE_SIZE-1)+0.5)+1;
alphaimage=alphaTable[indexAlpha];
alphaimage_inv=(1-alphaimage);
//Update the current pixel in the shear image buffer
interImgBuf[int(px[ix])*LINE_SHEAR_LENGTH+int(py[iy])]=alphaimage_inv*interImgBuf[int(px[ix])*LINE_SHEAR_LENGTH+int(py[iy])]+alphaimage*intensity_loc;
}
}
cout<<"sheared intermediate image: "<<endl;
std::ofstream ofShear("shearImg.dat");
for(int i=0; i<LINE_SHEAR_LENGTH; i++)
{
for(int j=0; j<LINE_SHEAR_LENGTH; j++)
ofShear<<interImgBuf[i*LINE_SHEAR_LENGTH+j]<<" ";
ofShear<<endl;
}
ofShear.close();
}
cout<<"exit shear"<<endl;
}
//set x to boundary
void setBoundary(double &x, double floor, double ceil)
{
if(x<floor) x=floor;
if(x>ceil-1) x=ceil-1;
}
//
void Warp()
{
//format the output image
for(int i=0; i<IMAGE_SIZE; i++)
{
for(int j=0; j<IMAGE_SIZE; j++)
{
renderImage[i*IMAGE_SIZE+j] = 0;
}
}
cout<<"start Warp"<<endl;
double *Tlocalx = new double[IMAGE_SIZE*IMAGE_SIZE];
double *Tlocaly = new double[IMAGE_SIZE*IMAGE_SIZE];
double *xbas = new double[IMAGE_SIZE*IMAGE_SIZE];
double *ybas = new double[IMAGE_SIZE*IMAGE_SIZE];
double *tx = new double[IMAGE_SIZE*IMAGE_SIZE];
double *ty = new double[IMAGE_SIZE*IMAGE_SIZE];
//center of output image
double mean_out = IMAGE_SIZE/2;
//center of input image
double mean_in = LINE_SHEAR_LENGTH/2;
double percInterp[4];
double imageInterp[4];
bool check_xbas0, check_ybas0, check_xbas1, check_ybas1;
for(int i=0; i<IMAGE_SIZE; i++)
{
for(int j=0; j<IMAGE_SIZE; j++)
{
//center of output image coordinates is (0,0)
double xd = i-mean_out;
double yd = j-mean_out;
//Calculate the Transformed coordinates
Tlocalx[i*IMAGE_SIZE+j] = mean_in + MwarpInv[0*(DIM-1)+0]*xd + MwarpInv[0*(DIM-1)+1]*yd + (MwarpInv[0*(DIM-1)+2]+MshearInv[0*DIM+3]) * 1;
Tlocaly[i*IMAGE_SIZE+j] = mean_in + MwarpInv[1*(DIM-1)+0]*xd + MwarpInv[1*(DIM-1)+1]*yd + (MwarpInv[1*(DIM-1)+2]+MshearInv[1*DIM+3]) * 1;
//Interp coordinates
xbas[i*IMAGE_SIZE+j] = floor(Tlocalx[i*IMAGE_SIZE+j]);
ybas[i*IMAGE_SIZE+j] = floor(Tlocaly[i*IMAGE_SIZE+j]);
tx[i*IMAGE_SIZE+j] = Tlocalx[i*IMAGE_SIZE+j] - xbas[i*IMAGE_SIZE+j];
ty[i*IMAGE_SIZE+j] = Tlocaly[i*IMAGE_SIZE+j] - ybas[i*IMAGE_SIZE+j];
}
}
for(int i=0; i<IMAGE_SIZE-1; i++)
{
for(int j=0; j<IMAGE_SIZE-1; j++)
{
percInterp[0] = (1-tx[i*IMAGE_SIZE+j])*(1-ty[i*IMAGE_SIZE+j]);
percInterp[1] = (1-tx[i*IMAGE_SIZE+j])*ty[i*IMAGE_SIZE+j];
percInterp[2] = tx[i*IMAGE_SIZE+j]*(1-ty[i*IMAGE_SIZE+j]);
percInterp[3] = tx[i*IMAGE_SIZE+j]*ty[i*IMAGE_SIZE+j];
//limit indices to boundaries
check_xbas0 = xbas[i*IMAGE_SIZE+j]<0 || xbas[i*IMAGE_SIZE+j]>(LINE_SHEAR_LENGTH-1);
check_ybas0 = ybas[i*IMAGE_SIZE+j]<0 || ybas[i*IMAGE_SIZE+j]>(LINE_SHEAR_LENGTH-1);
check_xbas1 = (xbas[i*IMAGE_SIZE+j]+1)<0 || (xbas[i*IMAGE_SIZE+j]+1)>(LINE_SHEAR_LENGTH-1);
check_ybas1 = (ybas[i*IMAGE_SIZE+j]+1)<0 || (ybas[i*IMAGE_SIZE+j]+1)>(LINE_SHEAR_LENGTH-1);
//set to boundary
setBoundary(xbas[i*IMAGE_SIZE+j], 0, LINE_SHEAR_LENGTH);
setBoundary(xbas[i*IMAGE_SIZE+j], -1, LINE_SHEAR_LENGTH-1); //xbas[i]+1
setBoundary(ybas[i*IMAGE_SIZE+j], 0, LINE_SHEAR_LENGTH);
setBoundary(ybas[i*IMAGE_SIZE+j], -1, LINE_SHEAR_LENGTH-1);
imageInterp[0] = interImgBuf[int(xbas[i*IMAGE_SIZE+j])*LINE_SHEAR_LENGTH+int(ybas[i*IMAGE_SIZE+j])];
imageInterp[1] = interImgBuf[int(xbas[i*IMAGE_SIZE+j])*LINE_SHEAR_LENGTH+int(ybas[i*IMAGE_SIZE+j]+1)];
imageInterp[2] = interImgBuf[int(xbas[i*IMAGE_SIZE+j]+1)*LINE_SHEAR_LENGTH+int(ybas[i*IMAGE_SIZE+j])];
imageInterp[3] = interImgBuf[int(xbas[i*IMAGE_SIZE+j]+1)*LINE_SHEAR_LENGTH+int(ybas[i*IMAGE_SIZE+j]+1)];
imageInterp[0] = (check_xbas0 || check_ybas0) ? 0 : imageInterp[0];
imageInterp[1] = (check_xbas0 || check_ybas1) ? 0 : imageInterp[1];
imageInterp[2] = (check_xbas1 || check_ybas0) ? 0 : imageInterp[2];
imageInterp[3] = (check_xbas0 || check_ybas1) ? 0 : imageInterp[3];
renderImage[i*IMAGE_SIZE+j] = Interp(imageInterp, percInterp);
}
}
delete [] Tlocalx ;
delete [] Tlocaly ;
delete [] xbas ;
delete [] ybas ;
delete [] tx ;
delete [] ty ;
cout<<"exit Warp"<<endl;
}
//
bool render(const char* volumefile, const char* alphafile)
{
for(int i=0; i<LINE_SHEAR_LENGTH; i++)
{
for(int j=0; j<LINE_SHEAR_LENGTH; j++)
interImgBuf[i*LINE_SHEAR_LENGTH+j]=0;
}
for(int i=0; i<LINE_LENGTH; i++)
{
for(int j=0; j<LINE_LENGTH; j++)
renderImage[i*LINE_LENGTH+j]=0;
}
std::ifstream ifVolume(volumefile);
if(ifVolume.fail())
{
cout<<"unable to open volume file!"<<endl;
return false;
}
//read volume
for(int i=0; i<LINE_LENGTH; i++)
for(int j=0; j<LINE_LENGTH; j++)
for(int k=0; k<LINE_LENGTH; k++)
{
ifVolume>>volume[i][j][k];
}
ifVolume.close();
std::ifstream ifAlpha(alphafile);
if(ifAlpha.fail())
{
cout<<"unable to open alpha table file!"<<endl;
return false;
}
//read alpha table
for(int i=0; i<ALPHA_TABLE_SIZE; i++)
ifAlpha>>alphaTable[i];
ifAlpha.close();
int c=MakeShearWarpMat();
cout<<"Mshear:"<<endl;
printMatrix(Mshear, DIM);
cout<<"Mwarp:"<<endl;
printMatrix(Mwarp, DIM-1);
Shear();
Warp();
std::ofstream ofImage("render.dat");
for(int i=0; i<IMAGE_SIZE; i++)
{
for(int j=0; j<IMAGE_SIZE; j++)
ofImage<<renderImage[i*IMAGE_SIZE+j]<<" ";
ofImage<<endl;
}
ofImage.close();
}
int main()
{
double mview[DIM*DIM]=
{ 0.6783, 1.6190, -0.2468, 0,
0.9310, -0.1614, 1.4998, 0,
1.3473, -0.7035, -0.9121, 0,
0, 0, 0, 1.0000
};
copyMatrix2D(mview, Mview, DIM);
const char* volumefile = "volume.dat";
const char* alphafile = "alphatable.dat";
render(volumefile, alphafile);
system("pause");
}
标签:
xil_printfprintfsdkxilinxmicroblazeit |
分类: 硬件 |
在xilinx SDK基于microblaze测试pcie示例程序一直不能run,简单的下面代码
printf("x=%8.8x\n", x);
xil_printf("x=%8.8x\n", x);
第一个就不能运行,第二个就可以。很奇怪。
http://www.eefocus.com/walkie/blog/09-02/165549_bf04c.html
这篇文章讲了一些区别,但没解释我看到的现象。
标签:
矩阵求逆ccpplup分解 |
分类: 算法 |
按照算法导论上矩阵求逆的原理,写了个C++代码。
有A*X=I,则X为inv(A)。
struct LUPMat
{
float* L, *U, *P; //dim*dim
int* pai; //dim
int dim; //dimension of LUP, size is d*d
};
void DelLUPMat( LUPMat lm)
{
delete [] lm.L;
delete [] lm.U;
delete [] lm.P;
delete [] lm.pai;
}
void printMatrix(float* mat, int dim)
{
for(int i=0; i<dim; i++)
{
for(int j=0; j<dim; j++)
printf("%2.2f ", mat[i*dim+j]);
printf("\n");
}
}
void printVector(float* vec, int dim)
{
for(int i=0; i<dim; i++)
{
printf("%2.2f ", vec[i]);
}
printf("\n");
}
//LUP decomposition of dim*dim matrix
LUPMat LUPDecomp(float *A, int dim)
{
float* mat = new float[dim*dim];
for(int i=0; i<dim; i++)
for(int j=0; j<dim; j++)
mat[i*dim+j] = A[i*dim+j];
float* l = new float[dim*dim];
float* u = new float[dim*dim];
float* p = new float[dim*dim];
int* pai = new int[dim]; //pai[i]=k, then p[i][k]=1
for(int i=0; i<dim; i++)
pai[i] = i;
float cmax; //max value of column
int maxLineNo; //line of cmax
for(int k=0; k<dim; k++)
{
//find max value of the k-th column
cmax=0;
for(int i=k; i<dim; i++)
{
if(abs(mat[i*dim+k])>abs(cmax))
{
cmax = mat[i*dim+k];
maxLineNo = i;
}
}
if(cmax==0)
{
printf("singular matrix!\n");
exit(1);
}
int tmpk = pai[k];
pai[k] = pai[maxLineNo];
pai[maxLineNo] = tmpk;
float tmpLn;
//exchange line
for(int li=0; li<dim; li++)
{
tmpLn = mat[k*dim+li];
mat[k*dim+li] = mat[maxLineNo*dim+li];
mat[maxLineNo*dim+li] = tmpLn;
}
//LU decomposition
for(int i=k+1; i<dim; i++)
{
mat[i*dim+k] = mat[i*dim+k]/mat[k*dim+k];
for(int j=k+1; j<dim; j++)
mat[i*dim+j] = mat[i*dim+j] - mat[i*dim+k]*mat[k*dim+j];
}
}
for(int i=0; i<dim; i++)
{
for(int j=0; j<dim; j++)
{
if(i>j)
{
l[i*dim+j] = mat[i*dim+j];
u[i*dim+j] = 0;
}
else if(i==j)
{
u[i*dim+j] = mat[i*dim+j];
l[i*dim+j] = 1;
}
else
{
u[i*dim+j] = mat[i*dim+j];
l[i*dim+j] = 0;
}
}
}
for(int i=0; i<dim; i++)
{
for(int j=0; j<dim; j++)
p[i*dim+j] = 0;
p[i*dim+pai[i]] = 1;
}
LUPMat ret;
ret.L = l;
ret.U = u;
ret.P = p;
ret.pai = pai;
ret.dim = dim;
delete [] mat;
return ret;
}
//testbench
void LUPDecomp_tb()
{
float mat[DIM*DIM] = {
2, 0, 2, 0.6,
3, 3, 4, -2,
5, 5, 4, 2,
-1, -2, 3.4, -1};
printMatrix(mat, DIM);
LUPMat lm = LUPDecomp(mat, DIM);
cout<<"P = "<<endl;
printMatrix(lm.P, DIM);
cout<<"L = "<<endl;
printMatrix(lm.L, DIM);
cout<<"U = "<<endl;
printMatrix(lm.U, DIM);
DelLUPMat(lm);
}
float *SolveLinearEq(float* A, float* b, int dim)
{
LUPMat lm = LUPDecomp(A, dim);
float* x = new float[dim];
float* y = new float[dim];
for(int i=0; i<dim; i++)
{
y[i] = b[lm.pai[i]];
for(int j=0; j<i; j++)
y[i] -= y[j]*lm.L[i*dim+j];
}
//cout<<"y:"<<endl;
printVector(y, dim);
for(int i=dim-1; i>=0; i--)
{
for(int j=dim-1; j>i; j--)
y[i] -= lm.U[i*dim+j]*x[j];
x[i] = y[i]/lm.U[i*dim+i];
}
//cout<<"y:"<<endl;
printVector(y, dim);
delete [] y;
DelLUPMat(lm);
return x;
}
void SolveLinearEq_tb()
{
const int dim=3;
float A[dim*dim] =
{1, 2, 0,
3, 4, 4,
5, 6, 3};
cout<<"A: "<<endl;
printMatrix(A, dim);
float b[dim] ={3, 7, 8};
float* x = SolveLinearEq(A, b, dim);
cout<<"x: "<<endl;
printVector(x, dim);
delete [] x;
}
float* InverseMatrix(float *A, int dim)
{
float *invA = new float[dim*dim];
float *e = new float[dim];
float *x;
for(int i=0; i<dim; i++)
e[i] = 0;
for(int i=0; i<dim; i++)
{
e[i] = 1;
if(i>0) e[i-1]=0;
x = SolveLinearEq(A, e, dim);
// cout<<"No. "<<i<<" x: ";
printVector(x, dim);
// cout<<"e: ";
printVector(e, dim);
for(int j=0; j<dim; j++)
invA[j*dim+i] = x[j];
}
delete [] x;
return invA;
}
float* isInverse(float* A, float* invA, int dim)
{
float* aij = new float[dim*dim];
for(int i=0; i<dim; i++)
for(int j=0; j<dim; j++)
{
aij[i*dim+j]=0;
for(int k=0; k<dim; k++)
aij[i*dim+j] += A[i*dim+k]*invA[k*dim+j];
}
return aij;
}
void InverseMatrix_tb()
{
const int dim=3;
float A[dim*dim] =
{1, 2, 0,
3, 4, 4,
5, 6, 3};
cout<<"A: "<<endl;
printMatrix(A, dim);
float* invA = InverseMatrix(A, dim);
cout<<"inverse of A: "<<endl;
printMatrix(invA, dim);
float* aij = isInverse(A, invA, dim);
cout<<"A*invA:"<<endl;
printMatrix(aij, dim);
delete [] invA;
delete [] aij;
}
测试程序的结果:
标签:
cmut压电陶瓷超声换能器 |
分类: 医疗成像 |
作为新型的二维超声换能器阵列,CMUT阵列相比原来的二维压电陶瓷换能器阵列有什么优势呢,我们来看一篇论文:引文1,斯坦福大学Omer Oralkan等人通过CMUT换能器与压电陶瓷换能器的实验比较,测试了CMUT的性能。里面比较了CMUT与二维压电陶瓷换能器。
二维压电陶瓷换能器缺点:
而CMUT优势:
论文中用直径36um CMUT和400us*400um压电换能器做实验。下图为压电陶瓷PZT与CMUT灵敏度比较,相比CMUT 200% Cp(寄生电容)模型,压电陶瓷只在中心频率3MHz附近有优势。通过把接收放大器集成到CMUT芯片上,可以降低寄生电容。
http://s16/middle/679f93564baf73bbd0e0f&690
二者信噪比比较,压电陶瓷只在中心频率3MHz附近有优势。
http://s13/middle/679f93564baf73bd2878c&690
[1] O. Oralkan, X. Jin, F. L.Degertekin, and B. T.Khuri-Yakub, "Simulation and experimental characterization of a 2-D capacitive micromachined ultrasonic transducer array element," IEEE Trans. Ultrason. Ferroelect. Freq. Contr., vol. 46, pp. 1337–1340, Nov. 1999.
标签:
fieldii医疗超声成像建模matlab |
分类: 医疗成像 |
昨天开组会大家讨论问题,有几个疑问被提出来了:
本文只讨论第一个问题,第二个另文细述。
和大二小师弟讨论Field II建模CMUT换能器时,发现Field II的Matlab代码只是来做参数配置和调用函数的,这些函数编译为可执行文件,主要的建模算法是用C代码实现,而这个代码并没有开源。我给Dr. Jensen发了封邮件要C代码,但愿能回复我。
使用空间冲击响应(spatial impulse response)的原理,依托于超声场的线性系统理论。发射时,当换能器被狄拉克delta函数激发后,空间中每个点的声场是关于时间的函数。声场可以通过空间冲激响应和激发函数卷积得到。接收时,把换能器激发函数和发射孔径的空间冲击响应、接受孔径的空间冲击响应卷积得到接收响应,通过换能器的机械电子传递函数得到接收电压曲线。
如果只是用Field II仿真声场,可以直接调用Matlab函数,配置参数,比如探头的物理参数(阵元类型,数量,尺寸,探测物,接收孔径等),然后得到接收信号,可以拿来波束合成。我们用一段示例程序来产生血流的接收波束信号如图。
http://s13/middle/679f93564baf697eb57fc&690
% This examples shows how the procedures can be used for making flow data from a number of scatters in a tube.
% Example of use of the new Field II program running under Matlab
%
% This example shows how flow can simulated
%
% This script assumes that the field_init procedure has been called
%
% Example by Joergen Arendt Jensen, March 22, 2011.
% Generate the transducer apertures for send and receive
f0=3e6; % Transducer center frequency [Hz]
fs=100e6; % Sampling frequency [Hz]
c=1540; % Speed of sound [m/s],人体内声音平均速度
lambda=c/f0; % Wavelength
element_height=5/1000; % Height of element [m]
kerf=0.1/1000; % Kerf [m]
focus=[0 0 70]/1000; % Fixed focal point [m]
% Generate aperture
aperture = xdc_linear_array (128, lambda/2, element_height, kerf, 1, 1,focus);
% Set the impulse response and excitation of the emit aperture
impulse_response=sin(2*pi*f0*(0:1/fs:2/f0));
impulse_response=impulse_response.*hanning(max(size(impulse_response)))';
xdc_impulse (aperture, impulse_response);
excitation=sin(2*pi*f0*(0:1/fs:8/f0));
xdc_excitation (aperture, excitation);
% Set the seed of the random number generator
randn('seed',sum(100*clock))
% Initialize the ranges for the scatterers,血管里面的物质
% Notice that the coordinates are in meters
x_range=0.015; % x range for the scatterers [m]
y_range=0.015; % y range for the scatterers [m]
z_range=0.015; % z range for the scatterers [m]
z_offset=0.70; % Offset of the mid-point of the scatterers [m]
R=0.005; % Radius of blood vessel [m]
% Set the number of scatterers. It should be roughly
% 10 scatterers per resolution cell
c=1540; % Ultrasound propagation velocity [m/s]
f0=3e6; % Center frequency of transducer [Hz]
lambda=c/f0;
N=round(10*x_range/(5*lambda)*y_range/(5*lambda)*z_range/(lambda*2));
disp([num2str(N),' Scatterers'])
% Generate the coordinates and amplitude
% Coordinates are rectangular within the range.
% The amplitude has a Gaussian distribution.
x=x_range*(rand(1,N)-0.5);
y=y_range*(rand(1,N)-0.5);
z=z_range*(rand(1,N)-0.5);
% Find which scatterers that lie within the blood vessel
r=(y.^2+z.^2).^0.5;
within_vessel= (r < R)';
% Assign an amplitude and a velocity for each scatterer
v0=0.5; % Largest velocity of scatterers [m/s]
velocity=v0*(1-(r/R).^2).*within_vessel';
blood_to_stationary= 0.1; % Ratio between amplitude of blood to stationary tissue
amp=randn(N,1).*((1-within_vessel) + within_vessel*blood_to_stationary);
% Calculate a suitable Tprf
theta=45/180*pi;
f_max=2*v0*cos(theta)/c*f0;
fprf=3*f_max;
Tprf=1/fprf; % Time between pulse emissions [s]
Nshoots=128; % Number of shoots
% Find the response by calling field
for i=1:Nshoots
i
% Generate the rotated and offset block of sample
xnew=x*cos(theta)+z*sin(theta);
znew=z*cos(theta)-x*sin(theta) + z_offset;
scatterers=[xnew; y; znew;]' ;
% Calculate the received response
[v, t1]=calc_scat(aperture, aperture, scatterers, amp);
% Store the result
image_data(1:max(size(v)),i)=v;
times(i) = t1;
% Propagate the scatterers and alias them
% to lie within the correct range
x=x + velocity*Tprf;
outside_range= (x > x_range/2);
x=x - x_range*outside_range;
end
% Here the display of the data
% Here the display of the data is inserted
plot(image_data)
标签:
volumerenderingshear-warp三维成像 |
分类: 算法 |
常见的三维成像有表面绘制和体绘制,surface rendering, volume rendering,后者需要庞大的计算量,为了利用硬件加速计算的的优势,我只关注volume rendering。
主要包括以下方法:
( 1 ) 基于图像空间扫描的绘制, 如光线投射( Ray Casting ) 算法;该方法是对射入观察者眼睛的所有光线,沿着光线路径对所有体元按照颜色和不透明度积分得到最后射出的颜色。Ray tracing:逆向跟踪射入的光线,遇到交点时类似积分。
( 2 ) 基于物体空间扫描的绘制, 如足迹表法( 又叫是splatting算法) 、 错切变形( Shear-Warp ) 算法、 体元投射( Cell Projection ) 法等。
其中Shear-Warp算法把三维投影变为三维数据场错切shear和二维图像变形warp两步实现,是目前最快的Volume Rendering算法。
我们来看看斯坦福大学Philippe Lacroute和 Marc Levoy的论文Fast Volume Rendering Using a Shear-Warp Factorization of the Viewing Transformation,Shear-Warp算法分为三个步骤:
http://s9/middle/679f93564bab577d54e98&690
http://s3/middle/679f93564bab577dc4602&690
Shear-Warp相当于对原坐标系做了变换,变换矩阵为:
http://s11/middle/679f93564bab577e41dea&690
P说明以那个方向为主轴来切片,有xyz三种可能。S从物体空间变到错切空间。M(warp)再变回图像空间。以z为主轴时,平行投影S有
http://s15/middle/679f93562f4b16b0aeb3e&690
透视投影S有,
http://s1/middle/679f93564bab5781e5860&690
其中切片z0被拉伸了http://s5/middle/679f93564bab5781ddd04&690。矩阵元素从M(view)得到。
最后,
http://s16/middle/679f93564bab57821840f&690
图3为前述三个步骤详解。
http://s2/middle/679f93564bab5782e6001&690
对于平行投影,首先对于原数据游程编码RLE(run-length encode),
http://s1/middle/679f93564bab57830b870&690
这篇文章还提出了一种alpha传递函数,通过递归的办法实现透明度可变时的行程编码。先得到一个立方体八个顶点确定的八叉树,查表计算立方体是否透明,不透明则继续递归计算更小立方体,直到体积小到一定值。