/* A micro-accelerometer demo that uses CT and DE domains.
Copyright (c) 1998-2005 The Regents of the University of California.
All rights reserved.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the above
copyright notice and the following two paragraphs appear in all copies
of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
PT_COPYRIGHT_VERSION_2
COPYRIGHTENDKEY
*/
package ptolemy.domains.ct.demo.SigmaDelta;
import ptolemy.actor.TypedCompositeActor;
import ptolemy.actor.TypedIOPort;
import ptolemy.actor.TypedIORelation;
import ptolemy.actor.lib.AddSubtract;
import ptolemy.actor.lib.Average;
import ptolemy.actor.lib.Clock;
import ptolemy.actor.lib.CurrentTime;
import ptolemy.actor.lib.Quantizer;
import ptolemy.actor.lib.Scale;
import ptolemy.actor.lib.TrigFunction;
import ptolemy.actor.lib.gui.TimedPlotter;
import ptolemy.data.DoubleToken;
import ptolemy.data.StringToken;
import ptolemy.data.expr.Parameter;
import ptolemy.domains.ct.kernel.CTMixedSignalDirector;
import ptolemy.domains.ct.lib.CTPeriodicSampler;
import ptolemy.domains.ct.lib.Integrator;
import ptolemy.domains.ct.lib.ZeroOrderHold;
import ptolemy.domains.de.kernel.DEDirector;
import ptolemy.domains.de.lib.Sampler;
import ptolemy.domains.sdf.lib.FIR;
import ptolemy.kernel.Relation;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;
import ptolemy.kernel.util.Workspace;
import ptolemy.plot.Plot;
//////////////////////////////////////////////////////////////////////////
//// SigmaDelta
/**
A demo of Sigma Delta quantization. The underlying model is a
micro-accelerometer which uses beam-gap capacitor to measure accelerations.
A second order CT subsystem is used to model the beam.
The voltage on the beam-gap capacitor is sampled every T seconds (much
faster than the required output of the digital signal), then filtered by
a lead compensator (FIR filter), and fed to an one-bit quantizer.
The outputs of the quantizer are converted to force and fed back to the
beams. The outputs are also counted and averaged every N*T seconds to
produce the digital output. In our example, the external acceleration
is a Sin wave.
Reference: Mark A. Lemkin, <I>"Micro Accelerometer Design with Digital
Feedback Control"</I>, doctoral dissertation, University of California,
Berkeley, Fall 1997
@author Jie Liu
@version $Id: SigmaDelta.java,v 1.25 2005/07/08 19:57:57 cxh Exp $
@since Ptolemy II 1.0
@Pt.ProposedRating Red (liuj)
@Pt.AcceptedRating Red (cxh)
*/
public class SigmaDelta extends TypedCompositeActor {
public SigmaDelta(Workspace workspace) throws IllegalActionException,
NameDuplicationException {
// Creating the model.
super(workspace);
setName("DigitalSystem");
// Set up the top level composite actor, director and manager
DEDirector deDirector = new DEDirector(this, "DEDirector");
//deDirector.addDebugListener(new StreamListener());
double stopT = 15.0;
deDirector.stopTime.setToken(new DoubleToken(stopT));
// Create toplevel parameters.
samplePeriod = new Parameter(this, "samplePeriod",
new DoubleToken(0.02));
feedbackGain = new Parameter(this, "feedbackGain", new DoubleToken(
-20.0));
// CT subsystem
TypedCompositeActor ctsub = new TypedCompositeActor(this, "CTSubsystem");
Parameter ctSamplePeriod = new Parameter(ctsub, "samplePeriod");
ctSamplePeriod.setExpression("samplePeriod");
Parameter ctFeedbackGain = new Parameter(ctsub, "feedbackGain");
ctFeedbackGain.setExpression("feedbackGain");
TypedIOPort subin = new TypedIOPort(ctsub, "Pin");
subin.setInput(true);
TypedIOPort subout = new TypedIOPort(ctsub, "Pout");
subout.setOutput(true);
CTMixedSignalDirector ctdir = new CTMixedSignalDirector(ctsub,
"CTEmbDir");
//ctdir.addDebugListener(new StreamListener());
// ---------------------------------
// Create the actors.
// ---------------------------------
// CTActors
CurrentTime time = new CurrentTime(ctsub, "CurTime");
TrigFunction trigFunction = new TrigFunction(ctsub, "TrigFunction");
ZeroOrderHold hold = new ZeroOrderHold(ctsub, "Hold");
AddSubtract add1 = new AddSubtract(ctsub, "Add1");
Integrator intgl1 = new Integrator(ctsub, "Integrator1");
Integrator intgl2 = new Integrator(ctsub, "Integrator2");
Scale scale0 = new Scale(ctsub, "Scale0");
Scale scale1 = new Scale(ctsub, "Scale1");
Scale scale2 = new Scale(ctsub, "Scale2");
Scale scale3 = new Scale(ctsub, "Scale3");
Scale scale4 = new Scale(ctsub, "Scale4");
scale4.factor.setExpression("feedbackGain");
TimedPlotter ctPlot = new TimedPlotter(ctsub, "CTPlot");
ctPlot.plot = new Plot();
ctPlot.plot.setGrid(true);
ctPlot.plot.setXRange(0.0, stopT);
ctPlot.plot.setYRange(-1.0, 1.0);
ctPlot.plot.setSize(500, 180);
ctPlot.plot.addLegend(0, "Position");
ctPlot.plot.addLegend(1, "Input");
ctPlot.plot.addLegend(2, "Control");
CTPeriodicSampler ctSampler = new CTPeriodicSampler(ctsub,
"PeriodicSampler");
ctSampler.samplePeriod.setExpression("samplePeriod");
// CT Connections
ctsub.connect(time.output, scale3.input);
ctsub.connect(scale3.output, trigFunction.input);
Relation cr0 = ctsub.connect(trigFunction.output, scale0.input, "CR0");
ctsub.connect(scale0.output, add1.plus, "CR1");
ctsub.connect(add1.output, intgl1.input, "CR2");
Relation cr3 = ctsub.connect(intgl1.output, intgl2.input, "CR3");
Relation cr4 = ctsub.connect(intgl2.output, ctPlot.input, "CR4");
scale1.input.link(cr3);
scale2.input.link(cr4);
ctSampler.input.link(cr4);
TypedIORelation cr5 = new TypedIORelation(ctsub, "CR5");
ctSampler.output.link(cr5);
subout.link(cr5);
ctsub.connect(scale1.output, add1.plus, "CR6");
ctsub.connect(scale2.output, add1.plus, "CR7");
ctsub.connect(scale4.output, add1.plus, "CR8");
TypedIORelation cr9 = new TypedIORelation(ctsub, "CR9");
hold.input.link(cr9);
subin.link(cr9);
Relation cr10 = ctsub.connect(hold.output, scale4.input, "CR10");
ctPlot.input.link(cr0);
ctPlot.input.link(cr10);
// DE System
ptolemy.domains.de.lib.TimedDelay delay = new ptolemy.domains.de.lib.TimedDelay(
this, "delay");
delay.delay.setToken(new DoubleToken(0.02));
FIR fir = new FIR(this, "fir");
fir.taps.setExpression("{0.7, 0.3}");
Quantizer quan = new Quantizer(this, "Quantizer");
Average accumulator = new Average(this, "accumulator");
Sampler sampler = new Sampler(this, "sampler");
Clock clk = new Clock(this, "ADClock");
clk.offsets.setExpression("{0.0}");
clk.period.setToken(new DoubleToken(1.0));
clk.values.setExpression("{true}");
TimedPlotter dePlot = new TimedPlotter(this, "DEPlot");
Plot newPlot = new Plot();
dePlot.plot = newPlot;
newPlot.setGrid(true);
newPlot.setXRange(0.0, stopT);
newPlot.setYRange(-1.0, 1.0);
newPlot.setSize(500, 180);
newPlot.setConnected(false);
newPlot.setImpulses(true);
newPlot.setMarksStyle("dots");
newPlot.addLegend(0, "Accum");
newPlot.addLegend(1, "Quantize");
FIR mav = new FIR(this, "MAV");
mav.taps.setExpression("{0.1, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05, 0.05, "
+ "0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05}");
// DE connections.
connect(subout, delay.input);
connect(delay.output, fir.input);
connect(fir.output, quan.input);
Relation dr3 = connect(quan.output, subin);
mav.input.link(dr3);
connect(mav.output, accumulator.input);
Relation dr4 = connect(clk.output, sampler.trigger);
accumulator.reset.link(dr4);
connect(accumulator.output, sampler.input);
connect(sampler.output, dePlot.input);
dePlot.input.link(dr3);
// CT Director parameters
ctdir.initStepSize.setToken(new DoubleToken(0.0001));
ctdir.minStepSize.setToken(new DoubleToken(1e-6));
//StringToken token1 = new StringToken(
// "ptolemy.domains.ct.kernel.solver.BackwardEulerSolver");
//ctdir.BreakpointODESolver.setToken(token1);
StringToken token2 = new StringToken(
"ptolemy.domains.ct.kernel.solver.ExplicitRK23Solver");
ctdir.ODESolver.setToken(token2);
// CT Actor Parameters
scale0.factor.setToken(new DoubleToken(50.0));
scale1.factor.setToken(new DoubleToken(-2.50));
scale2.factor.setToken(new DoubleToken(-250.0));
scale3.factor.setToken(new DoubleToken(0.5));
}
///////////////////////////////////////////////////////////////////
//// parameters ////
/** Sampling rate.
*/
Parameter samplePeriod;
/** Feedback gain.
*/
Parameter feedbackGain;
}