精华内容
下载资源
问答
  • 农业科技成果推广的相关概念与周期性原理.pptx
  • 周期性动作原理表述如下:1)用周期性的动作(脉冲)代替连续的动作;2)如果动作已经是周期性的,则改变其频率:3)利用脉动之间的停顿来执行额外的动作;尝试改变物体的运动规律--频率(将连续的动作试作频率为0)...

    周期性动作原理表述如下:
    1)用周期性的动作(脉冲)代替连续的动作;
    2)如果动作已经是周期性的,则改变其频率:
    3)利用脉动之间的停顿来执行额外的动作;

    尝试改变物体的运动规律--频率(将连续的动作试作频率为0),通过增大频率或降低频率来看看是否可以获得新的功能或者是强化某种功能,也可以尝试利用周期性动作的间歇来执行其它额外的动作,以充分利用系统的资源;案例如下:
    A)警笛和警灯:
    B) 冲击钻,蛤蟆夯;
    C)计算机指令;
    D)Windows操作系统的基本指令执行周期:
    E)汽车的雨刷器;
    ....

    如果有些周期性动作的间隙时间比较长,那么可以充分利用这种间隙时间来完成其它功能,就可以起到充分利用资源的目的,比如上述案例中的D。周期性原理中第3)条的利用非常广泛,无论是在管理领域还是生产领域都一样。

    周期性动作比连续性动作不同之处在于周期性动作有间歇,会得到“振动”效果。如果能利用到共振作用,则动作的周期性化会更加有利。
    当然不是所有的动作都需要改为周期性的,这个原理也仅仅是告诉一个方向,具体的问题还是需要具体分析。

    展开全文
  • 为分析石英MEMS陀螺仪的周期性误差在INS系统导航过程中引起误差的原理,研究了数据平滑过程对周期性误差参数的影响原理,并利用误差传递理论分析了各个周期性误差参数的传递特性,发现数据平滑过程会严重影响周期性误差...
  • ScheduledFutureTask类有三个构造函数,可分别构造周期性任务和非周期性任务; ScheduledFutureTask类重写FutureTask类的run()方法,进而执行周期性任务; ScheduledFutureTask类实现compareTo(T)方法,使得队列中的...

    ScheduledThreadPoolExecutor

    在进一步了解ScheduledThreadPoolExecutor类之前,先学习下ScheduledFutureTask类的构造。

    1. ScheduledFutureTask

    类的继承图:
    scheduledFutureTask
    类图显示,该类实现Runnable接口并继承FutureTask类,表明该类是一个被包装的任务,同时该类实现Delayed接口和Comparable< Delayed>接口,表明该任务具有延迟性和优先级。所以,我们可以初步断定ScheduledFutureTask任务使得Runnable任务具有延迟性。下面详细分析该类。

    1.1 ScheduledFutureTask类的五个属性和三个构造函数
    // FIFO队列的序列号
    private final long sequenceNumber;
    // 以毫秒为单位的相对于任务创建时刻的等待时间,即延迟时间
    private long time;
    // 以纳秒为单位的周期时间,正数表明fixed-rate执行,负数表明delay-rate执行,0表明非重复
    private final long period;
    // 当前任务
    RunnableScheduledFuture<V> outerTask = this;
    // 进入延迟队列的索引值,它便于取消任务
    int heapIndex;
    

    类的三个构造函数:

    // 创建延迟时间为ns的非重复任务,返回结果为result
    ScheduledFutureTask(Runnable r, V result, long ns) {
    super(r, result);
        this.time = ns;
        this.period = 0;  // 0表示非重复
        this.sequenceNumber = sequencer.getAndIncrement(); // 当前任务的序列号
    }
    
    // 创建延迟时间为ns,周期时间为period,返回结果为result的任务
    ScheduledFutureTask(Runnable r, V result, long ns, long period) {
    super(r, result);
        this.time = ns;
        this.period = period;
        this.sequenceNumber = sequencer.getAndIncrement();
    }
    // 创建延迟时间为ns的非重复任务
    ScheduledFutureTask(Callable<V> callable, long ns) {
    super(callable);
        this.time = ns;
        this.period = 0;
        this.sequenceNumber = sequencer.getAndIncrement();
    }
    

    通过类的属性和构造函数可知,ScheduledFutureTask类使得Runnable任务可以延迟执行,甚至设置周期执行;同时记录每个Runnable任务进入延迟队列的序列号.

    1.2 ScheduledFutureTask的run()方法

    ScheduledFutureTask类继承FutureTask类,所以可以执行带有返回结果的任务.

    // 重写FutureTask的run方法
    public void run() {
        // 属性period不等于0返回true,表明周期任务;否则返回false,表明非周期任务
        boolean periodic = isPeriodic(); 
        // 当前线程池状态下是否可以继续执行
    	if (!canRunInCurrentRunState(periodic))
            cancel(false); // 终止线程并移除任务
        // 非周期任务执行FutureTask的run()方法
    	else if (!periodic)
            ScheduledFutureTask.super.run();
        // 周期任务,新建任务且可执行
    	else if (ScheduledFutureTask.super.runAndReset()) {
        	// 根据period值设置该任务的time值,如果period为正数,则直接与time值相加,如果是负数,则去掉符号后与系统当前时间相加
    		setNextRunTime();
    		// 当前任务加入队列
            reExecutePeriodic(outerTask);
        }
    }
    
    private void setNextRunTime() {
    	// 构造函数中设置的周期时间
    	long p = period;
    	// 若周期时间为正数
    	if (p > 0)
    		// 则把周期时间与延迟时间相加作为任务下次执行的时间
            time += p;
    	else
    		// 若为负数,则忽略延迟时间,以当前时间为基准加上周期时间作为下次任务执行时间
            time = triggerTime(-p);
    }
    
    long triggerTime(long delay) {
        return now() +
            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
    }
    

    如果delay值小于Long.MAX_VALUE值的一半,则取delay的值,否则delay值取overflowFree(delay)方法返回的值.

    private long overflowFree(long delay) {
    	// 获取队列的头部节点,即优先级最高的任务
        Delayed head = (Delayed) super.getQueue().peek();
    	if (head != null) {
    		// 获取任务的延迟时间
            long headDelay = head.getDelay(NANOSECONDS);
    		// 若任务时间已到但还没有被处理且delay和headDelay相加溢出
            if (headDelay < 0 && (delay - headDelay < 0))
    			// delay取差值
                delay = Long.MAX_VALUE + headDelay;
        }
        return delay;
    }
    

    overflowFree()方法的目的是保证队列内任务的延迟时间都在Long.MAX_VALUE范围内

    run()在处理任务时,会根据任务是否是周期任务走不通的流程:

    • 非周期任务,则采用futureTask类的run()方法,不存储优先队列;
    • 周期任务,首先确定任务的延迟时间,然后把延迟任务插入优先队列;
    1.3 ScheduledFutureTask的reExecutePeriodic(outerTask)方法

    该方法是把周期任务插入优先队列的过程.

    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
        // 当前状态可以运行线程
    	if (canRunInCurrentRunState(true)) {
    	// task任务放入delayedWorkQueue队列中,实际执行offer()方法
            super.getQueue().add(task);
            // 当前状态(shutdown)不可以运行线程,删除任务 
            if (!canRunInCurrentRunState(true) && remove(task))
                task.cancel(false);  // 且中断线程
            else
                ensurePrestart();  // 否则判断是否要创建新的线程
        }
    }
    
    boolean canRunInCurrentRunState(boolean periodic) {
        return isRunningOrShutdown(periodic ?
                               continueExistingPeriodicTasksAfterShutdown :
                                executeExistingDelayedTasksAfterShutdown);
    }
    

    continueExistingPeriodicTasksAfterShutdown属性值默认为false,表示shutDown状态下取消周期性任务.
    executeExistingDelayedTasksAfterShutdown属性值默认为true,表示shutDown状态下不会取消非周期性任务.
    我们这里判断的是周期性任务,所以取continueExistingPeriodicTasksAfterShutdown属性的值.

    void ensurePrestart() {
        int wc = workerCountOf(ctl.get());
        if (wc < corePoolSize)
            addWorker(null, true);
        else if (wc == 0)
            addWorker(null, false);
    }
    

    方法表明即使corePoolSize为0,也会创建一个线程.该线程会去等待获取队列中的任务.

    通过上面的分析,可知reExecutePeriodic(outerTask)方法把周期任务插入优先队列的过程:

    • 判断当前状态是否可以插入任务;
    • 任务插入到优先队列;
    • 创建新的线程;
    1.4 ScheduledFutureTask的compareTo(T)方法

    compareTo(T)方法是核心方法,在周期任务插入优先队列的时候会根据该方法判断队列的插入位置.

    public int compareTo(Delayed other) {
        // 如果与自己比较则返回0
        if (other == this) // compare zero if same object
            return 0; 
        // 放进来的任务为ScheduledFutureTask类型
        if (other instanceof ScheduledFutureTask) {
            ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
            // 当前任务的延迟时间与比较任务的延迟时间之差
    		long diff = time - x.time;
            // 如果小于0,则返回-1
    		if (diff < 0)
                return -1;
            // 如果大于0,则返回1
    		else if (diff > 0)
                return 1;
            // 如果等于0,则比较任务的序列号,当前任务序列号小则返回-1
    		else if (sequenceNumber < x.sequenceNumber)
                return -1;
            // 当前序列号大则返回1
    		else
                return 1;
    	}
    	// 任务不为ScheduledFutureTask类型,则直接比较两者的延迟时间
        long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
        return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
    }
    

    compareTo(Delayed)方法表明:

    • 当前任务与参数任务(siftUp时是父节点,siftDown时是子节点)比较time属性,即任务的延迟时间;
    • 如果是siftUp,若插入任务延迟时间大于父节点任务延迟时间,则返回1,表明节点不交换,即任务插入当前位置;否则与 父节点任务交换位置并继续比较父节点的父节点;
    • 如果是siftDown,若插入任务延迟时间小于子节点任务延迟时间,则返回-1,表明节点不交换,即任务放置在当前父节点位置;否则与自己诶单任务交换位置并继续比较子节点的子节点;

    PS:这个过程需要结合DelayedWorkQueue类的siftUp()和siftDown()方法理解,表明这里使用的是最小堆,即延迟时间最短的任务放置在头部节点,即优先级最高.

    1.5 ScheduledFutureTask类的小节

    分析ScheduledFutureTask类可知:

    • ScheduledFutureTask类是对Runnable类的一个包装;
    • Runnable任务转变成ScheduledFutureTask任务,使得任务具有周期性,周期任务放入DelayedWorkQueue具有延迟性;
    • ScheduledFutureTask类封装time属性和period属性,分别代表延迟时间和周期时间;
    • ScheduledFutureTask类有三个构造函数,可分别构造周期性任务和非周期性任务;
    • ScheduledFutureTask类重写FutureTask类的run()方法,进而执行周期性任务;
    • ScheduledFutureTask类实现compareTo(T)方法,使得队列中的延迟性任务根据延迟时间的长短排出优先级;

    2. ScheduledThreadPoolExecutor

    类的主要作用
    它是一个可以把提交的任务延迟执行或者周期执行的线程池。比起java.util.Timer类,它更加灵活。延迟任务提交到线程池后开始执行,但具体何时执行则不知道,延迟任务是根据先进先出(FIFO)的提交顺序来执行的。
    当提交的任务在运行之前被取消时,执行将被禁止。默认情况下,这样一个被取消的任务不会自动从工作队列中删除,直到它的延迟过期为止。虽然这可以进行进一步的检查和监视,但也可能导致取消的任务无限制地保留。为了避免这种情况,将setRemoveOnCancelPolicy设置为true,这将导致任务在取消时立即从工作队列中删除。
    通过scheduleAtFixedRate或scheduleWithFixedDelay调度的任务的连续执行不会重叠。
    虽然这个类继承自ThreadPoolExecutor,但是一些继承的调优方法对它并不有用。特别是,由于它使用corePoolSize线程和无界队列(队列最大为Integer.MAX_VALUE)充当固定大小的池,所以对maximumPoolSize的调整没有任何有用的效果。

    • ScheduledThreadPoolExecutor类使用自定义的任务类型,即ScheduledFutureTask;该任务类型可把普通Runnable任务包装成延迟任务,当然也能接受非延迟任务,即设置延迟时间为0.
    • ScheduledThreadPoolExecutor类使用自定义的等待队列,即DelayedWorkQueue;该队列是基于堆实现的优先队列,且队列最大容量为Integer.MAX_VALUE,可被认为是无界队列.与线程池内无界队列搭配的最大线程为Integer.MAX_VALUE.
    • ScheduledThreadPoolExecutor类可以通过属性值控制线程池shutdown后的运行状态;具体属性值看后面的分析.
    • ScheduledThreadPoolExecutor类提供修改任务的装饰方法,默认返回原始任务;具体还没有找到使用场景.
    2.1 ScheduledThreadPoolExecutor类的属性
    // 线程池停止后,周期任务取消执行则为false,默认为false,不取消则为ture
    private volatile boolean continueExistingPeriodicTasksAfterShutdown;
    
    // 线程池停止后,取消非周期任务则为false,不取消非周期任务则为true,默认为true
    private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
    
    // 取消的任务是否移出队列,默认为false不移出
    private volatile boolean removeOnCancel = false;
    
    // 任务进入队列的序列号
    private static final AtomicLong sequencer = new AtomicLong();
    
    
    2.2 ScheduledThreadPoolExecutor类的构造函数
    // 参数corePoolSize为核心线程数
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    
    // 参数corePoolSize为核心线程数,threadFactory为自定义线程工厂
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                           ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }
    
    //参数corePoolSize为核心线程数,handler为拒绝策略
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                           RejectedExecutionHandler handler) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), handler);
    }
    
    //参数corePoolSize为核心线程数, threadFactory为自定义线程工厂,handler为拒绝策略
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                           ThreadFactory threadFactory,
                                           RejectedExecutionHandler handler) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory, handler);
    }
    

    构造函数都是调用父类ThreadPoolExecutor的构造函数,如果不清楚可以看这篇文章的分析。不过,这里可以看出:

    • 最大线程数为Integer.MAX_VALUE;表明线程池内线程数不受限制;
    • 空闲线程的等待时间都为0纳秒,表明池内不存在空闲线程,除了核心线程;
    • 任务等待队列为DelayedWorkQueue,即延迟队列

    PS:关于DelayedWorkQueue队列,可以看这篇文章的介绍.

    或许此时你想问为什么最大线程数设置为Integer.MAX_VALUE?
    如果你知道DelayedWorkQueue队列的原理,你就能理解了。这是因为延迟队列内用数组存放任务,数组初始长度为16,但数组长度会随着任务数的增加而动态扩容,直到数组长度为Integer.MAX_VALUE;既然队列能存放Integer.MAX_VALUE个任务,又因为任务是延迟任务,因此保证任务不被抛弃,最多需要Integer.MAX_VALUE个线程.

    那么为什么空闲线程的超时时间设置为0呢?
    第三个参数为0,表示空闲线程超时时间 ,第四个参数为前一个参数的时间位;ScheduledThreadPoolExecutor的四个构造函数,空闲线程超时时间都为0,表示池内不存在空闲线程.
    如何定义池内的空闲线程是关键.我们知道ScheduledThreadPoolExecutor线程池会把池内的某一个线程定义为leader线程,该leader线程用于等待队列的根节点直到获取并运行任务,而其他线程则会阻塞等待;阻塞等待的线程等待leader线程释放唤醒的信号,等待队列中的某个线程会被升级为leader线程,其他线程继续等待.那么,这里等待的线程都为空闲线程,为了避免过多的线程浪费资源,所以ScheduledThreadPool线程池内更多的存活的是核心线程.

    PS:核心线程数的设置应该跟任务的周期时间和实际执行完成的时间有关.若任务周期短,但执行时间长,则核心线程数设置大一点,这样避免线程频繁的创建和销毁.若任务周期长,但执行时间短,则核心线程数设置小一点,避免核心线程数内存活过多的空闲线程.

    2.4 ScheduledThreadPoolExecutor类的schedule(Runnable,long,TimeUnit)

    ScheduledThreadPoolExecutor类的execute(Runnable)和submit(Runnable)方法都是调用schedule(Runnable,long,TimeUnit)方法.
    首先看下被重写的execute(Runnable)方法:

    public void execute(Runnable command) {
        schedule(command, 0, NANOSECONDS);
    }
    public Future<?> submit(Runnable task) {
        return schedule(task, 0, NANOSECONDS);
    }
    public <T> Future<T> submit(Runnable task, T result) {
        return schedule(Executors.callable(task, result), 0, NANOSECONDS);
    }
    public <T> Future<T> submit(Callable<T> task) {
        return schedule(task, 0, NANOSECONDS);
    }
    

    通过正常方法提交的任务, 内部调用的都是schedule(Runnable,long,TimeUnit);方法第一个参数就是执行的任务,第二个参数都为0,表示任务的延迟时间为0,第三个参数为前一个参数的时间单位.

    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        RunnableScheduledFuture<?> t = decorateTask(command,
             new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        delayedExecute(t);
        return t;
    }
    

    参数含义:

    • command:执行任务;
    • delay:延迟时间;
    • unit:延迟时间的单位,有七种;一般使用SECONDS和MILLISECONDS;

    执行过程:

    • 若Runnable任务为null,则抛出NPE异常;
    • 根据delay和unit参数计算延迟任务的触发时间;我们这里delay值都为0,表示非延迟任务;
    • 把Runnable类型的任务转变成ScheduledFutureTask类型;第二个参数表示任务返回类型,这里设置为null;
    • decorateTask(Runnable,ScheduledFutureTask)默认返回ScheduledFutureTask任务.该方法作用是修改或替换用于执行的任务,可覆盖用于管理内部任务的具体类;默认实现只返回给定的任务。
    • delayedExecute(RunnableScheduledFuture)执行提交的ScheduledFutureTask任务;

    分析schedule执行过程可知,首先Runnable任务需要转变成ScheduledFutureTask任务,然后该任务由delayedExecute(RunnableScheduledFuture)方法执行.

    以上方法提交到线程池的任务都是普通任务,属于非延迟任务.

    delayedExecute(RunnableScheduledFuture)方法如何执行任务?

    private void delayedExecute(RunnableScheduledFuture<?> task) {
    	if (isShutdown())
    	// 线程池状态为shutdown,则执行拒绝策略拒绝任务
            reject(task);
    	else {
    	// 线程状态正常,则把任务放入优先队列
            super.getQueue().add(task);
    		// shutdown状态下,非周期任务不会移除队列
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
    			// shutdown状态下,周期任务会默认移除队列
                task.cancel(false);
            else
    			// 如果池内线程数小于核心线程数,则新建一个线程
                ensurePrestart();
        }
    }
    

    队列中的任务等待leader线程消费任务.

    目前为止,我们讨论的都是普通任务,而么有讨论周期性任务.ScheduledThreadPool线程池通过下面两个方法提交周期任务并处理周期任务.也是该线程池的核心任务.

    2.5 ScheduledThreadPoolExecutor类的scheduledAtFixedRate(Runnable,long,long,TimeUnit)

    该方法创建一个周期性任务,且设置任务的首次执行时间,即延迟时间;方法参数:

    • command:需要执行的周期任务;
    • initialDelay:初始化延迟时间;根据该参数计算出任务的首次执行时间;
    • period:周期时间;任务周期化执行的时间;根据该参数计算出任务的后续执行时间;
    • unit:第二和第三个参数的时间单位;
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                      long initialDelay,
                                                      long period,
                                                      TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (period <= 0)
            throw new IllegalArgumentException();
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(period));
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;
        delayedExecute(t);
        return t;
    }
    

    方法执行逻辑:

    • 若Runnable任务和unit值为null,则抛出NPE异常;
    • 确保period参数大于0,否则抛出非法参数异常;首先period参数不能为0,不然和方法schedule(Runnable,long,TimeUnit)没区别;然后period参数不能小于0,period参数本身的含义是周期性,若小于0 则没有任何意义;
    • Runnable任务封装成ScheduledFutureTask任务;确定任务的延迟时间和周期时间;
    • decorateTask()方法默认返回sft参数;方法可以修改或者取代任务;
    • outerTask属性值是ScheduledFutureTask任务run()方法的处理的任务;
    • delayedExecute(t)会把任务加入延迟队列并根据线程池内线程数判断是否新建线程;该方法的具体理解见这片文章;

    这里可能会问,如果任务的执行时间超过周期时间会如何?
    关于这个问题的答案应该是,任务的执行时间和周期性没有任何关系;即会按照固定的周期时间设置该任务的下次执行时间,然后放入优先队列;优先队列最大深度为Integer.MAX_VALUE,线程池最大线程数也为Integer.MAX_VALUE.
    注意:由于线程在执行该任务,即拥有该Runnable对象的锁,因此即使下一次runnable对象的延迟时间到期也会因为锁没有被释放而无法执行;所以,表现出来的现象是只有该runnable任务执行完,才会开始执行下一次的任务。

    2.6 ScheduledThreadPoolExecutor类的ScheduleWithFixedDelay (Runnable,long,long,TimeUnit)

    ScheduleWithFixedDelay()方法创建并执行一个周期性的Runnable方法,该方法会在给定的初始化延迟时间之后执行;Runnable方法执行结束之后,在给定的delay值(延迟时间)后再次执行;该周期性操作会在Runnable方法执行出现异常时停止,或者线程池终止时停止.

    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (delay <= 0)
            throw new IllegalArgumentException();
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(-delay));
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;
        delayedExecute(t);
        return t;
    }
    

    ScheduleWithFixedDelay与ScheduleAtFixedRate的区别在于Runnable方法的执行方式;前者是方法执行结束之后,延迟一段时间之后再执行下一次,表明前后两次执行关系紧密;后者时不管前一次方法执行有没有结束,在固定的时间后都会再次重复该方法;当然,由于两者的Runnable任务都是延迟任务,因此任务都会加入到优先队列中等候.
    既然是这样,那么如果使用ScheduleWithFixedDelay()方法,核心线程数尽量取小一点,这样可以避免空闲线程.

    3. 总结

    围绕ScheduledThreadPoolExecutor类来讲,讲到内部任务类ScheduledFutureTask的属性和方法;然后讲到周期线程池的属性和方法,特别强调ScheduleWithFixedDelay()和ScheduleAtFixedRate()方法的使用和区别.

    展开全文
  • 绝对不变性原理、内模原理

    千次阅读 2020-02-25 09:22:00
    绝对不变性原理:欲想克服外扰影响,就要测量外扰;控制器必须同时含有反馈稳定的通道和抑制外扰的通道,即“双通道原理”。 内模原理:欲想克服外扰影响,就要知道外扰模型;控制器必须含有外扰模型。 ...

    绝对不变性原理:欲想克服外扰影响,就要测量外扰;控制器必须同时含有反馈稳定的通道和抑制外扰的通道,即“双通道原理”。

    在这里插入图片描述

    内模原理:欲想克服外扰影响,就要知道外扰模型;控制器必须含有外扰模型。

    自抗扰技术:作用于被控对象的所有不确定因素都是“未知扰动”,被控对象的不确定性称为“内扰”,外部的不确定性称为“外扰”,两者合并称“总扰动”,根据输入输出数据估计出总扰动并予以补偿。

    展开全文
  • 主要介绍了Python实现SVN的目录周期性备份,实例分析了Python实现SVN周期性备份的原理与实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • 去除图像周期性线状噪声

    千次阅读 2019-11-03 18:34:20
    本文主要讲述的是如何去除图像中周期性的线性噪声,尝试过的方法从空域的开关中值滤波到频域的陷波滤波等,在此做个总结

    本文主要讲述的是如何去除图像中周期性的线性噪声,尝试过的方法从空域开关中值滤波频域陷波滤波等,在此做个总结,其中陷波滤波的尝试失败,效果并不理想,而开关中止滤波的效果很好。

    在这里插入图片描述
    图1:带周期性线条噪声的图片

    1.实验过程

    首先我是想用openCV自带的cv2.medianBlur()来去除噪声,但是在测试过几组kernel过后发现:随着线条的消除,图片也会越来越模糊,小的kernel并不能很好的消除噪声,而大的kernel会让图片失真。然后我并没有很聪明的想到我最终的解决方案:开关中值滤波,而是转变了另一个方向:陷波滤波。

    2.陷波滤波

    先来说说陷波滤波吧。

    陷波滤波是一种频域滤波,频域滤波的过程是先对图像进行正交变换(常用的是傅里叶变换),再对正交变换得到的正交变换域系数阵列进行滤波处理,然后逆变换到空域,得到处理结果图像。

    傅里叶变换是把图像从空域变换到频域,图像的背景区域和缓慢变化部分对应频谱中的低频部分,而边
    缘、细节、跳跃部分以及噪声则对应高频部分。线状和网格状噪声具有准周期性,噪声频谱与图像的频谱是可分离的,因此对于带有此类噪声的图像,可以通过频域滤波的方法来去除噪声。

    理想陷波滤波器的传递函数:
    H ( u , v ) = { 0 D 1 ( u , v ) < = D 0 0 D 2 ( u , v ) < = D 0 1 e l s e H(u,v)= \begin {cases} 0&D_1(u,v)<=D_0 \\0&D_2(u,v)<=D_0\\1&else \end {cases} H(u,v)=001D1(u,v)<=D0D2(u,v)<=D0else

    采用陷波滤波器去除线状和网格状噪声的关键在于如何准确地定位噪声对应的亮点确定陷波滤波器参数

    对图1所示的叠加了水平线状噪声的图像进行傅里叶变换后,得到如图2所示的傅立叶频谱。

    在这里插入图片描述
    图2:傅里叶频谱

    以其纵轴上各点的位置为横坐标(自上而下),以各点的频谱值为纵坐标,绘制的频谱曲线如图3所示。

    在这里插入图片描述
    图3: 纵轴频谱值

    图5中的中心点及其附近点均是亮点,但不是噪声所对应的。这是因为中心点表示图像的平均亮度。因此,将检测范围限制在不包含中心点附近部分的区域。

    寻找各点(不包含中心点及其附近)频谱值的最小值和最大值,分别记为 k m i n k_{min} kmin k m a x k_{max} kmax,令 T = T m i n + 3 ∗ ( T m a x − T m i n / 4 ) T=T_{min}+3*(T_{max}-T_{min}/4) T=Tmin+3(TmaxTmin/4), 如果某点的频谱值是局部最大值(即大于与它相邻点 的频谱值)且其值大于等于 T T T,那么该点的位置就是亮
    点中心。计算每个亮点中心与其左侧第一个谷底(局部最小值所对应的点)之间的距离,记为 D 1 D_1 D1;与其右侧第一个谷底(局部最小值所对应的点)之间的距离,记为: D 2 D_2 D2 D 1 D_1 D1 D 2 D_2 D2:中的最大值作为陷波滤波器的带宽半径,这就是所需要的陷波滤波器参数。

    但遗憾的是不知道后续步骤哪里出现了问题导致最终结果并不理想,可能是filter写的比较奇怪吧。。还在检查中。放出来给大家看一下结果:

    在这里插入图片描述
    奇怪的结果

    3.开关中值滤波

    开关中值滤波器是先检测噪声像素。然后只对检测到的噪声像素进行中值滤波。而被判断为非噪声的像素则不再参与中值滤波。

    效果那是非常好,话不多说上代码:

    def detec(img):
        (w,h) = img.shape
        flt = np.ones((w,h),dtype = int)
        bright = []
        for y in range(h):
            bright.append(np.sum(img[:][y]))
        x=np.arange(512)
        plt.plot(x,bright,c='b')
        plt.ylabel('Brightness')
        plt.savefig('Brightness.jpg')
        for i in range(h):
            if bright[i]>100000:
                flt[:][i]=0
        return flt
     
     def medianBlur(img):#只支持3*3的BlockSize
        (w,h) = img.shape
        for i in range(2,w-1):
            for j in range(2,h-1):
                n = 0
                s = 0
                if img[i][j] == 0:
                    for ii in range(i-1,i+1):
                        for jj in range(j-1,j+1):
                            if img[ii][jj] != 0:
                                n = n + 1
                                s = s + img[ii][jj]
               if n != 0:
                   img[i][j] = int(s/n)
        return img
    if __name__ == '__main__':
        fileName = 'line.jpg'
        gray = loadData(fileName)
        flt = detec(gray)
        grayWithoutNoise = gray*flt
        row = np.zeros(512)
        col = np.zeros(514)
        grayWithoutNoise = np.row_stack((grayWithoutNoise,row))
        grayWithoutNoise = np.row_stack((row,grayWithoutNoise))
        grayWithoutNoise = np.column_stack((grayWithoutNoise,col))
        grayWithoutNoise = np.column_stack((col,grayWithoutNoise))
        mb = medianBlur(grayWithoutNoise)
        mb = mb[1:512,1:512]   
        mb = np.array(mb,dtype=np.uint8)
        cv2.imshow('medianBlurWithDetection',mb)
        cv2.imwrite('medianBlurWithDetection.jpg',mb)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    在这里插入图片描述
    成功的结果
    展开全文
  • 本文基于数字信号处理中信号经过多次叠加平均后,信号中的随机噪声将被消除的原理,设计了一种针对周期性信号的随机噪声消除电路。该电路主要由锁相倍频、周期延时及放大电路组成。本文对该电路的原理进行分析,并...
  • 计算机教材中关于CPU总线周期时序描述的原理性错误.pdf
  • 频率域滤波去除周期性噪声

    千次阅读 2020-12-26 03:25:40
    频率域滤波去除周期性噪声(波纹状噪声)matlab实现
  • (MATLAB)空间周期性噪声的一种通用处理方法 本文的目的在于处理图像中出现的周期性噪声,使用的语言是MATLAB 常见的结构有线状周期性结构,蜂窝状周期性结构等,总而言之,图像中出现了某种结构并这种结构在图像中...
  • 对数周期天线工作原理

    千次阅读 2021-04-26 11:29:36
    对数周期天线是一种宽频带天线,由于它结构简单,频带宽,因此得到广泛应用,天线的特性随频率的对数做周期性变化,而在谐振频率之间,天线的特性是波动的。
  • 在计算机组成原理中又叫T周期或节拍脉冲。是CPU和其他单片机的基本时间单位。它可以表示为时钟晶振频率(1秒钟的时钟脉冲数)的倒数(也就是1s/时钟脉冲数,比如1/12MHz),对CPU来说,在一个时钟周期内,CPU仅完成...
  • 《计算机组成原理实验》 单周期CPU

    千次阅读 多人点赞 2019-08-26 22:44:32
    《计算机组成原理实验》 单周期CPU 前言 这是中山大学2018年计算机组成原理实验中单周期CPU的实验报告,仿真与写板的内容暂略,所有源代码(包括写板)已经上传至我的github当中,欢迎大家访问。 github个人主页:...
  • 通常判断数据周期性的方法是对数据进行傅里叶变换。采用是傅立叶变换,该方法快速且计算效率高,但在存在多季节性模式时效果不佳。 2. 代码示例 代码位置: https://github.com/lilihongjava/aiops def is_...
  • 《计算机组成原理实验》 多周期CPU

    千次阅读 2019-08-27 11:35:22
    《计算机组成原理实验》 多周期CPU 前言 这是中山大学2018年计算机组成原理实验中多周期CPU的实验报告,仿真与写板的内容暂略,所有源代码(包括写板)已经上传至我的github当中,欢迎大家访问。 github个人主页:...
  • 白噪声和周期信号完全不相关,白噪声的完全随机导致它和任何函数都不相关恋。它们之间的互相关函数可认为是零 fs = 5e3; n = 0:1/fs:1; len = length(n); freq = 100; s = sin(2*pi*freq*n)...
  • 周期置换密码的加密操作原理

    千次阅读 2021-03-15 17:44:23
    加密方法: 把明文字符以固定的宽度m(分组长度)水平地(按行)...Q: 假设明文是“Data security is very important”, 按密钥“4,3,1,2” 进行周期置换加密, 求加密后的密文? 【周期置换加密的解题思路】 ①按
  • 本文根据J.Upatinieks的椭圆等光程原理,提出了一种现场观测多纵模激光有效相干长度及其TC周期性的全息法.介绍了基本原理与方法,给出了相应的实验结果.
  • 在nova中可以通过添加@periodic_task.periodic_task 来产生一个周期任务。 例如使用默认周期的任务: @periodic_task.periodic_task def _poll_rebooting_instances(self, context): if CONF.reboot_timeout > 0:...
  • 周期原理(转)

    千次阅读 2006-10-12 20:25:00
    周期的原理(转)宇宙万物都处在周期性循环运动之中,不论是具体的还是抽象的,物质的还是精神的,乃至包括你的想象,都可以构成循环,并发生在你的身上,经过数年,你将会得到这些结果,或好或坏,完全按照你当初想象的...
  • 《Maven进阶》1.maven 项目生命周期与构建原理

    万次阅读 多人点赞 2016-01-15 14:19:34
    本文将介绍maven对于项目生命周期的设计以及原理。 读完本文,你将了解到: 一、maven对项目生命周期的抽象--三大项目生命周期 二、maven对项目默认生命周期的抽象 三、maven指令与生命周期阶段的关系 四...
  • matlab中周期图功率谱法的实现原理

    万次阅读 2015-06-20 09:57:47
    matlab中的周期图功率谱法原理是通过计算采样信号的FFT,获得离散点的幅度,再根据幅度与功率之间的关系,转换为离散点的功率,再通过坐标变换将离散点的功率图转换为连续功率谱密度。 1、计算采样信号x(n)的DFT,...
  • 假设得到了一组被认为是具有一定周期性的数据,为了分析出数据中重复结构,需要计算他的周期。举个例子比如在matlab中拟合出这样的图像: ![图片说明]...
  • 其主要提供了schedule,scheduleAtFixedRate,scheduleWithFixedDelay三个方法,分别用于延迟执行任务,特定频率周期性执行任务,特定延迟周期性执行任务。 public interface ScheduledExecutorS...
  • 日期 内核版本 架构 作者 GitHub CSDN 2016-6-29 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度 我们前面提到linux有两种方法...另一种是通过周期性的机制, 以固定的频率运行, 不时
  • %包含f1,f2整数倍周期的最少点数就是16 x=cos(2pit+pi/4)+2cos(2pi0.5t+pi/8); X=fft(x); stem((0:N-1),abs(X)); figure; stem((0:N-1),angle(X)/pi*180); perfect。这是最perfect的图了,不能再perfect了。好在哪...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 290,319
精华内容 116,127
关键字:

周期性原理

友情链接: VxWorks.zip