block RealFFT "Sampling and FFT of input u"
extends Modelica.Blocks.Interfaces.DiscreteBlock(final samplePeriod = (2 * f_res * div(ns, 2)) ^ (-1));
parameter Modelica.SIunits.Frequency f_max "Maximum frequency of interest";
parameter Modelica.SIunits.Frequency f_res "Frequency resolution";
final parameter Integer ns = Modelica.Math.FastFourierTransform.realFFTsamplePoints(f_max, f_res, f_max_factor = 5) "Number of samples";
final parameter Integer nf = max(1, min(integer(ceil(f_max / f_res)) + 1, div(ns, 2))) "Number of frequency points";
parameter String resultFileName = "realFFT.mat" "Result file: f, abs, arg";
output Integer info(start = 0, fixed = true) "Information flag from FFT computation";
Modelica.Blocks.Interfaces.RealInput u annotation (Placement(
transformation(extent = {
{-140, -20},
{-100, 20}}),
iconTransformation(extent = {
{-140, -20},
{-100, 20}})));
protected
Real buf[ns](start = zeros(ns), each fixed = true) "Input buffer";
Real abs[nf](start = zeros(nf), each fixed = true) "FFT amplitudes";
Real arg[nf](start = zeros(nf), each fixed = true) "FFT phases";
Integer iTick(start = 0, fixed = true) "Sample ticks";
algorithm
when {sampleTrigger} then
iTick := pre(iTick) + 1;
if iTick <= ns then
buf[iTick] := u;
end if;
end when;
when terminal() then
if iTick < ns then
assert(false, "Sampling time not sufficient! stopTime>= " + String(startTime + (ns - 1) * samplePeriod));
else
(info,abs,arg) := Modelica.Math.FastFourierTransform.realFFT(buf, nf);
assert(info == 0, "Error in FFT");
Modelica.Math.FastFourierTransform.realFFTwriteToFile(startTime + (ns - 1) * samplePeriod, resultFileName, f_max, abs, arg);
end if;
end when;
annotation (
Documentation(info = "<html>\n<p>\nThis block samples the input signal, calculates the Fast Fourier Transform by function <a href=\"modelica://Modelica.Math.FastFourierTransform.realFFT\">Math.realFFT</a>,\nand (when simulation terminates) writes the output to result file resultFileName by function <a href=\"modelica://Modelica.Math.FastFourierTransform.realFFTwriteToFile\">Math.realFFTwriteToFile</a>.\n</p>\n<p>\nThe number of sampling points as well as the samplePeriod is calculated from desired maximum frequency f_max and frequency resolution f_res.\n</p>\n<h4>Note</h4>\n<p>\nThe user has to take care that enough points can be sampled before the simulation ends: startTime + (ns - 1)*samplePeriod <= stopTime.\n</p>\n<p>\nThe result file is written as mat, first column = frequency, second column = amplitudes, third column = phases. The frequency points are separated by rows with amplitude and phase = 0,\nso one can plot the result directly as frequency lines.\n</p>\n</html>"),
Icon(graphics = {
Polygon(
points = {
{-80, 96},
{-86, 80},
{-74, 80},
{-80, 96}},
lineColor = {135, 135, 135},
fillColor = {192, 192, 192},
fillPattern = FillPattern.Solid),
Line(
points = {
{-80, -92},
{-80, 80}},
color = {135, 135, 135}),
Line(
points = {
{-92, -80},
{80, -80.3976}},
color = {135, 135, 135}),
Polygon(
points = {
{96, -80.3976},
{80, -74.3976},
{80, -86.3976},
{96, -80.3976}},
lineColor = {135, 135, 135},
fillColor = {192, 192, 192},
fillPattern = FillPattern.Solid),
Line(
points = {
{-70, 60},
{-70, -80}},
thickness = 0.5),
Line(
points = {
{-30, -52},
{-30, -80}},
thickness = 0.5),
Line(
points = {
{-10, -60},
{-10, -80}},
thickness = 0.5),
Line(
points = {
{30, -68},
{30, -80}},
thickness = 0.5),
Line(
points = {
{50, -70},
{50, -80}},
thickness = 0.5)}));
end RealFFT;