FixedRateAsynchronousSource.java

/*
 * Created on 2010/01/04
 * Copyright (C) 2010 Koga Laboratory. All rights reserved.
 *
 */
package org.mklab.tool.control.system.source;

import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;


/**
 * 等間隔のサンプリングを行うソースです。
 * 
 * @author Yuhi Ishikura
 * @version $Revision$, 2010/01/04
 * @param <RS> type of real scalar
 * @param <RM> type of real matrix
 * @param <CS> type of complex scalar
 * @param <CM> type of complex matrix
 */
public abstract class FixedRateAsynchronousSource<RS extends RealNumericalScalar<RS,RM,CS,CM>, RM extends RealNumericalMatrix<RS,RM,CS,CM>, CS extends ComplexNumericalScalar<RS,RM,CS,CM>, CM extends ComplexNumericalMatrix<RS,RM,CS,CM>> extends AsynchronousSource<RS,RM,CS,CM> {

  /** 全出力データです。 */
  private RS[] outputData;
  /** 出力データ配列中の次に記録するインデックスです。 */
  private int outputIndex;
  /** 次に記録するデータの時間です。 */
  private RS time;
  /** データの時間の間隔、サンプリングインターバルです。 */
  private RS interval;

  /**
   * {@link FixedRateAsynchronousSource}オブジェクトを構築します。
   * 
   * @param size サイズ
   * @param interval データの時間の間隔、サンプリングインターバル
   * @param sunit unit of scalar
   */
  public FixedRateAsynchronousSource(int size, RS interval, RS sunit) {
    super(1, sunit);
    this.outputData = sunit.createArray(size);
    this.interval = interval;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected final RM getOutput(RS t) {
    if (isReadyFor(t) == false) {
      throw new IllegalStateException(Messages.getString("FixedRateAsynchronousSource.1")); //$NON-NLS-1$
    }

    final int index = (int)t.divide( this.interval).toDouble();
    if (index >= this.outputData.length) {
      throw new IndexOutOfBoundsException(Messages.getString("FixedRateAsynchronousSource.0")); //$NON-NLS-1$
    }

    RS[] out =this.sunit.createArray(1);
    out[0]= this.outputData[index];
    return this.sunit.createGrid(out);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected final boolean isReadyFor(RS t) {
    return t.isLessThan(this.time);
  }

  /**
   * 出力データがいっぱいであるかを調べます。
   * 
   * @return これ以上記録できない場合はtrue,そうでなければfalse
   */
  protected final boolean isOutputDataFilled() {
    return this.outputIndex >= this.outputData.length;
  }

  /**
   * 出力を追加します。
   * 
   * @param output 出力
   */
  protected final void publish(RS output) {
    if (isOutputDataFilled()) {
      throw new IllegalStateException();
    }
    this.outputData[this.outputIndex] = output;
    this.outputIndex++;
    this.time = this.time.add(this.interval);

    bufferChanged();
  }

}