从1开始的Matlab(快速入门)

MATLAB软件版本:MATLAB R2016b

本文是博主从零开始学Matlab的记录,适合第一次接触Matlab的同学阅读。

一、基础介绍

1.1界面认识

1.2变量命名

注:Matlab中的注释

%% 独占一行的注释(有上下横线分割)

% 普通注释

1)清空环境变量及命令

clear all 清除Workspace中的所有变量(右侧工作区)

clc 清除Command Window中的所有命令(命令行窗口)

2)变量命名规则

①变量名区分大小写

②变量名长度不超过63位

③变量名以字母开头,可以由字母、数字和下划线组成,但不能使用标点

1.3数据类型

1)数字

2 + 4

10 - 7

3 * 5

8 / 2

2)字符与字符串

s = 'a' (单引号表示字符串)

==abs(s)==ASCII码

char(97) 输出 a (ASCII码转字符串)

num2str(65) 输出数字65

str='I love MATLAB & Machine Learning'

length(str) 字符串长度

doc num2str

3)矩阵(Matlab最NB的东西)

A = [1 2 3; 4 5 2; 3 2 7]

B = A' 把A进行转置,行变列,列变行

C = A( 竖向拉长(按列输出矩阵

D = inv(A) 逆矩阵(必须时方阵才能求逆矩阵)

执行下面两条语句

D = inv(A) (求逆矩阵)

A * D (相当于A×A的逆)

E = zeros(10,5,3) 创建一个10行5列3维的全0矩阵

E(:,:,1) = rand(10,5)

rand生成均匀分布的伪随机数。分布在(0~1)之间

主要语法:rand(m,n)生成m行n列的均匀分布的伪随机数

rand(m,n,'double')生成指定精度的均匀分布的伪随机数,参数还可以是'single'

rand(RandStream,m,n)利用指定的RandStream(随机种子)生成伪随机数

E(:,:,2) = randi(5,10,5)

randi生成均匀分布的伪随机数

主要语法:randi(iMax)在开区间(0,iMax)生成均匀分布的伪随机数

randi(iMax,m,n)在开区间(0,iMax)生成mXn型随机矩阵

r = randi([iMin,iMax],m,n)在开区间(iMin,iMax)生成mXn型随机矩阵

E(:,:,3) = randn(10,5)

randn生成标准正态分布的伪随机数(均值为0,方差为1)

**主要语法:**和上面一样

4)元胞数组和结构体

在MATLAB中,元胞数组和结构体是两种不同的数据类型,可以用来存储和组织不同类型的数据。

元胞数组(cell array)是一种特殊的数组,可以存储不同类型的数据。元胞数组的每个元素可以是任何类型的数据,包括数字、字符串、矩阵、函数句柄等。元胞数组使用大括号{}来索引和操作元素。

例如,创建一个包含不同类型数据的元胞数组:

Matlab 复制代码
cellArray = {1, 'hello', [1 2 3], @sin};
Matlab 复制代码
%元胞数组
A = cell(1,6)
A{2} = eye(3) %2021版本前的matlab下标从1开始
A{5} = magic(5)
B = A{5}

注:magic:字面意思是魔方,魔术的意思。在MATLAB中用来生成n阶幻方。比如三阶幻方就是1-9九个数字,组成一个3*3的矩阵,使得该矩阵无论横、竖还是斜三个方向上的三个数的和总是相同的。幻方是一个很古老的问题,试一下就知道了!

结构体(structure)是一种可以存储不同类型数据的数据结构。结构体的每个成员可以有不同的名称,并且每个成员可以是任何类型的数据。结构体使用点操作符.来访问和操作成员。

例如,创建一个包含不同类型数据的结构体:

Matlab 复制代码
structure.field1 = 1;
 structure.field2 = 'hello'; 
structure.field3 = [1 2 3]; 
structure.field4 = @sin;
Matlab 复制代码
%结构体
books = struct('name',{{'Machine Learning','Data Mining'}},'price',[30,40])
books.name %属性
books.name(1)
books.name{1}

元胞数组和结构体在某些情况下可以互相转换。使用函数cell2struct可以将元胞数组转换为结构体,使用函数struct2cell可以将结构体转换为元胞数组。

Matlab 复制代码
% 元胞数组转换为结构体 
cellArray = {1, 'hello', [1 2 3], @sin};
 structure = cell2struct(cellArray, {'field1', 'field2', 'field3', 'field4'});
 % 结构体转换为元胞数组 structure.field1 = 1;
 structure.field2 = 'hello'; 
structure.field3 = [1 2 3];
 structure.field4 = @sin;
 cellArray = struct2cell(structure);

1.4.内置常量

Matlab 复制代码
eps % 计算机的最小数

pi % 圆周率

i % 虚数单位,表示√(-1)

j % 虚数单位,表示√(-1)

1.5查看已有的变量信息

Matlab 复制代码
>> who

您的变量为:

ans  t    

>> whos
  Name      Size            Bytes  Class     Attributes

  ans       1x1                 8  double              
  t         1x3                24  double              

>> size(t) // 列出n,m

ans =

     1     3

>> length(t) // 列出max(n,m)

ans =

     3

二、矩阵操作

2.1矩阵的定义与构造

Matlab 复制代码
A = [1,2,3,4,5,6,5,4,6]
B = 1:2:9 %第二个参数为步长,不可缺省
B = 1:3:9
C = repmat(B,3,2) %重复执行3行2列
D = ones(2,4) %生成一个2行4列的全1矩阵

在MATLAB中,可以使用不同的方法构造矩阵。

  1. 使用方括号[]构造矩阵:

    A = [1,2,3,4,5,6,5,4,6];

  2. 使用冒号运算符构造向量:

    Matlab 复制代码
    B = 1:2:9; % 步长为2,生成1到9的向量 
    B = 1:3:9; % 步长为3,生成1到9的向量
  3. 使用repmat函数复制矩阵:

    Matlab 复制代码
    B = 1:3:9; % 步长为3,生成1到9的向量 
    C = repmat(B,3,2); % 重复执行3行2列,生成一个3行6列的矩阵
  4. 使用ones函数生成全1矩阵:

    D = ones(2,4); % 生成一个2行4列的全1矩阵

以上代码示例中,A是一个1行9列的矩阵,B是一个1行5列的向量,C是一个3行6列的矩阵,D是一个2行4列的全1矩阵。

补充行向量

在MATLAB中,可以使用 linspace(a, b, n) 函数来生成一个从 a 到 b 的等间距向量,其中 n 是向量的长度。下面是将这两个表达式转化为 MATLAB 代码的示例:

Matlab 复制代码
t1 = linspace(1, 2, 3); % 生成一个长度为 3 的向量 t1,元素在 1 和 2 之间等间距分布
t2 = linspace(1, 2, 3); % 生成一个长度为 3 的向量 t2,元素在 1 和 2 之间等间距分布

执行这些代码将会生成两个向量 t1 和 t2,它们的元素分别为 [1, 1.5, 2] 和 [1, 1.5, 2]。

在MATLAB中,可以使用 logspace(a, b, n) 函数来生成一个从 10^a 到 10^b 的对数间隔向量,其中 n 是向量的长度。下面是将这个表达式转化为 MATLAB 代码的示例:

Matlab 复制代码
t = logspace(1, 2, 2); % 生成一个长度为 2 的对数间隔向量 t,元素在 10^1 和 10^2 之间

执行这个代码将会生成一个向量 t,它的元素为 [10, 100]。这意味着 t 的第一个元素是 10,第二个元素是 100。

补充特殊矩阵

Matlab 复制代码
>> eye(3) // 单位矩阵

ans =

     1     0     0
     0     1     0
     0     0     1
     
>> eye(3,4)

ans =

     1     0     0     0
     0     1     0     0
     0     0     1     0
     
>> ones(2) // 全为1的矩阵

ans =

     1     1
     1     1
     
>> ones(2,3)

ans =

     1     1     1
     1     1     1
     
>> zeros(2) // 全为0的矩阵

ans =

     0     0
     0     0
     
>> zeros(2,3)

ans =

     0     0     0
     0     0     0

>> diag([1,2,3]) // 产生对角矩阵

ans =

     1     0     0
     0     2     0
     0     0     3

>> rand(2) // 创建随机矩阵,服从均匀分布

ans =

    0.2785    0.9575
    0.5469    0.9649

>> rand(2,1) 

ans =

    0.1576
    0.9706
    
>> randn(2) // 创建随机矩阵,服从正态分布

ans =

    0.5377   -2.2588
    1.8339    0.8622

>> randn(2,1)

ans =

    0.3188
   -1.3077

>> randperm(5) // 产生随机排列

ans =

     5     3     1     2     4

2.2矩阵的四则运算

Matlab 复制代码
A = [1 2 3 4; 5 6 7 8]
B = [1 1 2 2; 2 2 1 1]
C = A + B
D = A - B
E = A * B'
F = A .* B % .*表示对应项相乘
G = A / B %相当于A*B的逆 G*B = A  G*B*pinv(B) = A*pinv(B)  G = A*pinv(B),相当于A乘B
H = A ./ B % ./表示对应项相除

在MATLAB中,可以使用四则运算对矩阵进行操作。

给定两个矩阵A和B:

A = [1 2 3 4; 5 6 7 8]; B = [1 1 2 2; 2 2 1 1];

可以进行以下运算:

  1. 矩阵加法:

    C = A + B;

    结果C为两个矩阵对应元素相加得到的矩阵:

    C = [2 3 5 6; 7 8 8 9];

  2. 矩阵减法:

    D = A - B;

    结果D为两个矩阵对应元素相减得到的矩阵:

    D = [0 1 1 2; 3 4 6 7];

  3. 矩阵乘法:

    E = A * B';

    结果E为矩阵A乘以矩阵B的转置得到的矩阵:

    E = [13 9; 29 21];

  4. 对应项相乘:

    F = A .* B;

    结果F为两个矩阵对应元素相乘得到的矩阵:

    F = [1 2 6 8; 10 12 7 8];

  5. 对应项相除:

    H = A ./ B;

    结果H为两个矩阵对应元素相除得到的矩阵:

    H = [1 2 1.5 2; 2.5 3 7 8];

  6. 矩阵除法(相当于乘以逆矩阵):

    G = A / B;

    结果G为矩阵A乘以矩阵B的逆矩阵:

    G = [0.5 0.5; 1.5 1.5];

以上是常见的矩阵四则运算操作。请注意,矩阵乘法和矩阵除法的定义与数学中的矩阵乘法和矩阵除法略有不同,需要根据具体的应用场景进行理解和使用。

2.3矩阵的下标

Matlab 复制代码
A = magic(5)
B = A(2,3)
C = A(3,:) % :为取全部,那么这条语句表示取第三行
D = A(:,4) %取第四列
[m,n] = find(A > 20) %找到大于20的序号值/矩阵
%取的是索引值
E = A(2:3,1:2) // 取出第2行到第3行,第1列到第2列的所有元素

2.4 删除矩阵的整行或整列

Matlab 复制代码
A = [1, 2; 3, 4];

A

A(:, 1) = []; % 删去第一列,即把第一列变成空矩阵[]

B = [4, 5; 6, 7];

B

B(1, :) = []; % 删去第一行

B

在这段代码中,首先定义了矩阵A和B。然后,通过将A的第一列设置为空矩阵[]来删除了A的第一列。接着,通过将B的第一行设置为空矩阵[]来删除了B的第一行。

2.5合并矩阵

Matlab 复制代码
A = [1, 2, 3];

B = [4, 5, 6];

C = [A, B]; % 按行合并矩阵

C = [A; B]; % 按列合并矩阵

执行这些代码将会生成矩阵C,它分别按行和按列合并了矩阵A和B的元素

2.6矩阵的重塑、旋转

重塑

Matlab 复制代码
>> A=[1,2,3;4,5,6]

A =

     1     2     3
     4     5     6

>> reshape(A,3,2) // 按列顺序重塑矩阵A为3*2

ans =

     1     5
     4     3
     2     6

旋转

Matlab 复制代码
>> A

A =

     1     2     3
     4     5     6

>> rot90(A)

ans =

     3     6
     2     5
     1     4

三、程序结构

3.1顺序结构

在MATLAB中,顺序结构是指程序按照代码的顺序依次执行。简单来说,就是从上到下依次执行每一行代码。

例如,下面是一个简单的MATLAB程序,展示了顺序结构的应用:

Matlab 复制代码
a = 5;
b = 10;

c = a + b;
d = a - b;

disp(c);
disp(d);

在这个程序中,首先定义了变量a和b,并分别赋值为5和10。然后,通过a + b计算出变量c的值,通过a - b计算出变量d的值。最后,使用disp函数将c和d的值打印出来。

按照顺序结构的原则,程序将依次执行每一行代码,输出结果为:

Matlab 复制代码
15
-5

3.2循环结构

在MATLAB中,循环结构是用来重复执行一段代码的结构。MATLAB提供了两种常用的循环结构:for循环和while循环。

  1. for循环:for循环用于指定一个变量的起始值、终止值和步长,并在每次循环中递增或递减这个变量的值。for循环的语法如下:
Matlab 复制代码
for 变量 = 起始值:步长:终止值
    循环体代码
end

例如,下面的代码展示了使用for循环计算1到10的累加和:

Matlab 复制代码
sum = 0;
for i = 1:10
    sum = sum + i;
end

disp(sum);

在这个例子中,for循环从1到10依次取值给变量i,每次循环将i加到sum上。最后,使用disp函数将sum的值打印出来。

  1. while循环:while循环用于在满足某个条件的情况下重复执行一段代码,直到条件不满足为止。while循环的语法如下:
Matlab 复制代码
while 条件
    循环体代码
end

例如,下面的代码展示了使用while循环计算1到10的累加和:

Matlab 复制代码
sum = 0;
i = 1;
while i <= 10
    sum = sum + i;
    i = i + 1;
end

disp(sum);

在这个例子中,while循环在i小于等于10的条件下执行循环体代码,每次循环将i加到sum上,并将i递增1。当i大于10时,条件不再满足,循环结束。最后,使用disp函数将sum的值打印出来。

3.3分支结构

在MATLAB中,分支结构用于根据条件的真假执行不同的代码块。MATLAB提供了if语句和switch语句两种常用的分支结构。

  1. if语句:if语句根据条件的真假执行不同的代码块。if语句的语法如下:
Matlab 复制代码
if 条件
    代码块1
elseif 条件
    代码块2
else
    代码块3
end

其中,条件可以是一个表达式,如果条件为真,则执行代码块1;如果条件为假,但满足第二个条件,则执行代码块2;如果条件都不满足,则执行代码块3。

例如,下面的代码展示了使用if语句判断一个数的正负性:

Matlab 复制代码
num = -5;

if num > 0
    disp('正数');
elseif num < 0
    disp('负数');
else
    disp('零');
end

在这个例子中,根据num的值,if语句会判断num的正负性,并输出相应的结果。

  1. switch语句:switch语句根据表达式的值执行不同的代码块。switch语句的语法如下:
Matlab 复制代码
switch 表达式
    case 值1
        代码块1
    case 值2
        代码块2
    otherwise
        代码块3
end

其中,表达式的值会逐个与每个case后面的值进行比较,如果匹配成功,则执行相应的代码块。如果没有匹配成功的case,则执行otherwise后面的代码块。

例如,下面的代码展示了使用switch语句根据星期几输出相应的信息:

Matlab 复制代码
day = 3;

switch day
    case 1
        disp('星期一');
    case 2
        disp('星期二');
    case 3
        disp('星期三');
    case 4
        disp('星期四');
    case 5
        disp('星期五');
    otherwise
        disp('周末');
end

在这个例子中,根据day的值,switch语句会匹配相应的case,并输出相应的信息。

3.4分号

在MATLAB中,分号(;)的主要含义是用于分隔语句或抑制输出。

  1. 分隔语句:分号用于分隔多个语句。当你在一行中写多个语句时,可以使用分号将它们分隔开。这样可以使代码更简洁,易于阅读。

例如,下面的代码将两个语句放在一行中,并使用分号分隔它们:

Matlab 复制代码
a = 2; b = 3;
  1. 抑制输出:在MATLAB中,每当执行一个语句时,结果会自动显示在命令窗口中。但是,如果在语句的末尾加上分号,就可以抑制输出。这在执行大量计算或不需要显示结果的情况下很有用。

例如,下面的代码计算两个数的和,但是只将结果存储在变量中,而不在命令窗口中显示:

Matlab 复制代码
a = 2;
b = 3;
c = a + b;

在这个例子中,c的值是5,但是由于语句末尾加上了分号,所以不会在命令窗口中显示出来。

需要注意的是,分号只能用于抑制当前语句的输出,对于其他语句的输出没有影响。如果你希望在代码中的多个位置都抑制输出,需要在每个语句的末尾都加上分号。

3.5输入输出

输入

Matlab 复制代码
s=input('please input a string: ','s');

输出

Matlab 复制代码
x = rand(1, 3);

fprintf("x=%.3f\n", x); % 输出x的所有元素,保留3位小数

fprintf("x=%.3f\n", x(2)); % 输出x[2](可省略第1行的行下标)

fprintf("x=%.3f\n", x(1, 2)); % 输出x[1][2]

y = [1, 2; 3, 4];

fprintf("y=%.3f\n", y(:)); % 按列输出y的所有元素

fprintf("y=%.3f\n", y(2, 1)); % 输出y[2][1]

fprintf("y=%.3f\n", y(1)); % 输出y[1][1](可省略第1列的列下标)

fprintf("y=%.3f\n", y(2)); % 输出y[2][1](可省略第1列的列下标)

3.6函数

编写函数,存于文件ave.m中,代码如下:

Matlab 复制代码
% You can get the average of a vector.
% Just input "ave;" to run this function.
function y = ave(x)
x = input('input a vector x=');
[m,n] = size(x);
if ~(m==1|n==1)
	error('please input a vector which is m=1 or n=1')
end
y = sum(x)/length(x);
fprintf("y=%.2f\n",y);

四、基本绘图操作

4.1二维平面绘图

Matlab 复制代码
% 初始化
clear;
clc;

% 将图片的字体等格式设置成latex样式,方便输入公式
set(0,'defaulttextinterpreter','latex');
set(0,'defaultAxesTickLabelInterpreter','latex');
set(0,'defaultLegendInterpreter','latex');

set(groot,'defaultLineLineWidth',2); % 更改默认线宽

%% 产生x,y数据
x=linspace(0,2*pi,20);
y{1}=sin(x);
y{2}=cos(x);
y{3}=x;
y{4}=exp(sin(x));

%% 绘制图1
figure(1);
plot(x,y{1},'--ro',... % --虚线 r红色 o圆圈标记
	x,y{2},':k^',... % :点组成的线 k黑色 ^三角形标记
	x,y{3},'-.',... % -.线如-.
	x,y{4});
xlabel('x轴');
ylabel('y轴');
title('例图');
% legend显示图中曲线对应的公式(在坐标区上添加图例)
legend('$y=sin(x)$','$y=cos(x)$','$y=x$','$y=e^{sin(x)}$','Location','best');
xlim([0,2*pi]); % 设置x轴范围
print('C:\Users\LJW\Desktop\example1','-dpng'); % 保存为png格式图片到桌面路径 

%% 绘制图2
figure(2);

subplot(2,2,1); % 分成2*2四个子图,开始画第一个子图
plot(x,y{1},'--');
title('$y=sin(x)$');

subplot(2,2,2); % 分成2*2四个子图,开始画第二个子图
plot(x,y{2},':');
title('$y=cos(x)$');

subplot(2,2,[3,4]); % 第3,4个子图合并,写成[3,4]
plot(x,y{3},':',x,y{4}); % 2个子图合并
legend('$y=x$','$y=e^{sin(x)}$','Location','best');
xlim([0,2*pi]); % 设置x轴范围

print('C:\Users\LJW\Desktop\example2','-dpng'); % 保存为png格式图片到桌面路径 

Matlab 复制代码
x = 0:0.01:20;
y1 = 200*exp(-0.05*x).*sin(x);
y2 = 0.8*exp(-0.5*x).*sin(10*x);
figure
[AX,H1,H2] = plotyy(x,y1,x,y2,'plot'); %共用一个x的坐标系,在y上有不同的取值
%设置相应的标签
set(get(AX(1),'Ylabel'),'String','Slow Decay')
set(get(AX(2),'Ylabel'),'String','Fast Decay')
xlabel('Time(\musec)')
title('Multiple Decay Rates')
set(H1,'LineStyle','--')
set(H2,'LineStyle',':')

4.2三维立体绘图

Matlab 复制代码
%2.三维立体绘图
t = 0: pi/50: 10*pi;
plot3(sin(t),cos(t),t)
xlabel('sin(t)')
ylabel('cos(t)')
zlabel('t')
%hold on
%hold off %不保留当前操作
grid on %把图片绘制出来,在图片中加一些网格线
axis square %使整个图(连同坐标系)呈方体

4.3图形的保存与导出

如果直接用截图的方式截取matlab生成的图像,会影响图像的清晰度。因此我们建议:可以用如下方法保存与导出图形。

1)如图

2)编辑→复制选项

可调节相应元素

3)编辑→图窗属性

4)文件→导出设置

通过调节宽度、高度等像素值属性,可以让图片即使很小,文字依然清晰。

五、读取文件

5.1Excel文件

使用 xlsread 函数来读取Excel文件中的数据。这个函数可以接受文件名、工作表名和单元格范围作为输入参数,并返回数值数据、文本数据和原始数据作为输出参数。例如,读取文件 myExample.xlsx 中的第一个工作表的 A1:C3 范围内的数据

Matlab 复制代码
[num,txt,raw] = xlsread('myExample.xlsx','Sheet1','A1:C3');

使用 readtable 函数来读取Excel文件中的表格数据。这个函数可以将Excel文件中的一个或多个工作表导入为一个或多个表格变量。例如,读取文件 myExample.xlsx 中的第二个工作表的所有数据

Matlab 复制代码
T = readtable('myExample.xlsx','Sheet',2);

将Matlab中的数据写入Excel文件中,可以使用 xlswrite 函数或 writetable 函数。这些函数可以将矩阵、元胞数组或表格变量写入Excel文件中的指定工作表和单元格范围。例如,如果您想将矩阵 A 写入文件 myExample.xlsx 中的第三个工作表的 B2:D6 范围内,可以使用以下代码:

Matlab 复制代码
A = rand(5,3); % 创建一个5行3列的随机矩阵
xlswrite('myExample.xlsx',A,'Sheet3','B2:D6');

5.2csv文件

使用 csvread 函数来读取只包含数值的CSV文件。这个函数可以接受文件名、起始行列和读取范围作为输入参数,并返回一个矩阵作为输出参数。例如,读取文件 myData.csv 中的第一行第二列开始的所有数据

Matlab 复制代码
M = csvread('myData.csv',0,1);

使用 textscan 函数来读取包含文本和数值的CSV文件。这个函数可以接受一个已打开的文件标识符、一个格式说明符和其他可选参数,并返回一个元胞数组作为输出参数。例如,读取文件 myInfo.csv 中的第一列是字符串,第二列是整数,第三列是浮点数的数据

Matlab 复制代码
fid = fopen('myInfo.csv');
C = textscan(fid,'%s%d%f','Delimiter',',','HeaderLines',1);
fclose(fid);

使用 readmatrix 函数来读取包含表格数据的CSV文件。这个函数可以根据文件的扩展名自动判断文件格式,并返回一个矩阵或一个表作为输出参数。可以指定输出类型和其他可选参数来控制导入过程。例如,想读取文件 myTable.csv 中的所有数据,并将字符串类型的数据转换为缺失值

Matlab 复制代码
A = readmatrix('myTable.csv','OutputType','double','TreatAsMissing','NA');
相关推荐
Ajiang28247353042 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空2 小时前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10225 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
----云烟----7 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024067 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic7 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it7 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康7 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神8 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
宅小海8 小时前
scala String
大数据·开发语言·scala